So one common programming idiom you’ll find a lot if you sniff around code in random projects is a helper function that reads or writes in a loop. Something almost, but not completely unlike…


bool write_it_harder (int fd, void *buf, size_t size_of_buf)
{
while (there are still bytes to write) {
the_number_of_bytes_written = write (fd, buf, the_number_of_bytes_left_to_write);
/* check for errors then figure out the_number_of_bytes_left_to_write */
}
return true;
}

THIS IS WRONG. It’s not a good idea to do in a gui program. It means that your app will

1) block until all the bytes are written (which could be a while, if the thing getting written to is slow)
2) will completely fall over on some devices

It’s really better (although harder to code) to treat read()/write() as one-shot operations. You do them once, get a result, and then should go back to poll() and wait for it to report that the fd you are working with is readable or writable again.

Another common one is:


again:
bytes_read = read (fd, buf, sizeof (buf));

if (bytes_read < 0 && errno == EAGAIN)
goto again;

Again, THIS IS WRONG.

1) you may get into a situation where read() will return EAGAIN over and over again in a tight, battery killing, cpu heating loop
2) there is no guarantee that you’ll get EAGAIN on successive calls anyway. pseudo-terminals for instance, will give you EAGAIN once, and then EIO for successive calls.

So, only every call read() or write() when poll() says its okay to call them, and realize that if poll() says its okay to call them, it’s only saying it’s okay to call them ONCE, and you need to ask poll() permission to call them again.

update
I’ve put a sample program up here to show what I mean.

Leave a Reply