Linux has a pselect syscall since 2.6.something. Using it
rather than emulating it with sigprocmask+select+sigprocmask
is smaller code, and works properly. (The emulation has
race conditions when unblocked signals arrive before or
after the select)

The tv.nsec >= 1E9 handling comes from uclibc's linux select()
implementation, which itself uses pselect() internally if the
pselect syscall exists. I though it would be good to do the
same here.

Signed-off-by: Nicolas S. Dade <nic.d...@gmail.com>
---
 libc/sysdeps/linux/common/pselect.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/libc/sysdeps/linux/common/pselect.c 
b/libc/sysdeps/linux/common/pselect.c
index bf19ce3..928577e 100644
--- a/libc/sysdeps/linux/common/pselect.c
+++ b/libc/sysdeps/linux/common/pselect.c
@@ -30,6 +30,32 @@ static int __NC(pselect)(int nfds, fd_set *readfds, fd_set 
*writefds,
                         fd_set *exceptfds, const struct timespec *timeout,
                         const sigset_t *sigmask)
 {
+#ifdef __NR_pselect6
+#define NSEC_PER_SEC 1000000000L
+       struct timespec _ts, *ts = 0;
+       if (timeout) {
+               /* The Linux kernel can in some situations update the timeout 
value.
+                * We do not want that so use a local variable.
+                */
+               _ts.tv_sec = timeout->tv_sec;
+               _ts.tv_nsec = timeout->tv_nsec;
+
+               /* GNU extension: allow for timespec values where the sub-sec
+               * field is equal to or more than 1 second.  The kernel will
+               * reject this on us, so take care of the time shift ourself.
+               * Some applications (like readline and linphone) do this.
+               * See 'clarification on select() type calls and invalid 
timeouts'
+               * on the POSIX general list for more information.
+               */
+               if (_ts.tv_nsec >= NSEC_PER_SEC) {
+                       _ts.tv_sec += _ts.tv_nsec / NSEC_PER_SEC;
+                       _ts.tv_nsec %= NSEC_PER_SEC;
+               }
+
+               ts = &_ts;
+       }
+       return INLINE_SYSCALL(pselect6, 6, nfds, readfds, writefds, exceptfds, 
ts, sigmask);
+#else
        struct timeval tval;
        int retval;
        sigset_t savemask;
@@ -57,6 +83,7 @@ static int __NC(pselect)(int nfds, fd_set *readfds, fd_set 
*writefds,
                sigprocmask (SIG_SETMASK, &savemask, NULL);
 
        return retval;
+#endif
 }
 CANCELLABLE_SYSCALL(int, pselect, (int nfds, fd_set *readfds, fd_set 
*writefds, fd_set *exceptfds,
                                   const struct timespec *timeout, const 
sigset_t *sigmask),
-- 
1.9.1

_______________________________________________
uClibc mailing list
uClibc@uclibc.org
http://lists.busybox.net/mailman/listinfo/uclibc

Reply via email to