From: Andre Noll Date: Wed, 29 Sep 2021 20:07:13 +0000 (+0200) Subject: fd.c: Prefer poll(2) over select(2) for write_ok(). X-Git-Tag: v0.7.1~6^2~12 X-Git-Url: http://git.tuebingen.mpg.de/?a=commitdiff_plain;h=f23a3bd46a21cae3749ff6c3d6459e119d4cee89;p=paraslash.git fd.c: Prefer poll(2) over select(2) for write_ok(). This is easy to do and avoids the old and well-known shortcomings of select(2). See http://0pointer.net/blog/file-descriptor-limits.html for a short discussion, or the references in the log message of commit e4a403876d2c of the man-pages repository. The linux poll manpage says: On some other UNIX systems, poll() can fail with the error EAGAIN if the system fails to allocate kernel-internal resources, rather than ENOMEM as Linux does. POSIX permits this behavior. Portable programs may wish to check for EAGAIN and loop, just as with EINTR. We do not follow this approach since failing the call in the out of memory case seems to be the right thing to do while busy looping without trying to free memory between the calls is not likely to help. Also, looping on EAGAIN would be inconsistent since in the OOM case the code would fail on Linux but loop on those other UNIX systems. To be consistent, one must check for both EAGAIN and ENOMEM. --- diff --git a/fd.c b/fd.c index d72096e1..2f3ec997 100644 --- a/fd.c +++ b/fd.c @@ -6,6 +6,7 @@ #include #include #include +#include #include "para.h" #include "error.h" @@ -651,14 +652,17 @@ int para_munmap(void *start, size_t length) * \return positive if fd is ready for writing, zero if it isn't, negative if * an error occurred. */ - int write_ok(int fd) { - fd_set wfds; + int ret; + struct pollfd pfd = {.fd = fd, .events = POLLOUT}; - FD_ZERO(&wfds); - FD_SET(fd, &wfds); - return para_select(fd + 1, NULL, &wfds, 0); + do + ret = poll(&pfd, 1, 0); + while (ret < 0 && errno == EINTR); + if (ret < 0) + return -ERRNO_TO_PARA_ERROR(errno); + return pfd.revents & POLLOUT; } /**