Skip to content

File Descriptors Opened by Crystal at Initialization

Bruce Perens edited this page Jun 14, 2020 · 10 revisions

You may be concerned by the file descriptors your Crystal program has open. Your concern may be security, or you are checking for file descriptor leaks.

On Unix-like systems, at initialization, Crystal opens:

  • A copy of each of stdin, stdout, and stderr if these are terminal devices. These would appear as file descriptors 3, 4, and 5 if all of stdin, stdout, and stderr are connected to a terminal. These are separate opens. Crystal internally performs non-blocking I/O so that it can start a thread while another thread is waiting for file I/O. Due to the semantics of Unix file descriptors, we can't call O_NONBLOCK on a terminal device file descriptor that is shared with our parent and sibling processes. It breaks them. So we figure out what the terminal device is, and open it again.
  • Both ends of two pipes, for a total of 4 file descriptors. These are a kludge for signal handling. Since few libc functions are safe to call in a signal handler, Crystal catches signals, and writes to a pipe an indication that the signal was caught. Crystal's main select() or poll() loop will wake up on the pipe and receive that notification, and activate the user's signal handler.
  • One file descriptor used by eventpoll.

Most Unix-like systems have file descriptors 0, 1, and 2 open for stdin, stdout, and stderr when they execute any program. So your Crystal program will have those file descriptors.

This makes a total of 11 file descriptors you should expect to see when a minimal Crystal program starts. Depending on your app, you can also expect to see one or more sockets open for your database connection, a socket for accepting web connections, and additional sockets for the existing connections.