diff options
author | 2013-04-29 17:06:20 +0000 | |
---|---|---|
committer | 2013-04-29 17:06:20 +0000 | |
commit | 17132ff2f50b3e4acd4801692230c7ffd78ee56e (patch) | |
tree | 48782d15d4b6d053e29214a7ec9670a0e7fb317f | |
parent | Remove most of pre-rc.d(8) backward compatibility. (diff) | |
download | wireguard-openbsd-17132ff2f50b3e4acd4801692230c7ffd78ee56e.tar.xz wireguard-openbsd-17132ff2f50b3e4acd4801692230c7ffd78ee56e.zip |
Extend P_SIGSUSPEND handling in userret() to properly restore the
sigmask even if there are no pending signals under the temporary
sigmask.
Refactor existing select() and poll() system calls to introduce the
pselect() and ppoll() system calls.
Add rthread wrappers for pselect() and ppoll(). While there, update
cancellation point comments to reflect recent fdatasync() addition.
Minor bumps for libc and librthread due to new symbols.
ok guenther, millert, deraadt, jmc
-rw-r--r-- | lib/libc/shlib_version | 2 | ||||
-rw-r--r-- | lib/libc/sys/Makefile.inc | 6 | ||||
-rw-r--r-- | lib/libc/sys/poll.2 | 65 | ||||
-rw-r--r-- | lib/libc/sys/select.2 | 64 | ||||
-rw-r--r-- | lib/librthread/rthread_cancel.c | 50 | ||||
-rw-r--r-- | lib/librthread/shlib_version | 2 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 16 | ||||
-rw-r--r-- | sys/kern/sys_generic.c | 234 | ||||
-rw-r--r-- | sys/kern/syscalls.master | 10 | ||||
-rw-r--r-- | sys/sys/poll.h | 29 | ||||
-rw-r--r-- | sys/sys/select.h | 25 | ||||
-rw-r--r-- | sys/sys/signal.h | 5 | ||||
-rw-r--r-- | sys/sys/time.h | 10 |
13 files changed, 404 insertions, 114 deletions
diff --git a/lib/libc/shlib_version b/lib/libc/shlib_version index bf8551aca93..b52840ac023 100644 --- a/lib/libc/shlib_version +++ b/lib/libc/shlib_version @@ -1,4 +1,4 @@ major=68 -minor=0 +minor=1 # note: If changes were made to include/thread_private.h or if system # calls were added/changed then librthread/shlib_version also be updated. diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index a22d4bf77e6..57f76b8fb16 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile.inc,v 1.110 2013/04/15 16:38:21 matthew Exp $ +# $OpenBSD: Makefile.inc,v 1.111 2013/04/29 17:06:20 matthew Exp $ # $NetBSD: Makefile.inc,v 1.35 1995/10/16 23:49:07 jtc Exp $ # @(#)Makefile.inc 8.1 (Berkeley) 6/17/93 @@ -45,7 +45,7 @@ ASM= __get_tcb.o __getcwd.o __semctl.o __set_tcb.o __syscall.o \ mknod.o mknodat.o mlock.o mlockall.o mount.o mprotect.o \ msgctl.o msgget.o msgrcv.o msgsnd.o msync.o munlock.o \ munlockall.o munmap.o nanosleep.o nfssvc.o \ - open.o openat.o pathconf.o pipe.o poll.o profil.o \ + open.o openat.o pathconf.o pipe.o poll.o ppoll.o profil.o pselect.o \ quotactl.o read.o readlink.o readlinkat.o readv.o reboot.o \ recvfrom.o recvmsg.o rename.o renameat.o revoke.o rmdir.o \ sched_yield.o select.o semget.o semop.o sendmsg.o sendto.o \ @@ -239,10 +239,12 @@ MLINKS+=mlockall.2 munlockall.2 MLINKS+=mount.2 unmount.2 MLINKS+=open.2 openat.2 MLINKS+=pathconf.2 fpathconf.2 +MLINKS+=poll.2 ppoll.2 MLINKS+=read.2 readv.2 read.2 pread.2 read.2 preadv.2 MLINKS+=readlink.2 readlinkat.2 MLINKS+=recv.2 recvfrom.2 recv.2 recvmsg.2 MLINKS+=rename.2 renameat.2 +MLINKS+=select.2 pselect.2 MLINKS+=select.2 FD_ISSET.3 select.2 FD_ZERO.3 MLINKS+=select.2 FD_SET.3 select.2 FD_CLR.3 MLINKS+=send.2 sendmsg.2 send.2 sendto.2 diff --git a/lib/libc/sys/poll.2 b/lib/libc/sys/poll.2 index adfb20831c1..7ceaffb33fa 100644 --- a/lib/libc/sys/poll.2 +++ b/lib/libc/sys/poll.2 @@ -1,4 +1,4 @@ -.\" $OpenBSD: poll.2,v 1.21 2007/07/11 08:12:15 jmc Exp $ +.\" $OpenBSD: poll.2,v 1.22 2013/04/29 17:06:20 matthew Exp $ .\" .\" Copyright (c) 1994 Jason R. Thorpe .\" All rights reserved. @@ -28,16 +28,19 @@ .\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" -.Dd $Mdocdate: July 11 2007 $ +.Dd $Mdocdate: April 29 2013 $ .Dt POLL 2 .Os .Sh NAME -.Nm poll +.Nm poll , +.Nm ppoll .Nd synchronous I/O multiplexing .Sh SYNOPSIS .Fd #include <poll.h> .Ft int .Fn poll "struct pollfd *fds" "nfds_t nfds" "int timeout" +.Ft int +.Fn ppoll "struct pollfd *fds" "nfds_t nfds" "const struct timespec *timeout" "const sigset_t *mask" .Sh DESCRIPTION .Fn poll provides a mechanism for multiplexing I/O across a set of file @@ -176,18 +179,39 @@ In addition to I/O multiplexing, can be used to generate simple timeouts. This functionality may be achieved by passing a null pointer for .Fa fds . +.Pp +The +.Fn ppoll +function is similar to +.Fn poll +except that it specifies the timeout using a timespec structure, +and a null pointer is used to specify an indefinite timeout +instead of +.Dv INFTIM . +Also, if +.Fa mask +is a non-null pointer, +.Fn ppoll +atomically sets the calling thread's signal mask to the signal set +pointed to by +.Fa mask +for the duration of the function call. +In this case, the original signal mask will be restored before +.Fn ppoll +returns. .Sh RETURN VALUES Upon error, .Fn poll -returns \-1 and sets the global variable +and +.Fn ppoll +return \-1 and set the global variable .Va errno to indicate the error. If the timeout interval was reached before any events occurred, -.Fn poll -returns 0. -Otherwise, -.Fn poll -returns the number of file descriptors for which +they return 0. +Otherwise, they return the number of +.Fa pollfd +structures for which .Fa revents is non-zero. .Sh EXAMPLES @@ -215,22 +239,22 @@ if (read(STDIN_FILENO, buf, sizeof(buf)) == -1) .Ed .Sh ERRORS .Fn poll +and +.Fn ppoll will fail if: -.Bl -tag -width "EINVAL " +.Bl -tag -width Er .It Bq Er EFAULT .Fa fds points outside the process's allocated address space. .It Bq Er EINTR -.Fn poll -caught a signal during the polling process. +A signal was caught before any polled events occurred +and before the timeout elapsed. .It Bq Er EINVAL .Fa nfds was greater than the number of available file descriptors. .It Bq Er EINVAL -The timeout passed to -.Fn poll -was too large. +The timeout passed was invalid. .El .Sh SEE ALSO .Xr getrlimit 2 , @@ -243,11 +267,18 @@ The function is compliant with the .St -xpg4.3 specification. +The +.Fn ppoll +function is a Linux extension. .Sh HISTORY A .Fn poll system call appeared in .At V.3 . +The +.Fn ppoll +function appeared in +.Ox 5.4 . .Sh BUGS The .Dv POLLERR @@ -273,4 +304,6 @@ flags are equivalent. .Pp Internally to the kernel, .Fn poll -works poorly if multiple processes wait on the same file descriptor. +and +.Fn ppoll +work poorly if multiple processes wait on the same file descriptor. diff --git a/lib/libc/sys/select.2 b/lib/libc/sys/select.2 index c521598f672..1cd5bee23ca 100644 --- a/lib/libc/sys/select.2 +++ b/lib/libc/sys/select.2 @@ -1,4 +1,4 @@ -.\" $OpenBSD: select.2,v 1.28 2007/05/31 19:19:33 jmc Exp $ +.\" $OpenBSD: select.2,v 1.29 2013/04/29 17:06:20 matthew Exp $ .\" $NetBSD: select.2,v 1.5 1995/06/27 22:32:28 cgd Exp $ .\" .\" Copyright (c) 1983, 1991, 1993 @@ -30,11 +30,12 @@ .\" .\" @(#)select.2 8.2 (Berkeley) 3/25/94 .\" -.Dd $Mdocdate: May 31 2007 $ +.Dd $Mdocdate: April 29 2013 $ .Dt SELECT 2 .Os .Sh NAME -.Nm select +.Nm select , +.Nm pselect .Nd synchronous I/O multiplexing .Sh SYNOPSIS .Fd #include <sys/types.h> @@ -43,6 +44,8 @@ .Fd #include <unistd.h> .Ft int .Fn select "int nfds" "fd_set *readfds" "fd_set *writefds" "fd_set *exceptfds" "struct timeval *timeout" +.Ft int +.Fn pselect "int nfds" "fd_set *readfds" "fd_set *writefds" "fd_set *exceptfds" "const struct timespec *timeout" "const sigset_t *mask" .Fn FD_SET fd &fdset .Fn FD_CLR fd &fdset .Fn FD_ISSET fd &fdset @@ -122,20 +125,47 @@ Any of and .Fa exceptfds may be given as null pointers if no descriptors are of interest. -.Sh RETURN VALUES +.Pp +The +.Fn pselect +function is similar to .Fn select -returns the number of ready descriptors that are contained in -the descriptor sets, or \-1 if an error occurred. -If the time limit expires, +except that it specifies the timeout using a timespec structure. +Also, if +.Fa mask +is a non-null pointer, +.Fn pselect +atomically sets the calling thread's signal mask to the signal set +pointed to by +.Fa mask +for the duration of the function call. +In this case, the original signal mask will be restored before +.Fn pselect +returns. +.Sh RETURN VALUES +If successful, .Fn select -returns 0. -If +and +.Fn pselect +return the number of ready descriptors that are contained in +the descriptor sets. +If a descriptor is included in multiple descriptor sets, +each inclusion is counted separately. +If the time limit expires before any descriptors become ready, +they return 0. +.Pp +Otherwise, if .Fn select -returns with an error, including one due to an interrupted call, -the descriptor sets will be unmodified. +or +.Fn pselect +return with an error, including one due to an interrupted call, +they return \-1, +and the descriptor sets will be unmodified. .Sh ERRORS An error return from .Fn select +or +.Fn pselect indicates: .Bl -tag -width Er .It Bq Er EFAULT @@ -149,7 +179,7 @@ points outside the process's allocated address space. One of the descriptor sets specified an invalid descriptor. .It Bq Er EINTR A signal was delivered before the time limit expired and -before any of the selected events occurred. +before any of the selected descriptors became ready. .It Bq Er EINVAL The specified time limit is invalid. One of its components is negative or too large. @@ -167,8 +197,12 @@ One of its components is negative or too large. .Sh HISTORY The .Fn select -function call appeared in +function appeared in .Bx 4.2 . +The +.Fn pselect +function appeared in +.Ox 5.4 . .Sh BUGS Although the provision of .Xr getdtablesize 3 @@ -250,7 +284,9 @@ and using .Pp Internally to the kernel, .Fn select -works poorly if multiple processes wait on the same file descriptor. +and +.Fn pselect +work poorly if multiple processes wait on the same file descriptor. Given that, it is rather surprising to see that many daemons are written that way (i.e., .Xr httpd 8 ) . diff --git a/lib/librthread/rthread_cancel.c b/lib/librthread/rthread_cancel.c index a1ccd9f0669..0004eb74f47 100644 --- a/lib/librthread/rthread_cancel.c +++ b/lib/librthread/rthread_cancel.c @@ -1,4 +1,4 @@ -/* $OpenBSD: rthread_cancel.c,v 1.6 2012/04/17 15:10:11 miod Exp $ */ +/* $OpenBSD: rthread_cancel.c,v 1.7 2013/04/29 17:06:20 matthew Exp $ */ /* $snafu: libc_tag.c,v 1.4 2004/11/30 07:00:06 marc Exp $ */ /* PUBLIC DOMAIN: No Rights Reserved. Marco S Hyman <marc@snafu.org> */ @@ -40,8 +40,12 @@ int _thread_sys_nanosleep(const struct timespec *, struct timespec *); int _thread_sys_open(const char *, int, ...); int _thread_sys_openat(int, const char *, int, ...); int _thread_sys_poll(struct pollfd *, nfds_t, int); +int _thread_sys_ppoll(struct pollfd *, nfds_t, const struct timespec *, + const sigset_t *); ssize_t _thread_sys_pread(int, void *, size_t, off_t); ssize_t _thread_sys_preadv(int, const struct iovec *, int, off_t); +int _thread_sys_pselect(int, fd_set *, fd_set *, fd_set *, + const struct timespec *, const sigset_t *); ssize_t _thread_sys_pwrite(int, const void *, size_t, off_t); ssize_t _thread_sys_pwritev(int, const struct iovec *, int, off_t); ssize_t _thread_sys_read(int, void *, size_t); @@ -203,7 +207,7 @@ fcntl(int fd, int cmd, ...) } #if 0 -fdatasync() /* don't have yet */ +fdatasync() /* built on fsync() */ #endif int @@ -333,6 +337,26 @@ poll(struct pollfd *fds, nfds_t nfds, int timeout) return (rv); } +int +ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, + const sigset_t *sigmask) +{ + pthread_t self = pthread_self(); + sigset_t set; + int rv; + + if (sigmask != NULL && sigismember(sigmask, SIGTHR)) { + set = *sigmask; + sigdelset(&set, SIGTHR); + sigmask = &set; + } + + _enter_cancel(self); + rv = _thread_sys_ppoll(fds, nfds, timeout, sigmask); + _leave_cancel(self); + return (rv); +} + ssize_t pread(int fd, void *buf, size_t nbytes, off_t offset) { @@ -357,8 +381,28 @@ preadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) return (rv); } +int +pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, + const struct timespec *timeout, const sigset_t *sigmask) +{ + pthread_t self = pthread_self(); + sigset_t set; + int rv; + + if (sigmask != NULL && sigismember(sigmask, SIGTHR)) { + set = *sigmask; + sigdelset(&set, SIGTHR); + sigmask = &set; + } + + _enter_cancel(self); + rv = _thread_sys_pselect(nfds, readfds, writefds, exceptfds, timeout, + sigmask); + _leave_cancel(self); + return (rv); +} + #if 0 -pselect() /* don't have yet */ putmsg() /* don't have: dumb STREAMS stuff */ putpmsg() /* don't have: dumb STREAMS stuff */ #endif diff --git a/lib/librthread/shlib_version b/lib/librthread/shlib_version index ffdd3d2d569..730231c38d0 100644 --- a/lib/librthread/shlib_version +++ b/lib/librthread/shlib_version @@ -1,2 +1,2 @@ major=17 -minor=0 +minor=1 diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 6f754f63cd7..fb7e0ee95f7 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.150 2013/04/06 06:08:20 tedu Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.151 2013/04/29 17:06:20 matthew Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -1744,6 +1744,20 @@ userret(struct proc *p) while ((sig = CURSIG(p)) != 0) postsig(sig); + /* + * If P_SIGSUSPEND is still set here, then we still need to restore + * the original sigmask before returning to userspace. Also, this + * might unmask some pending signals, so we need to check a second + * time for signals to post. + */ + if (p->p_flag & P_SIGSUSPEND) { + atomic_clearbits_int(&p->p_flag, P_SIGSUSPEND); + p->p_sigmask = p->p_oldmask; + + while ((sig = CURSIG(p)) != 0) + postsig(sig); + } + if (p->p_flag & P_SUSPSINGLE) { KERNEL_LOCK(); single_thread_check(p, 0); diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 8c9a8acc204..fb8c0fe76f6 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sys_generic.c,v 1.78 2012/07/09 17:51:08 claudio Exp $ */ +/* $OpenBSD: sys_generic.c,v 1.79 2013/04/29 17:06:20 matthew Exp $ */ /* $NetBSD: sys_generic.c,v 1.24 1996/03/29 00:25:32 cgd Exp $ */ /* @@ -65,6 +65,10 @@ int selscan(struct proc *, fd_set *, fd_set *, int, int, register_t *); void pollscan(struct proc *, struct pollfd *, u_int, register_t *); int pollout(struct pollfd *, struct pollfd *, u_int); +int dopselect(struct proc *, u_int, fd_set *, fd_set *, fd_set *, + const struct timespec *, const sigset_t *, register_t *); +int doppoll(struct proc *, struct pollfd *, u_int, const struct timespec *, + const sigset_t *, register_t *); /* * Read system call. @@ -534,13 +538,75 @@ sys_select(struct proc *p, void *v, register_t *retval) syscallarg(fd_set *) ex; syscallarg(struct timeval *) tv; } */ *uap = v; + + struct timespec ts, *tsp = NULL; + int error; + + if (SCARG(uap, tv) != NULL) { + struct timeval tv; + if ((error = copyin(SCARG(uap, tv), &tv, sizeof tv)) != 0) + return (error); + if ((error = itimerfix(&tv)) != 0) + return (error); +#ifdef KTRACE + if (KTRPOINT(p, KTR_STRUCT)) + ktrreltimeval(p, &tv); +#endif + TIMEVAL_TO_TIMESPEC(&tv, &ts); + tsp = &ts; + } + + return (dopselect(p, SCARG(uap, nd), SCARG(uap, in), SCARG(uap, ou), + SCARG(uap, ex), tsp, NULL, retval)); +} + +int +sys_pselect(struct proc *p, void *v, register_t *retval) +{ + struct sys_pselect_args /* { + syscallarg(int) nd; + syscallarg(fd_set *) in; + syscallarg(fd_set *) ou; + syscallarg(fd_set *) ex; + syscallarg(const struct timespec *) ts; + syscallarg(const sigset_t *) mask; + } */ *uap = v; + + struct timespec ts, *tsp = NULL; + sigset_t ss, *ssp = NULL; + int error; + + if (SCARG(uap, ts) != NULL) { + if ((error = copyin(SCARG(uap, ts), &ts, sizeof ts)) != 0) + return (error); + if ((error = timespecfix(&ts)) != 0) + return (error); +#ifdef KTRACE + if (KTRPOINT(p, KTR_STRUCT)) + ktrreltimespec(p, &ts); +#endif + tsp = &ts; + } + if (SCARG(uap, mask) != NULL) { + if ((error = copyin(SCARG(uap, mask), &ss, sizeof ss)) != 0) + return (error); + ssp = &ss; + } + + return (dopselect(p, SCARG(uap, nd), SCARG(uap, in), SCARG(uap, ou), + SCARG(uap, ex), tsp, ssp, retval)); +} + +int +dopselect(struct proc *p, u_int nd, fd_set *in, fd_set *ou, fd_set *ex, + const struct timespec *tsp, const sigset_t *sigmask, register_t *retval) +{ fd_mask bits[6]; fd_set *pibits[3], *pobits[3]; - struct timeval atv, rtv, ttv; + struct timespec ats, rts, tts; int s, ncoll, error = 0, timo; - u_int nd, ni; + u_int ni; - nd = SCARG(uap, nd); if (nd > p->p_fd->fd_nfiles) { /* forgiving; slightly wrong */ nd = p->p_fd->fd_nfiles; @@ -567,8 +633,7 @@ sys_select(struct proc *p, void *v, register_t *retval) } #define getbits(name, x) \ - if (SCARG(uap, name) && (error = copyin(SCARG(uap, name), \ - pibits[x], ni))) \ + if (name && (error = copyin(name, pibits[x], ni))) \ goto done; getbits(in, 0); getbits(ou, 1); @@ -576,46 +641,40 @@ sys_select(struct proc *p, void *v, register_t *retval) #undef getbits #ifdef KTRACE if (ni > 0 && KTRPOINT(p, KTR_STRUCT)) { - if (SCARG(uap, in)) ktrfdset(p, pibits[0], ni); - if (SCARG(uap, ou)) ktrfdset(p, pibits[1], ni); - if (SCARG(uap, ex)) ktrfdset(p, pibits[2], ni); + if (in) ktrfdset(p, pibits[0], ni); + if (ou) ktrfdset(p, pibits[1], ni); + if (ex) ktrfdset(p, pibits[2], ni); } #endif - if (SCARG(uap, tv)) { - error = copyin(SCARG(uap, tv), &atv, sizeof (atv)); - if (error) - goto done; -#ifdef KTRACE - if (KTRPOINT(p, KTR_STRUCT)) - ktrreltimeval(p, &atv); -#endif - if (itimerfix(&atv)) { - error = EINVAL; - goto done; - } - getmicrouptime(&rtv); - timeradd(&atv, &rtv, &atv); + if (tsp) { + getnanouptime(&rts); + timespecadd(tsp, &rts, &ats); } else { - atv.tv_sec = 0; - atv.tv_usec = 0; + ats.tv_sec = 0; + ats.tv_nsec = 0; } timo = 0; + if (sigmask) { + p->p_oldmask = p->p_sigmask; + atomic_setbits_int(&p->p_flag, P_SIGSUSPEND); + p->p_sigmask = *sigmask &~ sigcantmask; + } + retry: ncoll = nselcoll; atomic_setbits_int(&p->p_flag, P_SELECT); error = selscan(p, pibits[0], pobits[0], nd, ni, retval); if (error || *retval) goto done; - if (SCARG(uap, tv)) { - getmicrouptime(&rtv); - if (timercmp(&rtv, &atv, >=)) + if (tsp) { + getnanouptime(&rts); + if (timespeccmp(&rts, &ats, >=)) goto done; - ttv = atv; - timersub(&ttv, &rtv, &ttv); - timo = ttv.tv_sec > 24 * 60 * 60 ? - 24 * 60 * 60 * hz : tvtohz(&ttv); + timespecsub(&ats, &rts, &tts); + timo = tts.tv_sec > 24 * 60 * 60 ? + 24 * 60 * 60 * hz : tstohz(&tts); } s = splhigh(); if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { @@ -635,8 +694,7 @@ done: if (error == EWOULDBLOCK) error = 0; #define putbits(name, x) \ - if (SCARG(uap, name) && (error2 = copyout(pobits[x], \ - SCARG(uap, name), ni))) \ + if (name && (error2 = copyout(pobits[x], name, ni))) \ error = error2; if (error == 0) { int error2; @@ -647,9 +705,9 @@ done: #undef putbits #ifdef KTRACE if (ni > 0 && KTRPOINT(p, KTR_STRUCT)) { - if (SCARG(uap, in)) ktrfdset(p, pobits[0], ni); - if (SCARG(uap, ou)) ktrfdset(p, pobits[1], ni); - if (SCARG(uap, ex)) ktrfdset(p, pobits[2], ni); + if (in) ktrfdset(p, pobits[0], ni); + if (ou) ktrfdset(p, pobits[1], ni); + if (ex) ktrfdset(p, pobits[2], ni); } #endif } @@ -819,13 +877,67 @@ sys_poll(struct proc *p, void *v, register_t *retval) syscallarg(u_int) nfds; syscallarg(int) timeout; } */ *uap = v; + + struct timespec ts, *tsp = NULL; + int msec = SCARG(uap, timeout); + + if (msec != INFTIM) { + if (msec < 0) + return (EINVAL); + ts.tv_sec = msec / 1000; + ts.tv_nsec = (msec - (ts.tv_sec * 1000)) * 1000000; + tsp = &ts; + } + + return (doppoll(p, SCARG(uap, fds), SCARG(uap, nfds), tsp, NULL, + retval)); +} + +int +sys_ppoll(struct proc *p, void *v, register_t *retval) +{ + struct sys_ppoll_args /* { + syscallarg(struct pollfd *) fds; + syscallarg(u_int) nfds; + syscallarg(const struct timespec *) ts; + syscallarg(const sigset_t *) mask; + } */ *uap = v; + + int error; + struct timespec ts, *tsp = NULL; + sigset_t ss, *ssp = NULL; + + if (SCARG(uap, ts) != NULL) { + if ((error = copyin(SCARG(uap, ts), &ts, sizeof ts)) != 0) + return (error); + if ((error = timespecfix(&ts)) != 0) + return (error); +#ifdef KTRACE + if (KTRPOINT(p, KTR_STRUCT)) + ktrreltimespec(p, &ts); +#endif + tsp = &ts; + } + + if (SCARG(uap, mask) != NULL) { + if ((error = copyin(SCARG(uap, mask), &ss, sizeof ss)) != 0) + return (error); + ssp = &ss; + } + + return (doppoll(p, SCARG(uap, fds), SCARG(uap, nfds), tsp, ssp, + retval)); +} + +int +doppoll(struct proc *p, struct pollfd *fds, u_int nfds, + const struct timespec *tsp, const sigset_t *sigmask, register_t *retval) +{ size_t sz; struct pollfd pfds[4], *pl = pfds; - int msec = SCARG(uap, timeout); - struct timeval atv, rtv, ttv; + struct timespec ats, rts, tts; int timo, ncoll, i, s, error; extern int nselcoll, selwait; - u_int nfds = SCARG(uap, nfds); /* Standards say no more than MAX_OPEN; this is possibly better. */ if (nfds > min((int)p->p_rlimit[RLIMIT_NOFILE].rlim_cur, maxfiles)) @@ -837,42 +949,40 @@ sys_poll(struct proc *p, void *v, register_t *retval) if (sz > sizeof(pfds)) pl = (struct pollfd *) malloc(sz, M_TEMP, M_WAITOK); - if ((error = copyin(SCARG(uap, fds), pl, sz)) != 0) + if ((error = copyin(fds, pl, sz)) != 0) goto bad; for (i = 0; i < nfds; i++) pl[i].revents = 0; - if (msec != INFTIM) { - atv.tv_sec = msec / 1000; - atv.tv_usec = (msec - (atv.tv_sec * 1000)) * 1000; - - if (itimerfix(&atv)) { - error = EINVAL; - goto done; - } - getmicrouptime(&rtv); - timeradd(&atv, &rtv, &atv); + if (tsp != NULL) { + getnanouptime(&rts); + timespecadd(tsp, &rts, &ats); } else { - atv.tv_sec = 0; - atv.tv_usec = 0; + ats.tv_sec = 0; + ats.tv_nsec = 0; } timo = 0; + if (sigmask) { + p->p_oldmask = p->p_sigmask; + atomic_setbits_int(&p->p_flag, P_SIGSUSPEND); + p->p_sigmask = *sigmask &~ sigcantmask; + } + retry: ncoll = nselcoll; atomic_setbits_int(&p->p_flag, P_SELECT); pollscan(p, pl, nfds, retval); if (*retval) goto done; - if (msec != INFTIM) { - getmicrouptime(&rtv); - if (timercmp(&rtv, &atv, >=)) + if (tsp != NULL) { + getnanouptime(&rts); + if (timespeccmp(&rts, &ats, >=)) goto done; - ttv = atv; - timersub(&ttv, &rtv, &ttv); - timo = ttv.tv_sec > 24 * 60 * 60 ? - 24 * 60 * 60 * hz : tvtohz(&ttv); + timespecsub(&ats, &rts, &tts); + timo = tts.tv_sec > 24 * 60 * 60 ? + 24 * 60 * 60 * hz : tstohz(&tts); } s = splhigh(); if ((p->p_flag & P_SELECT) == 0 || nselcoll != ncoll) { @@ -893,13 +1003,13 @@ done: */ switch (error) { case ERESTART: - error = pollout(pl, SCARG(uap, fds), nfds); + error = pollout(pl, fds, nfds); if (error == 0) error = EINTR; break; case EWOULDBLOCK: case 0: - error = pollout(pl, SCARG(uap, fds), nfds); + error = pollout(pl, fds, nfds); break; } bad: diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index f6b193b48a0..ae4c947cccd 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ -; $OpenBSD: syscalls.master,v 1.129 2013/04/15 15:32:19 jsing Exp $ +; $OpenBSD: syscalls.master,v 1.130 2013/04/29 17:06:20 matthew Exp $ ; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $ ; @(#)syscalls.master 8.2 (Berkeley) 1/13/94 @@ -207,8 +207,12 @@ 106 STD { int sys_listen(int s, int backlog); } 107 OBSOL vtimes 108 OBSOL osigvec -109 OBSOL osigblock -110 OBSOL osigsetmask +109 STD { int sys_ppoll(struct pollfd *fds, \ + u_int nfds, const struct timespec *ts, \ + const sigset_t *mask); } +110 STD { int sys_pselect(int nd, fd_set *in, fd_set *ou, \ + fd_set *ex, const struct timespec *ts, \ + const sigset_t *mask); } 111 STD { int sys_sigsuspend(int mask); } 112 OBSOL osigstack 113 OBSOL orecvmsg diff --git a/sys/sys/poll.h b/sys/sys/poll.h index 84d28658937..184b3501c45 100644 --- a/sys/sys/poll.h +++ b/sys/sys/poll.h @@ -1,4 +1,4 @@ -/* $OpenBSD: poll.h,v 1.11 2003/12/10 23:10:08 millert Exp $ */ +/* $OpenBSD: poll.h,v 1.12 2013/04/29 17:06:20 matthew Exp $ */ /* * Copyright (c) 1996 Theo de Raadt @@ -51,10 +51,35 @@ typedef unsigned int nfds_t; #define INFTIM (-1) #ifndef _KERNEL -#include <ctype.h> +#include <sys/cdefs.h> + +#ifdef __BSD_VISIBLE +#include <sys/_types.h> + +#ifndef _SIGSET_T_DEFINED_ +#define _SIGSET_T_DEFINED_ +typedef unsigned int sigset_t; +#endif + +#ifndef _TIME_T_DEFINED_ +#define _TIME_T_DEFINED_ +typedef __time_t time_t; +#endif + +#ifndef _TIMESPEC_DECLARED +#define _TIMESPEC_DECLARED +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* and nanoseconds */ +}; +#endif +#endif /* __BSD_VISIBLE */ __BEGIN_DECLS int poll(struct pollfd[], nfds_t, int); +#ifdef __BSD_VISIBLE +int ppoll(struct pollfd[], nfds_t, const struct timespec *, const sigset_t *); +#endif /* __BSD_VISIBLE */ __END_DECLS #endif /* _KERNEL */ diff --git a/sys/sys/select.h b/sys/sys/select.h index 6dc0416a0c2..3cefa70db31 100644 --- a/sys/sys/select.h +++ b/sys/sys/select.h @@ -1,4 +1,4 @@ -/* $OpenBSD: select.h,v 1.10 2012/12/05 23:20:24 deraadt Exp $ */ +/* $OpenBSD: select.h,v 1.11 2013/04/29 17:06:20 matthew Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -37,6 +37,17 @@ #include <sys/time.h> /* for types and struct timeval */ /* + * Currently, <sys/time.h> includes <sys/types.h> before defining timeval and + * timespec, and <sys/types.h> in turn includes <sys/select.h>. So even though + * we include <sys/time.h> above, the compiler might not see the timeval and + * timespec definitions until after this header's contents have been processed. + * + * As a workaround, we forward declare timeval and timespec as structs here. + */ +struct timeval; +struct timespec; + +/* * Select uses bit masks of file descriptors in longs. These macros * manipulate such bit fields (the filesystem macros use chars). * FD_SETSIZE may be defined by the user, but the default here should @@ -83,11 +94,19 @@ typedef struct fd_set { #endif /* __BSD_VISIBLE */ #ifndef _KERNEL +#ifndef _SIGSET_T_DEFINED_ +#define _SIGSET_T_DEFINED_ +typedef unsigned int sigset_t; +#endif + #ifndef _SELECT_DEFINED_ #define _SELECT_DEFINED_ __BEGIN_DECLS -struct timeval; -int select(int, fd_set *, fd_set *, fd_set *, struct timeval *); +int select(int, fd_set * __restrict, fd_set * __restrict, + fd_set * __restrict, struct timeval * __restrict); +int pselect(int, fd_set * __restrict, fd_set * __restrict, + fd_set * __restrict, const struct timespec * __restrict, + const sigset_t * __restrict); __END_DECLS #endif #endif /* !_KERNEL */ diff --git a/sys/sys/signal.h b/sys/sys/signal.h index 53f7eb99073..f54860fb9a5 100644 --- a/sys/sys/signal.h +++ b/sys/sys/signal.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signal.h,v 1.25 2013/03/24 17:46:25 deraadt Exp $ */ +/* $OpenBSD: signal.h,v 1.26 2013/04/29 17:06:20 matthew Exp $ */ /* $NetBSD: signal.h,v 1.21 1996/02/09 18:25:32 christos Exp $ */ /* @@ -99,7 +99,10 @@ #define SIG_ERR (void (*)(int))-1 #if __POSIX_VISIBLE || __XPG_VISIBLE +#ifndef _SIGSET_T_DEFINED_ +#define _SIGSET_T_DEFINED_ typedef unsigned int sigset_t; +#endif #include <sys/siginfo.h> diff --git a/sys/sys/time.h b/sys/sys/time.h index b120fbf09a8..c9536b97e05 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -1,4 +1,4 @@ -/* $OpenBSD: time.h,v 1.29 2012/12/05 23:20:24 deraadt Exp $ */ +/* $OpenBSD: time.h,v 1.30 2013/04/29 17:06:20 matthew Exp $ */ /* $NetBSD: time.h,v 1.18 1996/04/23 10:29:33 mycroft Exp $ */ /* @@ -37,10 +37,6 @@ #include <sys/types.h> -#if __XPG_VISIBLE >= 420 && __XPG_VISIBLE < 600 -#include <sys/select.h> -#endif - /* * Structure returned by gettimeofday(2) system call, * and used in other calls. @@ -329,6 +325,10 @@ void clock_secs_to_ymdhms(time_t, struct clock_ymdhms *); #else /* !_KERNEL */ #include <time.h> +#if __XPG_VISIBLE >= 420 && __XPG_VISIBLE < 600 +#include <sys/select.h> /* must be after type declarations */ +#endif + #if __BSD_VISIBLE || __XPG_VISIBLE __BEGIN_DECLS #if __BSD_VISIBLE |