summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormatthew <matthew@openbsd.org>2013-04-29 17:06:20 +0000
committermatthew <matthew@openbsd.org>2013-04-29 17:06:20 +0000
commit17132ff2f50b3e4acd4801692230c7ffd78ee56e (patch)
tree48782d15d4b6d053e29214a7ec9670a0e7fb317f
parentRemove most of pre-rc.d(8) backward compatibility. (diff)
downloadwireguard-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_version2
-rw-r--r--lib/libc/sys/Makefile.inc6
-rw-r--r--lib/libc/sys/poll.265
-rw-r--r--lib/libc/sys/select.264
-rw-r--r--lib/librthread/rthread_cancel.c50
-rw-r--r--lib/librthread/shlib_version2
-rw-r--r--sys/kern/kern_sig.c16
-rw-r--r--sys/kern/sys_generic.c234
-rw-r--r--sys/kern/syscalls.master10
-rw-r--r--sys/sys/poll.h29
-rw-r--r--sys/sys/select.h25
-rw-r--r--sys/sys/signal.h5
-rw-r--r--sys/sys/time.h10
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