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:
Dmitry Chagin 2014-11-13 05:26:14 +00:00
parent aa8d1792d1
commit 186d9c3473
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=274462
9 changed files with 220 additions and 35 deletions

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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));
}

View File

@ -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); }

View File

@ -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 @@ sys_poll(td, uap)
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 @@ sys_poll(td, uap)
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)
{

View File

@ -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

View File

@ -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 */

View File

@ -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,