summaryrefslogtreecommitdiffstats
path: root/lib/pselect.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--lib/pselect.c110
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/pselect.c b/lib/pselect.c
new file mode 100644
index 0000000..a1eca0c
--- /dev/null
+++ b/lib/pselect.c
@@ -0,0 +1,110 @@
+/* pselect - synchronous I/O multiplexing
+
+ Copyright 2011-2022 Free Software Foundation, Inc.
+
+ This file is part of gnulib.
+
+ This file is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Lesser General Public License as
+ published by the Free Software Foundation; either version 2.1 of the
+ License, or (at your option) any later version.
+
+ This file is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with this program. If not, see <https://www.gnu.org/licenses/>. */
+
+/* written by Paul Eggert */
+
+#include <config.h>
+
+#include <sys/select.h>
+
+#include <errno.h>
+#include <signal.h>
+
+/* Examine the size-NFDS file descriptor sets in RFDS, WFDS, and XFDS
+ to see whether some of their descriptors are ready for reading,
+ ready for writing, or have exceptions pending. Wait for at most
+ TIMEOUT seconds, and use signal mask SIGMASK while waiting. A null
+ pointer parameter stands for no descriptors, an infinite timeout,
+ or an unaffected signal mask. */
+
+#if !HAVE_PSELECT
+
+int
+pselect (int nfds, fd_set *restrict rfds,
+ fd_set *restrict wfds, fd_set *restrict xfds,
+ struct timespec const *restrict timeout,
+ sigset_t const *restrict sigmask)
+{
+ int select_result;
+ sigset_t origmask;
+ struct timeval tv, *tvp;
+
+ if (timeout)
+ {
+ if (! (0 <= timeout->tv_nsec && timeout->tv_nsec < 1000000000))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ tv.tv_sec = timeout->tv_sec;
+ tv.tv_usec = (timeout->tv_nsec + 999) / 1000;
+ tvp = &tv;
+ }
+ else
+ tvp = NULL;
+
+ /* Signal mask munging should be atomic, but this is the best we can
+ do in this emulation. */
+ if (sigmask)
+ pthread_sigmask (SIG_SETMASK, sigmask, &origmask);
+
+ select_result = select (nfds, rfds, wfds, xfds, tvp);
+
+ if (sigmask)
+ {
+ int select_errno = errno;
+ pthread_sigmask (SIG_SETMASK, &origmask, NULL);
+ errno = select_errno;
+ }
+
+ return select_result;
+}
+
+#else /* HAVE_PSELECT */
+# include <unistd.h>
+# undef pselect
+
+int
+rpl_pselect (int nfds, fd_set *restrict rfds,
+ fd_set *restrict wfds, fd_set *restrict xfds,
+ struct timespec const *restrict timeout,
+ sigset_t const *restrict sigmask)
+{
+ int i;
+
+ /* FreeBSD 8.2 has a bug: it does not always detect invalid fds. */
+ if (nfds < 0 || nfds > FD_SETSIZE)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ for (i = 0; i < nfds; i++)
+ {
+ if (((rfds && FD_ISSET (i, rfds))
+ || (wfds && FD_ISSET (i, wfds))
+ || (xfds && FD_ISSET (i, xfds)))
+ && dup2 (i, i) != i)
+ return -1;
+ }
+
+ return pselect (nfds, rfds, wfds, xfds, timeout, sigmask);
+}
+
+#endif