diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2016-10-07 15:10:20 +0200 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2017-01-10 09:53:31 +0100 |
commit | c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f (patch) | |
tree | ad4f2519067709f00ab98b3c591186c26dc3a21f /freebsd/sys/kern/sys_generic.c | |
parent | userspace-header-gen.py: Simplify program ports (diff) | |
download | rtems-libbsd-c40e45b75eb76d79a05c7fa85c1fa9b5c728a12f.tar.bz2 |
Update to FreeBSD head 2016-08-23
Git mirror commit 9fe7c416e6abb28b1398fd3e5687099846800cfd.
Diffstat (limited to 'freebsd/sys/kern/sys_generic.c')
-rw-r--r-- | freebsd/sys/kern/sys_generic.c | 494 |
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> |