Reputation: 16743
man 2 select
states the following under BUGS:
Under Linux, select() may report a socket file descriptor as "ready for reading", while nevertheless a subsequent read blocks. This could for example happen when data has arrived but upon examination has wrong checksum and is discarded. There may be other circumstances in which a file descriptor is spuriously reported as ready. Thus it may be safer to use O_NONBLOCK on sockets that should not block.
Thus, my read
calls need to not block and therefore I have marked my pipe file descriptors O_NONBLOCK
. However, I want write
calls to block until data is written to the pipe.
Is it possible to have write
block when writing data to the pipe, but have read
not block the reading end? Is it legal for instance to call fcntl
on one end only after the pipe has been created, since read and write ends have separate file descriptors?
Upvotes: 5
Views: 1230
Reputation: 7482
You surely can remove O_NONBLOCK flag before each write
with fcntl
and put it back after write
completes. However, it seems better to keep the socket non-blocking all the time and to put write
into a loop until it finishes. In order not to overload the CPU, put a select which will block the process until the socket is ready for write.
So, the writing code will look like:
int blockingWriteOnNonBlockingFd(int fd, char *buf, int size) {
fd_set wset, w;
int n, r;
FD_ZERO(&wset);
FD_SET(fd, &wset);
n = 0;
while (n < size) {
w = wset;
select(fd+1, NULL, &w, NULL, NULL);
r = write(fd, buf+n, size-n);
if (r <= 0) {
if (r<0 && (errno == EWOULDBLOCK || errno == EAGAIN)) r = 0;
else { /* broken connection */ break; }
}
n += r;
}
return(n);
}
Upvotes: 3