It is possible to set up a timeout mechanism for reading or writing
to a file descriptor object.
An x::fdtimeout
gets attached to a file descriptor transport, and in turn exports a
file descriptor transport with a timeout facade. Reading and writing
through the x::fdtimeout
object reads and
writes the attached file descriptor, with the timeout functionality,
when it's enabled.
A timeout for reading and a timeout for writing to a file descriptor are independent and separate from each time, but only one read timeout and one write timeout may be set up for an individual file descriptor. Setting up a read timeout cancels any previously set up read timeout. Setting up a write timeout cancels any previously set up write timeout.
Additionally, an x::fdtimeout
object may
not be attached to another x::fdtimeout
object (although multiple x::fdtimeout
objects may be attached to the same underlying
x::fd
and used separately from each other).
pubread
() and
pubwrite
()
methods of x::fdtimeout
observe the
corresponding timeouts, when enabled.
pubaccept
() observes the read timeout, if set.
pubconnect
() observes the write timeout, if set.
If the underlying pubread_pending
() returns
non-0, pubread
() invokes the underlying
pubread
() immediately.
The file descriptor must be nonblocking for read and write timeouts to work reliably. Invoke “nonblock(true)” before creating a read or a write timeout.
When the file descriptor is set to nonblocking mode,
pubread
() and
pubwrite
() still block. They block until
the underlying file descriptor is readable or writable, or until
the timeout expires.
A read or a write timeout results in a thrown
ETIMEDOUT
x::sysexception
.
Once a read or a write timeout occurs, additional attempts to read/write/connect a file descriptor fail immediately, until the timeout is reset.
#include <x::fdtimeout.H> x::fd fd; x::fdtimeout fd_with_timeout(x::fdtimeout::create(fd)); x::istream i(fd_with_timeout->getistream()); // ... fd_with_timeout->set_read_timeout(5); std::string line; std::getline(i, line); // ... try { fd_with_timeout->pubread(buffer, bufsize); } catch (const x::exception &e) { } fd->cancel_read_timeout();
set_read_timeout
() starts a timer. Its parameter
is actually a
x::timespec
.
Invoking pubread
() directly or indirectly
waits for either data to be
available, or for the timer to expire.
In this case, an input stream reads a line from the
file descriptor, invoking its pubread
() method.
If the timer expires before the file descriptor is readable,
pubread
() throws an exception. If the file
descriptor's pubread
() gets invoked directly, catch
this exception
to detect a timeout condition (as demonstrated in the given example).
Formatted input and output stream operators
catch all exceptions thrown by the underlying
streambuf
, and set the failed bit in the stream's
state (which may rethrow a std::exception
, if the
stream object is configured to do so), causing
std::getline
() to return.
cancel_read_timeout
() removes the read timeout from
the file descriptor.
set_write_timeout
() and
cancel_write_timeout
() implement an equivalent
timeout functionality for writing to the file descriptor.
Timeouts do not get cleared automatically, after a succesful read or a write. They are more like a deadline. After the timeout expires, all subsequent reads and writes fail. The timeouts should be explicitly cleared, if they get installed for the benefit of a single read or a write attempt.
It is possible to set up a periodic read or a write timeout by specifying a byte count in addition to the timeout:
fd_with_timeout->set_read_timeout(8192, 15);
This example sets a 15 second timeout. A timer gets started.
As soon as 8192 bytes are read, the timer gets restarted. The timer
will continue to get re-started, every 8192 bytes, until it's cancelled
by cancel_read_timeout
().
fd_with_timeout->set_write_timeout(8192, 15);
This example sets up a write timeout with equivalent semantics.
Only the behavior of pubread
() and
pubwrite
() is affected by setting a read or a write
timeout. Other methods are not affected (except indirectly,
as the result of the file descriptor set to the non-blocking
mode).