Add the ppoll() system call.
Export kern_poll() needed by an upcoming Linuxulator change. Differential Revision: https://reviews.freebsd.org/D1133 Reviewed by: kib, wblock MFC after: 1 month
This commit is contained in:
parent
aa8d1792d1
commit
186d9c3473
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -2991,3 +2991,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));
|
||||
}
|
||||
|
@ -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); }
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user