From f23a3bd46a21cae3749ff6c3d6459e119d4cee89 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Wed, 29 Sep 2021 22:07:13 +0200 Subject: [PATCH] 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. --- fd.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) 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; } /** -- 2.39.2