]> git.tuebingen.mpg.de Git - paraslash.git/commitdiff
fd.c: Prefer poll(2) over select(2) for write_ok().
authorAndre Noll <maan@tuebingen.mpg.de>
Wed, 29 Sep 2021 20:07:13 +0000 (22:07 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Thu, 25 Aug 2022 13:37:26 +0000 (15:37 +0200)
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

diff --git a/fd.c b/fd.c
index d72096e1e9674fb0d5307dc4005f8a3d3aa7e6dc..2f3ec997c11e796fc5ff8ada46c40a662e0aef13 100644 (file)
--- a/fd.c
+++ b/fd.c
@@ -6,6 +6,7 @@
 #include <sys/types.h>
 #include <dirent.h>
 #include <sys/mman.h>
+#include <poll.h>
 
 #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;
 }
 
 /**