Index: lib/libc/include/namespace.h =================================================================== --- lib/libc/include/namespace.h +++ lib/libc/include/namespace.h @@ -82,6 +82,7 @@ #define open _open #define openat _openat #define poll _poll +#define ppoll _ppoll #define pthread_atfork _pthread_atfork #define pthread_attr_destroy _pthread_attr_destroy #define pthread_attr_get_np _pthread_attr_get_np Index: lib/libc/include/un-namespace.h =================================================================== --- lib/libc/include/un-namespace.h +++ lib/libc/include/un-namespace.h @@ -63,6 +63,7 @@ #undef open #undef openat #undef poll +#undef ppoll #undef pthread_atfork #undef pthread_attr_destroy #undef pthread_attr_get_np Index: lib/libc/sys/Makefile.inc =================================================================== --- lib/libc/sys/Makefile.inc +++ lib/libc/sys/Makefile.inc @@ -198,6 +198,7 @@ posix_fadvise.2 \ posix_fallocate.2 \ posix_openpt.2 \ + ppoll.2 \ procctl.2 \ profil.2 \ pselect.2 \ Index: lib/libc/sys/Symbol.map =================================================================== --- lib/libc/sys/Symbol.map +++ lib/libc/sys/Symbol.map @@ -399,6 +399,10 @@ wait6; }; +FBSD_1.4 { + ppoll; +}; + FBSDprivate_1.0 { ___acl_aclcheck_fd; __sys___acl_aclcheck_fd; Index: lib/libc/sys/ppoll.2 =================================================================== --- /dev/null +++ lib/libc/sys/ppoll.2 @@ -0,0 +1,103 @@ +.\" Copyright (c) 2014 Dmitry Chagin. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd November 9, 2014 +.Dt PPOLL 2 +.Os +.Sh NAME +.Nm ppoll +.Nd synchronous I/O multiplexing +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In poll.h +.Ft int +.Fo ppoll +.Fa "struct pollfd fds[]" +.Fa "nfds_t nfds" +.Fa "const struct timespec * restrict timeout" +.Fa "const sigset_t * restrict newsigmask" +.Fc +.Sh DESCRIPTION +The +.Fn ppoll +function examines a set of file descriptors to see if some of them are ready for I/O. +The +.Fa fds and nfds +arguments are identical to the analogous arguments of +.Fn poll . +The +.Fa timeout +argument in +.Fn ppoll +points to a +.Vt "const struct timespec" +rather than the +.Vt "int timeout" +used by +.Fn poll ; +a null pointer may be passed to indicate that +.Fn ppoll +should wait indefinitely . +Finally, +.Fa newsigmask +specifies a signal mask which is set while waiting for input. +When +.Fn ppoll +returns, the original signal mask is restored. +.Pp +See +.Xr poll 2 +for a more detailed discussion of the semantics of this interface. +.Sh RETURN VALUES +The +.Fn ppoll +fuction returns the same values and under the same conditions as +.Fn poll . +.Sh ERRORS +The +.Fn ppoll +function may fail for any of the reasons documented for +.Xr poll 2 +and (if a signal mask provided) +.Xr sigprocmask 2 . +.El +.Sh SEE ALSO +.Xr kqueue 2 , +.Xr poll 2 , +.Xr pselect 2 , +.Xr select 2 , +.Xr sigprocmask 2 . +.Sh HISTORY +The +.Fn ppoll +function first appeared in +.Fx 11.0 . +.Sh AUTHORS +The first implementation of +.Fn ppoll +function and this manual page were written by +.An Dmitry Chagin Aq Mt dchagin@FreeBSD.org . Index: sys/compat/freebsd32/freebsd32_misc.c =================================================================== --- sys/compat/freebsd32/freebsd32_misc.c +++ sys/compat/freebsd32/freebsd32_misc.c @@ -3017,3 +3017,31 @@ } return (kern_fcntl_freebsd(td, uap->fd, uap->cmd, tmp)); } + +int +freebsd32_ppoll(struct thread *td, struct freebsd32_ppoll_args *uap) +{ + struct timespec32 ts32; + struct timespec ts, *tsp; + sigset_t set, *ssp; + int error; + + if (uap->ts != NULL) { + error = copyin(uap->ts, &ts32, sizeof(ts32)); + if (error != 0) + return (error); + CP(ts32, ts, tv_sec); + CP(ts32, ts, tv_nsec); + tsp = &ts; + } else + tsp = NULL; + if (uap->set != NULL) { + error = copyin(uap->set, &set, sizeof(set)); + if (error != 0) + return (error); + ssp = &set; + } else + ssp = NULL; + + return (kern_ppoll(td, uap->fds, uap->nfds, tsp, ssp)); +} Index: sys/compat/freebsd32/syscalls.master =================================================================== --- sys/compat/freebsd32/syscalls.master +++ sys/compat/freebsd32/syscalls.master @@ -1066,3 +1066,6 @@ uint32_t id1, uint32_t id2, int com, \ void *data); } #endif +545 AUE_POLL STD { int freebsd32_ppoll(struct pollfd *fds, \ + u_int nfds, const struct timespec32 *ts, \ + const sigset_t *set); } Index: sys/kern/sys_generic.c =================================================================== --- sys/kern/sys_generic.c +++ sys/kern/sys_generic.c @@ -97,6 +97,8 @@ u_int); static int pollscan(struct thread *, struct pollfd *, u_int); static int pollrescan(struct thread *); +static int kern_poll(struct thread *, struct pollfd *, u_int, + sbintime_t, sbintime_t); static int selscan(struct thread *, fd_mask **, fd_mask **, int); static int selrescan(struct thread *, fd_mask **, fd_mask **); static void selfdalloc(struct thread *, void *); @@ -1301,30 +1303,12 @@ struct thread *td; struct poll_args *uap; { - struct pollfd *bits; - struct pollfd smallbits[32]; sbintime_t asbt, precision, rsbt; - u_int nfds; - int error; - size_t ni; - nfds = uap->nfds; - if (nfds > maxfilesperproc && nfds > FD_SETSIZE) - return (EINVAL); - ni = nfds * sizeof(struct pollfd); - if (ni > sizeof(smallbits)) - bits = malloc(ni, M_TEMP, M_WAITOK); - else - bits = smallbits; - error = copyin(uap->fds, bits, ni); - if (error) - goto done; precision = 0; if (uap->timeout != INFTIM) { - if (uap->timeout < 0) { - error = EINVAL; - goto done; - } + if (uap->timeout < 0) + return (EINVAL); if (uap->timeout == 0) asbt = 0; else { @@ -1337,13 +1321,37 @@ } } else asbt = -1; + + return (kern_poll(td, uap->fds, uap->nfds, asbt, precision)); +} + +static int +kern_poll(struct thread *td, struct pollfd *fds, u_int nfds, + sbintime_t sbt, sbintime_t prec) +{ + struct pollfd *bits; + struct pollfd smallbits[32]; + int error; + size_t ni; + + if (nfds > maxfilesperproc && nfds > FD_SETSIZE) + return (EINVAL); + ni = nfds * sizeof(struct pollfd); + if (ni > sizeof(smallbits)) + bits = malloc(ni, M_TEMP, M_WAITOK); + else + bits = smallbits; + error = copyin(fds, bits, ni); + if (error) + goto done; + seltdinit(td); /* Iterate until the timeout expires or descriptors become ready. */ for (;;) { error = pollscan(td, bits, nfds); if (error || td->td_retval[0] != 0) break; - error = seltdwait(td, asbt, precision); + error = seltdwait(td, sbt, prec); if (error) break; error = pollrescan(td); @@ -1359,7 +1367,7 @@ if (error == EWOULDBLOCK) error = 0; if (error == 0) { - error = pollout(td, bits, uap->fds, nfds); + error = pollout(td, bits, fds, nfds); if (error) goto out; } @@ -1369,6 +1377,88 @@ return (error); } +int +sys_ppoll(struct thread *td, struct ppoll_args *uap) +{ + struct timespec ts, *tsp; + sigset_t set, *ssp; + int error; + + if (uap->ts != NULL) { + error = copyin(uap->ts, &ts, sizeof(ts)); + if (error) + return (error); + tsp = &ts; + } else + tsp = NULL; + if (uap->set != NULL) { + error = copyin(uap->set, &set, sizeof(set)); + if (error) + return (error); + ssp = &set; + } else + ssp = NULL; + /* + * fds is still a pointer to user space. kern_poll() will + * take care of copyin that array to the kernel space. + */ + + return (kern_ppoll(td, uap->fds, uap->nfds, tsp, ssp)); +} + +int +kern_ppoll(struct thread *td, struct pollfd *fds, u_int nfds, + struct timespec *tsp, sigset_t *uset) +{ + struct timespec ts; + sbintime_t sbt, precision, tmp; + time_t over; + int error; + + precision = 0; + if (tsp != NULL) { + if (tsp->tv_sec < 0) + return (EINVAL); + if (tsp->tv_nsec < 0 || tsp->tv_nsec >= 1000000000) + return (EINVAL); + if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) + sbt = 0; + else { + ts = *tsp; + if (ts.tv_sec > INT32_MAX / 2) { + over = ts.tv_sec - INT32_MAX / 2; + ts.tv_sec -= over; + } else + over = 0; + tmp = tstosbt(ts); + precision = tmp; + precision >>= tc_precexp; + if (TIMESEL(&sbt, tmp)) + sbt += tc_tick_sbt; + sbt += tmp; + } + } else + sbt = -1; + + if (uset != NULL) { + error = kern_sigprocmask(td, SIG_SETMASK, uset, + &td->td_oldsigmask, 0); + if (error != 0) + return (error); + td->td_pflags |= TDP_OLDMASK; + /* + * Make sure that ast() is called on return to + * usermode and TDP_OLDMASK is cleared, restoring old + * sigmask. + */ + thread_lock(td); + td->td_flags |= TDF_ASTPENDING; + thread_unlock(td); + } + + return (kern_poll(td, fds, nfds, sbt, precision)); +} + static int pollrescan(struct thread *td) { Index: sys/kern/syscalls.master =================================================================== --- sys/kern/syscalls.master +++ sys/kern/syscalls.master @@ -980,5 +980,8 @@ 543 AUE_NULL NOSTD { int aio_mlock(struct aiocb *aiocbp); } 544 AUE_NULL STD { int procctl(idtype_t idtype, id_t id, \ int com, void *data); } +545 AUE_POLL STD { int ppoll(struct pollfd *fds, u_int nfds, \ + const struct timespec *ts, \ + const sigset_t *set); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master Index: sys/sys/poll.h =================================================================== --- sys/sys/poll.h +++ sys/sys/poll.h @@ -32,6 +32,16 @@ #define _SYS_POLL_H_ #include +#include + +#include +#include + + +#ifndef _SIGSET_T_DECLARED +#define _SIGSET_T_DECLARED +typedef __sigset_t sigset_t; +#endif /* * This file is intended to be compatible with the traditional poll.h. @@ -97,6 +107,9 @@ __BEGIN_DECLS int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout); +int ppoll(struct pollfd _pfd[], nfds_t _nfds, + const struct timespec *__restrict _timeout, + const sigset_t *__restrict _newsigmask); __END_DECLS #endif /* !_KERNEL */ Index: sys/sys/syscallsubr.h =================================================================== --- sys/sys/syscallsubr.h +++ sys/sys/syscallsubr.h @@ -46,6 +46,7 @@ struct mbuf; struct msghdr; struct msqid_ds; +struct pollfd; struct ogetdirentries_args; struct rlimit; struct rusage; @@ -164,6 +165,8 @@ int name, u_long flags); int kern_pipe(struct thread *td, int fildes[2]); int kern_pipe2(struct thread *td, int fildes[2], int flags); +int kern_ppoll(struct thread *td, struct pollfd *fds, u_int nfds, + struct timespec *tsp, sigset_t *uset); int kern_posix_fadvise(struct thread *td, int fd, off_t offset, off_t len, int advice); int kern_posix_fallocate(struct thread *td, int fd, off_t offset,