diff options
Diffstat (limited to 'sys/kern/sys_generic.c')
-rw-r--r-- | sys/kern/sys_generic.c | 128 |
1 files changed, 95 insertions, 33 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c index 1cd1287..0199615 100644 --- a/sys/kern/sys_generic.c +++ b/sys/kern/sys_generic.c @@ -1289,26 +1289,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); @@ -1316,34 +1350,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); @@ -1359,7 +1392,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; } @@ -1369,6 +1402,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) { |