According to its man page, the select() system call offers monitoring of three different aspects of one or more file descriptors: whether they are ready to read from, ready to write to, or whether an "error" or "exceptional condition" (language varies) has occurred. Which of these shall be monitored, is specified via three fd_set
arguments referred to as readfds
, writefds
, and errorfds
. While there is plenty of good documentation and examples about the proper use of readfds
and writefds
, I could hardly find anything useful on errorfds
.
Anyhow, for reasons discussed below, I gave the use of errorfds
a try, and did indeed find a few circumstances, in which the select()
call in my runloop responded to an "exceptional condition" on one of its file descriptors. For example, a TTY connected to a PTY, while the latter is being closed from its master side, raises such a condition.
But now what? I know that some "exceptional condition" occurred on a file descriptor, but how, in general, can I find out what exactly caused it? Just looking at errno
certainly does not give the answer (at that point it is always 0). Is there perhaps some "magical" ioctl
that I should be aware of?
Some further background: A number of my programs (mostly written in C) communicate with external hardware via serial ports. For testing, I also wrote a simple server that creates a PTY to which's corresponding TTY my other programs can connect to as if it was a serial port. While at a basic level all of this is working pretty well, handling of errors or other exceptional conditions is currently not really implemented at all, which occasionally leads to pretty nasty behavior. This needs to change!
One exceptional condition, that I am particularly interested in detecting, is whether a connection has been broken. For example, it would be nice to notice when a port goes away, say, because the user pulled a USB-to-serial adapter. Properly handling read and write errors seems to avoid the nastiest of unintended side effects, but I was wondering if there was more (watching errorfds
, or perhaps some other signals) that I should be doing. Unfortunately, UNIX signal handling is something I am not at all familiar with.
You should try reading 0 bytes. In linux, at least,
man 2 read
states:So, after
read(fd, NULL,0)
you should have anerrno
that tells you something more, without having to actually read anything. The weasel word may in the manpage means that this is probably not very portable, though (cf read(fd, NULL, 0); what does it do? is it well-defined?)