summaryrefslogtreecommitdiffstats
path: root/freebsd/sys/kern/sys_generic.c
diff options
context:
space:
mode:
Diffstat (limited to 'freebsd/sys/kern/sys_generic.c')
-rw-r--r--freebsd/sys/kern/sys_generic.c494
1 files changed, 321 insertions, 173 deletions
diff --git a/freebsd/sys/kern/sys_generic.c b/freebsd/sys/kern/sys_generic.c
index 91733ca3..26cd9d36 100644
--- a/freebsd/sys/kern/sys_generic.c
+++ b/freebsd/sys/kern/sys_generic.c
@@ -46,11 +46,12 @@ __FBSDID("$FreeBSD$");
#include <rtems/bsd/sys/param.h>
#include <sys/systm.h>
#include <sys/sysproto.h>
-#include <sys/capability.h>
+#include <sys/capsicum.h>
#include <sys/filedesc.h>
#include <sys/filio.h>
#include <sys/fcntl.h>
#include <sys/file.h>
+#include <rtems/bsd/sys/lock.h>
#include <sys/proc.h>
#include <sys/signalvar.h>
#include <sys/socketvar.h>
@@ -94,12 +95,14 @@ __FBSDID("$FreeBSD$");
#define SYS_IOCTL_SMALL_ALIGN 8 /* bytes */
#ifndef __rtems__
-int iosize_max_clamp = 1;
+#ifdef __LP64__
+static int iosize_max_clamp = 0;
SYSCTL_INT(_debug, OID_AUTO, iosize_max_clamp, CTLFLAG_RW,
&iosize_max_clamp, 0, "Clamp max i/o size to INT_MAX");
-int devfs_iosize_max_clamp = 1;
+static int devfs_iosize_max_clamp = 1;
SYSCTL_INT(_debug, OID_AUTO, devfs_iosize_max_clamp, CTLFLAG_RW,
&devfs_iosize_max_clamp, 0, "Clamp max i/o size to INT_MAX for devices");
+#endif
/*
* Assert that the return value of read(2) and write(2) syscalls fits
@@ -131,7 +134,7 @@ static int dofilewrite(struct thread *, int, struct file *, struct uio *,
#endif /* __rtems__ */
static void doselwakeup(struct selinfo *, int);
static void seltdinit(struct thread *);
-static int seltdwait(struct thread *, int);
+static int seltdwait(struct thread *, sbintime_t, sbintime_t);
static void seltdclear(struct thread *);
/*
@@ -163,12 +166,31 @@ struct selfd {
struct mtx *sf_mtx; /* Pointer to selinfo mtx. */
struct seltd *sf_td; /* (k) owning seltd. */
void *sf_cookie; /* (k) fd or pollfd. */
+ u_int sf_refs;
};
static uma_zone_t selfd_zone;
static struct mtx_pool *mtxpool_select;
#ifndef __rtems__
+#ifdef __LP64__
+size_t
+devfs_iosize_max(void)
+{
+
+ return (devfs_iosize_max_clamp || SV_CURPROC_FLAG(SV_ILP32) ?
+ INT_MAX : SSIZE_MAX);
+}
+
+size_t
+iosize_max(void)
+{
+
+ return (iosize_max_clamp || SV_CURPROC_FLAG(SV_ILP32) ?
+ INT_MAX : SSIZE_MAX);
+}
+#endif
+
#ifndef _SYS_SYSPROTO_H_
struct read_args {
int fd;
@@ -230,6 +252,7 @@ sys_pread(td, uap)
return(error);
}
+#if defined(COMPAT_FREEBSD6)
int
freebsd6_pread(td, uap)
struct thread *td;
@@ -243,6 +266,7 @@ freebsd6_pread(td, uap)
oargs.offset = uap->offset;
return (sys_pread(td, &oargs));
}
+#endif
/*
* Scatter read system call.
@@ -272,9 +296,10 @@ int
kern_readv(struct thread *td, int fd, struct uio *auio)
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = fget_read(td, fd, CAP_READ | CAP_SEEK, &fp);
+ error = fget_read(td, fd, cap_rights_init(&rights, CAP_READ), &fp);
if (error)
return (error);
error = dofileread(td, fd, fp, auio, (off_t)-1, 0);
@@ -315,9 +340,10 @@ kern_preadv(td, fd, auio, offset)
off_t offset;
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = fget_read(td, fd, CAP_READ, &fp);
+ error = fget_read(td, fd, cap_rights_init(&rights, CAP_PREAD), &fp);
if (error)
return (error);
if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
@@ -349,6 +375,8 @@ dofileread(td, fd, fp, auio, offset, flags)
struct uio *ktruio = NULL;
#endif
+ AUDIT_ARG_FD(fd);
+
/* Finish zero length reads right here */
if (auio->uio_resid == 0) {
td->td_retval[0] = 0;
@@ -439,6 +467,7 @@ sys_pwrite(td, uap)
return(error);
}
+#if defined(COMPAT_FREEBSD6)
int
freebsd6_pwrite(td, uap)
struct thread *td;
@@ -452,6 +481,7 @@ freebsd6_pwrite(td, uap)
oargs.offset = uap->offset;
return (sys_pwrite(td, &oargs));
}
+#endif
/*
* Gather write system call.
@@ -481,9 +511,10 @@ int
kern_writev(struct thread *td, int fd, struct uio *auio)
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = fget_write(td, fd, CAP_WRITE | CAP_SEEK, &fp);
+ error = fget_write(td, fd, cap_rights_init(&rights, CAP_WRITE), &fp);
if (error)
return (error);
error = dofilewrite(td, fd, fp, auio, (off_t)-1, 0);
@@ -524,9 +555,10 @@ kern_pwritev(td, fd, auio, offset)
off_t offset;
{
struct file *fp;
+ cap_rights_t rights;
int error;
- error = fget_write(td, fd, CAP_WRITE, &fp);
+ error = fget_write(td, fd, cap_rights_init(&rights, CAP_PWRITE), &fp);
if (error)
return (error);
if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE))
@@ -558,6 +590,7 @@ dofilewrite(td, fd, fp, auio, offset, flags)
struct uio *ktruio = NULL;
#endif
+ AUDIT_ARG_FD(fd);
auio->uio_rw = UIO_WRITE;
auio->uio_td = td;
auio->uio_offset = offset;
@@ -604,12 +637,13 @@ kern_ftruncate(td, fd, length)
off_t length;
{
struct file *fp;
+ cap_rights_t rights;
int error;
AUDIT_ARG_FD(fd);
if (length < 0)
return (EINVAL);
- error = fget(td, fd, CAP_FTRUNCATE, &fp);
+ error = fget(td, fd, cap_rights_init(&rights, CAP_FTRUNCATE), &fp);
if (error)
return (error);
AUDIT_ARG_FILE(td->td_proc, fp);
@@ -737,28 +771,64 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data)
{
struct file *fp;
struct filedesc *fdp;
- int error;
- int tmp;
+#ifndef CAPABILITIES
+ cap_rights_t rights;
+#endif
+ int error, tmp, locked;
AUDIT_ARG_FD(fd);
AUDIT_ARG_CMD(com);
- if ((error = fget(td, fd, CAP_IOCTL, &fp)) != 0)
- return (error);
- if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
- fdrop(fp, td);
- return (EBADF);
- }
+
fdp = td->td_proc->p_fd;
+
switch (com) {
case FIONCLEX:
+ case FIOCLEX:
FILEDESC_XLOCK(fdp);
- fdp->fd_ofileflags[fd] &= ~UF_EXCLOSE;
- FILEDESC_XUNLOCK(fdp);
+ locked = LA_XLOCKED;
+ break;
+ default:
+#ifdef CAPABILITIES
+ FILEDESC_SLOCK(fdp);
+ locked = LA_SLOCKED;
+#else
+ locked = LA_UNLOCKED;
+#endif
+ break;
+ }
+
+#ifdef CAPABILITIES
+ if ((fp = fget_locked(fdp, fd)) == NULL) {
+ error = EBADF;
+ goto out;
+ }
+ if ((error = cap_ioctl_check(fdp, fd, com)) != 0) {
+ fp = NULL; /* fhold() was not called yet */
+ goto out;
+ }
+ fhold(fp);
+ if (locked == LA_SLOCKED) {
+ FILEDESC_SUNLOCK(fdp);
+ locked = LA_UNLOCKED;
+ }
+#else
+ error = fget(td, fd, cap_rights_init(&rights, CAP_IOCTL), &fp);
+ if (error != 0) {
+ fp = NULL;
+ goto out;
+ }
+#endif
+ if ((fp->f_flag & (FREAD | FWRITE)) == 0) {
+ error = EBADF;
+ goto out;
+ }
+
+ switch (com) {
+ case FIONCLEX:
+ fdp->fd_ofiles[fd].fde_flags &= ~UF_EXCLOSE;
goto out;
case FIOCLEX:
- FILEDESC_XLOCK(fdp);
- fdp->fd_ofileflags[fd] |= UF_EXCLOSE;
- FILEDESC_XUNLOCK(fdp);
+ fdp->fd_ofiles[fd].fde_flags |= UF_EXCLOSE;
goto out;
case FIONBIO:
if ((tmp = *(int *)data))
@@ -778,7 +848,21 @@ kern_ioctl(struct thread *td, int fd, u_long com, caddr_t data)
error = fo_ioctl(fp, com, data, td->td_ucred, td);
out:
- fdrop(fp, td);
+ switch (locked) {
+ case LA_XLOCKED:
+ FILEDESC_XUNLOCK(fdp);
+ break;
+#ifdef CAPABILITIES
+ case LA_SLOCKED:
+ FILEDESC_SUNLOCK(fdp);
+ break;
+#endif
+ default:
+ FILEDESC_UNLOCK_ASSERT(fdp);
+ break;
+ }
+ if (fp != NULL)
+ fdrop(fp, td);
return (error);
}
#endif /* __rtems__ */
@@ -939,9 +1023,10 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
*/
fd_mask s_selbits[howmany(2048, NFDBITS)];
fd_mask *ibits[3], *obits[3], *selbits, *sbp;
- struct timeval atv, rtv, ttv;
- int error, lf, ndu, timo;
+ struct timeval rtv;
+ sbintime_t asbt, precision, rsbt;
u_int nbufbytes, ncpbytes, ncpubytes, nfdbits;
+ int error, lf, ndu;
if (nd < 0)
return (EINVAL);
@@ -1038,35 +1123,37 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
if (nbufbytes != 0)
bzero(selbits, nbufbytes / 2);
+ precision = 0;
if (tvp != NULL) {
- atv = *tvp;
- if (itimerfix(&atv)) {
+ rtv = *tvp;
+ if (rtv.tv_sec < 0 || rtv.tv_usec < 0 ||
+ rtv.tv_usec >= 1000000) {
error = EINVAL;
goto done;
}
- getmicrouptime(&rtv);
- timevaladd(&atv, &rtv);
- } else {
- atv.tv_sec = 0;
- atv.tv_usec = 0;
- }
- timo = 0;
+ if (!timevalisset(&rtv))
+ asbt = 0;
+ else if (rtv.tv_sec <= INT32_MAX) {
+ rsbt = tvtosbt(rtv);
+ precision = rsbt;
+ precision >>= tc_precexp;
+ if (TIMESEL(&asbt, rsbt))
+ asbt += tc_tick_sbt;
+ if (asbt <= SBT_MAX - rsbt)
+ asbt += rsbt;
+ else
+ asbt = -1;
+ } else
+ asbt = -1;
+ } else
+ asbt = -1;
seltdinit(td);
/* Iterate until the timeout expires or descriptors become ready. */
for (;;) {
error = selscan(td, ibits, obits, nd);
if (error || td->td_retval[0] != 0)
break;
- if (atv.tv_sec || atv.tv_usec) {
- getmicrouptime(&rtv);
- if (timevalcmp(&rtv, &atv, >=))
- break;
- ttv = atv;
- timevalsub(&ttv, &rtv);
- timo = ttv.tv_sec > 24 * 60 * 60 ?
- 24 * 60 * 60 * hz : tvtohz(&ttv);
- }
- error = seltdwait(td, timo);
+ error = seltdwait(td, asbt, precision);
if (error)
break;
error = selrescan(td, ibits, obits);
@@ -1196,32 +1283,11 @@ selsetbits(fd_mask **ibits, fd_mask **obits, int idx, fd_mask bit, int events)
static __inline int
getselfd_cap(struct filedesc *fdp, int fd, struct file **fpp)
{
- struct file *fp;
-#ifdef CAPABILITIES
- struct file *fp_fromcap;
- int error;
-#endif
+ cap_rights_t rights;
- if ((fp = fget_unlocked(fdp, fd)) == NULL)
- return (EBADF);
-#ifdef CAPABILITIES
- /*
- * If the file descriptor is for a capability, test rights and use
- * the file descriptor references by the capability.
- */
- error = cap_funwrap(fp, CAP_POLL_EVENT, &fp_fromcap);
- if (error) {
- fdrop(fp, curthread);
- return (error);
- }
- if (fp != fp_fromcap) {
- fhold(fp_fromcap);
- fdrop(fp, curthread);
- fp = fp_fromcap;
- }
-#endif /* CAPABILITIES */
- *fpp = fp;
- return (0);
+ cap_rights_init(&rights, CAP_EVENT);
+
+ return (fget_unlocked(fdp, fd, &rights, fpp, NULL));
}
/*
@@ -1315,29 +1381,66 @@ selscan(td, ibits, obits, nfd)
return (0);
}
-#ifndef _SYS_SYSPROTO_H_
-struct poll_args {
- struct pollfd *fds;
- u_int nfds;
- int timeout;
-};
-#endif
#ifdef __rtems__
+static int kern_poll(struct thread *td, struct pollfd *fds, u_int nfds,
+ struct timespec *tsp, sigset_t *uset);
+
static
#endif /* __rtems__ */
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];
- struct timeval atv, rtv, ttv;
- int error, timo;
- 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;
+
#ifndef __rtems__
if (nfds > maxfilesperproc && nfds > FD_SETSIZE)
#else /* __rtems__ */
@@ -1349,39 +1452,35 @@ 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;
- if (uap->timeout != INFTIM) {
- atv.tv_sec = uap->timeout / 1000;
- atv.tv_usec = (uap->timeout % 1000) * 1000;
- if (itimerfix(&atv)) {
- error = EINVAL;
+
+#ifndef __rtems__
+ if (uset != NULL) {
+ error = kern_sigprocmask(td, SIG_SETMASK, uset,
+ &td->td_oldsigmask, 0);
+ if (error)
goto done;
- }
- getmicrouptime(&rtv);
- timevaladd(&atv, &rtv);
- } else {
- atv.tv_sec = 0;
- atv.tv_usec = 0;
+ 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);
}
- timo = 0;
+#endif /* __rtems__ */
+
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;
- if (atv.tv_sec || atv.tv_usec) {
- getmicrouptime(&rtv);
- if (timevalcmp(&rtv, &atv, >=))
- break;
- ttv = atv;
- timevalsub(&ttv, &rtv);
- timo = ttv.tv_sec > 24 * 60 * 60 ?
- 24 * 60 * 60 * hz : tvtohz(&ttv);
- }
- error = seltdwait(td, timo);
+ error = seltdwait(td, sbt, precision);
if (error)
break;
error = pollrescan(td);
@@ -1397,7 +1496,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;
}
@@ -1432,6 +1531,37 @@ poll(struct pollfd fds[], nfds_t nfds, int timeout)
}
#endif /* __rtems__ */
+#ifndef __rtems__
+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));
+}
+#endif /* __rtems__ */
+
static int
pollrescan(struct thread *td)
{
@@ -1442,6 +1572,9 @@ pollrescan(struct thread *td)
struct filedesc *fdp;
struct file *fp;
struct pollfd *fd;
+#ifdef CAPABILITIES
+ cap_rights_t rights;
+#endif
int n;
n = 0;
@@ -1460,16 +1593,18 @@ pollrescan(struct thread *td)
if (si != NULL)
continue;
#ifndef __rtems__
- fp = fdp->fd_ofiles[fd->fd];
+ fp = fdp->fd_ofiles[fd->fd].fde_file;
#else /* __rtems__ */
- fp = fget_unlocked(fdp, fd->fd);
+ fget_unlocked(fdp, fd->fd, NULL, &fp, NULL);
#endif /* __rtems__ */
#ifdef CAPABILITIES
- if ((fp == NULL)
- || (cap_funwrap(fp, CAP_POLL_EVENT, &fp) != 0)) {
+ if (fp == NULL ||
+ cap_check(cap_rights(fdp, fd->fd),
+ cap_rights_init(&rights, CAP_EVENT)) != 0)
#else
- if (fp == NULL) {
+ if (fp == NULL)
#endif
+ {
fd->revents = POLLNVAL;
n++;
continue;
@@ -1526,14 +1661,16 @@ pollscan(td, fds, nfd)
#else /* __rtems__ */
struct filedesc *fdp = NULL;
#endif /* __rtems__ */
- int i;
struct file *fp;
- int n = 0;
+#ifdef CAPABILITIES
+ cap_rights_t rights;
+#endif
+ int i, n = 0;
FILEDESC_SLOCK(fdp);
for (i = 0; i < nfd; i++, fds++) {
#ifndef __rtems__
- if (fds->fd >= fdp->fd_nfiles) {
+ if (fds->fd > fdp->fd_lastfile) {
#else /* __rtems__ */
if (fds->fd >= rtems_libio_number_iops) {
#endif /* __rtems__ */
@@ -1543,16 +1680,18 @@ pollscan(td, fds, nfd)
fds->revents = 0;
} else {
#ifndef __rtems__
- fp = fdp->fd_ofiles[fds->fd];
+ fp = fdp->fd_ofiles[fds->fd].fde_file;
#else /* __rtems__ */
- fp = fget_unlocked(fdp, fds->fd);
+ fget_unlocked(fdp, fds->fd, NULL, &fp, NULL);
#endif /* __rtems__ */
#ifdef CAPABILITIES
- if ((fp == NULL)
- || (cap_funwrap(fp, CAP_POLL_EVENT, &fp) != 0)) {
+ if (fp == NULL ||
+ cap_check(cap_rights(fdp, fds->fd),
+ cap_rights_init(&rights, CAP_EVENT)) != 0)
#else
- if (fp == NULL) {
+ if (fp == NULL)
#endif
+ {
fds->revents = POLLNVAL;
n++;
} else {
@@ -1582,26 +1721,6 @@ pollscan(td, fds, nfd)
#ifndef __rtems__
/*
- * OpenBSD poll system call.
- *
- * XXX this isn't quite a true representation.. OpenBSD uses select ops.
- */
-#ifndef _SYS_SYSPROTO_H_
-struct openbsd_poll_args {
- struct pollfd *fds;
- u_int nfds;
- int timeout;
-};
-#endif
-int
-sys_openbsd_poll(td, uap)
- register struct thread *td;
- register struct openbsd_poll_args *uap;
-{
- return (sys_poll(td, (struct poll_args *)uap));
-}
-
-/*
* XXX This was created specifically to support netncp and netsmb. This
* allows the caller to specify a socket to wait for events on. It returns
* 0 if any events matched and an error otherwise. There is no way to
@@ -1610,21 +1729,32 @@ sys_openbsd_poll(td, uap)
int
selsocket(struct socket *so, int events, struct timeval *tvp, struct thread *td)
{
- struct timeval atv, rtv, ttv;
- int error, timo;
+ struct timeval rtv;
+ sbintime_t asbt, precision, rsbt;
+ int error;
+ precision = 0; /* stupid gcc! */
if (tvp != NULL) {
- atv = *tvp;
- if (itimerfix(&atv))
+ rtv = *tvp;
+ if (rtv.tv_sec < 0 || rtv.tv_usec < 0 ||
+ rtv.tv_usec >= 1000000)
return (EINVAL);
- getmicrouptime(&rtv);
- timevaladd(&atv, &rtv);
- } else {
- atv.tv_sec = 0;
- atv.tv_usec = 0;
- }
-
- timo = 0;
+ if (!timevalisset(&rtv))
+ asbt = 0;
+ else if (rtv.tv_sec <= INT32_MAX) {
+ rsbt = tvtosbt(rtv);
+ precision = rsbt;
+ precision >>= tc_precexp;
+ if (TIMESEL(&asbt, rsbt))
+ asbt += tc_tick_sbt;
+ if (asbt <= SBT_MAX - rsbt)
+ asbt += rsbt;
+ else
+ asbt = -1;
+ } else
+ asbt = -1;
+ } else
+ asbt = -1;
seltdinit(td);
/*
* Iterate until the timeout expires or the socket becomes ready.
@@ -1635,22 +1765,11 @@ selsocket(struct socket *so, int events, struct timeval *tvp, struct thread *td)
/* error here is actually the ready events. */
if (error)
return (0);
- if (atv.tv_sec || atv.tv_usec) {
- getmicrouptime(&rtv);
- if (timevalcmp(&rtv, &atv, >=)) {
- seltdclear(td);
- return (EWOULDBLOCK);
- }
- ttv = atv;
- timevalsub(&ttv, &rtv);
- timo = ttv.tv_sec > 24 * 60 * 60 ?
- 24 * 60 * 60 * hz : tvtohz(&ttv);
- }
- error = seltdwait(td, timo);
- seltdclear(td);
+ error = seltdwait(td, asbt, precision);
if (error)
break;
}
+ seltdclear(td);
/* XXX Duplicates ncp/smb behavior. */
if (error == ERESTART)
error = 0;
@@ -1682,11 +1801,16 @@ static void
selfdfree(struct seltd *stp, struct selfd *sfp)
{
STAILQ_REMOVE(&stp->st_selq, sfp, selfd, sf_link);
- mtx_lock(sfp->sf_mtx);
- if (sfp->sf_si)
- TAILQ_REMOVE(&sfp->sf_si->si_tdlist, sfp, sf_threads);
- mtx_unlock(sfp->sf_mtx);
- uma_zfree(selfd_zone, sfp);
+ if (sfp->sf_si != NULL) {
+ mtx_lock(sfp->sf_mtx);
+ if (sfp->sf_si != NULL) {
+ TAILQ_REMOVE(&sfp->sf_si->si_tdlist, sfp, sf_threads);
+ refcount_release(&sfp->sf_refs);
+ }
+ mtx_unlock(sfp->sf_mtx);
+ }
+ if (refcount_release(&sfp->sf_refs))
+ uma_zfree(selfd_zone, sfp);
}
/* Drain the waiters tied to all the selfd belonging the specified selinfo. */
@@ -1742,6 +1866,7 @@ selrecord(selector, sip)
*/
sfp->sf_si = sip;
sfp->sf_mtx = mtxp;
+ refcount_init(&sfp->sf_refs, 2);
STAILQ_INSERT_TAIL(&stp->st_selq, sfp, sf_link);
/*
* Now that we've locked the sip, check for initialization.
@@ -1806,6 +1931,8 @@ doselwakeup(sip, pri)
stp->st_flags |= SELTD_PENDING;
cv_broadcastpri(&stp->st_wait, pri);
mtx_unlock(&stp->st_mtx);
+ if (refcount_release(&sfp->sf_refs))
+ uma_zfree(selfd_zone, sfp);
}
mtx_unlock(sip->si_mtx);
}
@@ -1826,7 +1953,7 @@ out:
}
static int
-seltdwait(struct thread *td, int timo)
+seltdwait(struct thread *td, sbintime_t sbt, sbintime_t precision)
{
struct seltd *stp;
int error;
@@ -1845,8 +1972,11 @@ seltdwait(struct thread *td, int timo)
mtx_unlock(&stp->st_mtx);
return (0);
}
- if (timo > 0)
- error = cv_timedwait_sig(&stp->st_wait, &stp->st_mtx, timo);
+ if (sbt == 0)
+ error = EWOULDBLOCK;
+ else if (sbt != -1)
+ error = cv_timedwait_sig_sbt(&stp->st_wait, &stp->st_mtx,
+ sbt, precision, C_ABSOLUTE);
else
error = cv_wait_sig(&stp->st_wait, &stp->st_mtx);
mtx_unlock(&stp->st_mtx);
@@ -1897,6 +2027,24 @@ selectinit(void *dummy __unused)
NULL, NULL, UMA_ALIGN_PTR, 0);
mtxpool_select = mtx_pool_create("select mtxpool", 128, MTX_DEF);
}
+
+#ifndef __rtems__
+/*
+ * Set up a syscall return value that follows the convention specified for
+ * posix_* functions.
+ */
+int
+kern_posix_error(struct thread *td, int error)
+{
+
+ if (error <= 0)
+ return (error);
+ td->td_errno = error;
+ td->td_pflags |= TDP_NERRNO;
+ td->td_retval[0] = error;
+ return (0);
+}
+#endif /* __rtems__ */
#ifdef __rtems__
#include <machine/rtems-bsd-thread.h>