Automatic file descriptor terminator

x::fdtimeout also implements the concept of a file descriptor terminator. A file descriptor terminator is a separate file descriptor object that's attached to the primary file descriptor. When the terminator file descriptor becomes readable, calls to primary descriptor's pubread(), pubwrite(), pubaccept(), and pubconnect() methods throw an exception:

x::fd socket, terminatefd;

// ...
socket->nonblock(true);

x::fdtimeout socket_with_timeout(x::fdtimeout::create(socket));

socket_with_timeout->set_terminate_fd(terminatefd);

In this example, when terminatefd becomes readable, all subsequent attempts to read or write from socket_with_timeout throw an exception. The same terminator file descriptor may be attached, using set_terminate_fd() to multiple file descriptors.

Note

The primary file descriptor must be placed in non-blocking mode for this to work, however its pubread() and write() will block until either the primary file is readable or writable, or until the terminator file descriptor becomes readable.

Use cancel_terminate_fd() to remove a terminator file descriptor.

Note

Only the behavior of pubread(), pubwrite(), pubaccept() and pubconnect is affected by attaching a terminator file descriptor. Other methods are not affected (except indirectly, as the result of the file descriptor set to the non-blocking mode).

This is a convenient mechanism to shut down a multithreaded server. Each client socket connection is serviced by a separate thread, and a terminator file descriptor gets attached to each socket file descriptor. The terminator file descriptor is the read end of a pipe, or an event file descriptor. Closing a pipe, or posting an event, stops reading and writing to all active sockets, which presumably results in automatic termination of all threads.