summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordchagin <dchagin@FreeBSD.org>2014-12-21 07:58:28 +0000
committerdchagin <dchagin@FreeBSD.org>2014-12-21 07:58:28 +0000
commitdfe2ad4d4623524826fd780517aa15fdc759a1da (patch)
tree7345c217602377f5b4227533feef3ce74e57a719
parentf73f068967977545d4d60b36864475974dca2613 (diff)
downloadFreeBSD-src-dfe2ad4d4623524826fd780517aa15fdc759a1da.zip
FreeBSD-src-dfe2ad4d4623524826fd780517aa15fdc759a1da.tar.gz
MFC r274462: Add the ppoll() system call.
-rw-r--r--lib/libc/sys/Makefile.inc1
-rw-r--r--lib/libc/sys/Symbol.map6
-rw-r--r--lib/libc/sys/poll.265
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c28
-rw-r--r--sys/compat/freebsd32/syscalls.master3
-rw-r--r--sys/kern/sys_generic.c128
-rw-r--r--sys/kern/syscalls.master3
-rw-r--r--sys/sys/poll.h18
-rw-r--r--sys/sys/syscallsubr.h3
9 files changed, 220 insertions, 35 deletions
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index c9ed70c..b01657f 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -356,6 +356,7 @@ MLINKS+=pdfork.2 pdgetpid.2\
pdfork.2 pdkill.2 \
pdfork.2 pdwait4.2
MLINKS+=pipe.2 pipe2.2
+MLINKS+=poll.2 ppoll.2
MLINKS+=read.2 pread.2 \
read.2 preadv.2 \
read.2 readv.2
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index fe887c3..448bcce 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -399,6 +399,10 @@ FBSD_1.3 {
wait6;
};
+FBSD_1.4 {
+ ppoll;
+};
+
FBSDprivate_1.0 {
___acl_aclcheck_fd;
__sys___acl_aclcheck_fd;
@@ -821,6 +825,8 @@ FBSDprivate_1.0 {
__sys_pipe;
_poll;
__sys_poll;
+ _ppoll;
+ __sys_ppoll;
_preadv;
__sys_preadv;
_procctl;
diff --git a/lib/libc/sys/poll.2 b/lib/libc/sys/poll.2
index 932186d..a1c7ada 100644
--- a/lib/libc/sys/poll.2
+++ b/lib/libc/sys/poll.2
@@ -28,7 +28,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd July 8, 2002
+.Dd November 13, 2014
.Dt POLL 2
.Os
.Sh NAME
@@ -40,6 +40,13 @@
.In poll.h
.Ft int
.Fn poll "struct pollfd fds[]" "nfds_t nfds" "int timeout"
+.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 poll
@@ -139,6 +146,47 @@ If
is zero, then
.Fn poll
will return without blocking.
+.Pp
+The
+.Fn ppoll
+system call, unlike
+.Fn poll ,
+is used to safely wait until either a set of file descriptors becomes
+ready or until a signal is caught.
+The
+.Fa fds
+and
+.Fa 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"
+which is defined in
+.In sys/timespec.h
+(shown below) 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
+.Bd -literal
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* and nanoseconds */
+};
+.Ed
.Sh RETURN VALUES
The
.Fn poll
@@ -185,17 +233,26 @@ points outside the process's allocated address space.
A signal was delivered before the time limit expired and
before any of the selected events occurred.
.It Bq Er EINVAL
-The specified time limit is negative.
+The specified time limit is invalid. One of its components is negative or too large.
.El
.Sh SEE ALSO
.Xr accept 2 ,
.Xr connect 2 ,
.Xr kqueue 2 ,
+.Xr pselect 2 ,
.Xr read 2 ,
.Xr recv 2 ,
.Xr select 2 ,
.Xr send 2 ,
.Xr write 2
+.Sh STANDARDS
+The
+.Fn poll
+function conforms to
+.St -p1003.1-2001 .
+The
+.Fn ppoll
+is not specified by POSIX.
.Sh HISTORY
The
.Fn poll
@@ -203,6 +260,10 @@ function appeared in
.At V .
This manual page and the core of the implementation was taken from
.Nx .
+The
+.Fn ppoll
+function first appeared in
+.Fx 11.0
.Sh BUGS
The distinction between some of the fields in the
.Fa events
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index eeb8347..2061100 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -3102,3 +3102,31 @@ freebsd32_fcntl(struct thread *td, struct freebsd32_fcntl_args *uap)
}
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_poll(td, uap->fds, uap->nfds, tsp, ssp));
+}
diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master
index f14fb76..ed3cc29 100644
--- a/sys/compat/freebsd32/syscalls.master
+++ b/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); }
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 2358172..6131dab 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -1300,26 +1300,60 @@ selscan(td, ibits, obits, nfd)
return (0);
}
-#ifndef _SYS_SYSPROTO_H_
-struct poll_args {
- struct pollfd *fds;
- u_int nfds;
- int timeout;
-};
-#endif
int
-sys_poll(td, uap)
- struct thread *td;
- struct poll_args *uap;
+sys_poll(struct thread *td, struct poll_args *uap)
+{
+ struct timespec ts, *tsp;
+
+ if (uap->timeout != INFTIM) {
+ if (uap->timeout < 0)
+ return (EINVAL);
+ ts.tv_sec = uap->timeout / 1000;
+ ts.tv_nsec = (uap->timeout % 1000) * 1000000;
+ tsp = &ts;
+ } else
+ tsp = NULL;
+
+ return (kern_poll(td, uap->fds, uap->nfds, tsp, NULL));
+}
+
+int
+kern_poll(struct thread *td, struct pollfd *fds, u_int nfds,
+ struct timespec *tsp, sigset_t *uset)
{
struct pollfd *bits;
struct pollfd smallbits[32];
- sbintime_t asbt, precision, rsbt;
- u_int nfds;
+ sbintime_t sbt, precision, tmp;
+ time_t over;
+ struct timespec ts;
int error;
size_t ni;
- nfds = uap->nfds;
+ 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 (nfds > maxfilesperproc && nfds > FD_SETSIZE)
return (EINVAL);
ni = nfds * sizeof(struct pollfd);
@@ -1327,34 +1361,33 @@ sys_poll(td, uap)
bits = malloc(ni, M_TEMP, M_WAITOK);
else
bits = smallbits;
- error = copyin(uap->fds, bits, ni);
+ error = copyin(fds, bits, ni);
if (error)
goto done;
- precision = 0;
- if (uap->timeout != INFTIM) {
- if (uap->timeout < 0) {
- error = EINVAL;
+
+ if (uset != NULL) {
+ error = kern_sigprocmask(td, SIG_SETMASK, uset,
+ &td->td_oldsigmask, 0);
+ if (error)
goto done;
- }
- if (uap->timeout == 0)
- asbt = 0;
- else {
- rsbt = SBT_1MS * uap->timeout;
- precision = rsbt;
- precision >>= tc_precexp;
- if (TIMESEL(&asbt, rsbt))
- asbt += tc_tick_sbt;
- asbt += rsbt;
- }
- } else
- asbt = -1;
+ 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);
+ }
+
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, precision);
if (error)
break;
error = pollrescan(td);
@@ -1370,7 +1403,7 @@ done:
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;
}
@@ -1380,6 +1413,35 @@ out:
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_poll(td, uap->fds, uap->nfds, tsp, ssp));
+}
+
static int
pollrescan(struct thread *td)
{
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index e959214..15c2d12 100644
--- a/sys/kern/syscalls.master
+++ b/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
diff --git a/sys/sys/poll.h b/sys/sys/poll.h
index c955f32..ca3ce12 100644
--- a/sys/sys/poll.h
+++ b/sys/sys/poll.h
@@ -95,8 +95,26 @@ struct pollfd {
#ifndef _KERNEL
+#if __BSD_VISIBLE
+#include <sys/_types.h>
+
+#include <sys/_sigset.h>
+#include <sys/timespec.h>
+
+#ifndef _SIGSET_T_DECLARED
+#define _SIGSET_T_DECLARED
+typedef __sigset_t sigset_t;
+#endif
+
+#endif
+
__BEGIN_DECLS
int poll(struct pollfd _pfd[], nfds_t _nfds, int _timeout);
+#if __BSD_VISIBLE
+int ppoll(struct pollfd _pfd[], nfds_t _nfds,
+ const struct timespec *__restrict _timeout,
+ const sigset_t *__restrict _newsigmask);
+#endif
__END_DECLS
#endif /* !_KERNEL */
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 52c894d..6d8316d 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -46,6 +46,7 @@ struct ksiginfo;
struct mbuf;
struct msghdr;
struct msqid_ds;
+struct pollfd;
struct ogetdirentries_args;
struct rlimit;
struct rusage;
@@ -164,6 +165,8 @@ int kern_pathconf(struct thread *td, char *path, enum uio_seg pathseg,
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_poll(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,
OpenPOWER on IntegriCloud