0

On page 34 of the book "Linux System Programming" the following example of correctly handling partial reads with a while loop for blocking reads is given

ssize_t ret;

while (len != 0 && (ret = read(fd, buf, len)) != 0) {
    if (ret == -1) {
        if (errno == EINTR) 
            continue;
        perror("read");
        break;
    }

    len -= ret;
    buf += ret;
}

On the next page it gives the following example for nonblocking reads. Does this example need to be wrapped in a while loop to handle the possibility of partial reads?

char buf[BUFSIZ];
ssize_t nr;

start:
nr = read(fd, buf, BUFSIZ);
if (nr == -1) {
    if (errno == EINTR)
        goto start; /* oh shush */
    if (erron == EAGAIN)
        /* resubmit later */
    else
        /* error */
}
JIghtuse
  • 866
  • 5
  • 11
user782220
  • 10,677
  • 21
  • 72
  • 135

2 Answers2

0

No, this example don't need to be wrapped in loop. It uses goto statement (see this answer for good examples of its using).

This example shows nonblocking read, that's why this code differs from the first one. See note after second code block:

Handling the EAGAIN case like we did the EINTR case (with a goto start) would make little sense. We might as well not have used non‐ blocking I/O. The point of nonblocking I/O is to catch the EAGAIN and do other, useful work.

Community
  • 1
  • 1
JIghtuse
  • 866
  • 5
  • 11
  • But why isn't it possible for the nonblocking read to return something less than BUFSIZ indicating that only partial read occurred. In such a case `nr` would not be `-1` so that the error handling code is not relevant. – user782220 Nov 20 '13 at 08:45
0

Typically, a non-blocking IO is used when the code can (or intends to) do something else in parallel instead of waiting on input (e.g. check on another file or socket). Otherwise, a simple blocking IO will do the same trick as polling on the file for reads, as Jlghtuse mentioned. However, I am not sure if a non-blocking IO is guaranteed to return exact number of bytes requested. As a safe bet, it probably could use a while loop anyways. I think one usable code chunk might look like:

char buf[BUFSIZ];
ssize_t nr;
char *bufp = buf;
ssize_t rdbyts = 0;

while(rdbyts < BUFSIZ) {
    nr = read(fd, bufp, (BUFSIZ - rdbyts));
    if (nr == -1) {
        if (errno == EINTR)
            continue; /* oh shush */
        else if (errno == EAGAIN)
            /* resubmit later - might be do
             * something else and come back
             * or just sleep. */
            do_some_work_or_sleep();
            continue;
        else
            /* error */
            break;
    } else if (nr < (BUFSIZ - rdbytes)) {
        bufp += nr;
        rdbyts += nr;
    }
}
Vasu
  • 62
  • 1
  • 7