Bug #895 » select.diff
dfly/src/sys/kern/sys_generic.c 2007-12-25 13:10:32.000000000 +0100 | ||
---|---|---|
static MALLOC_DEFINE(M_SELECT, "select", "select() buffer");
|
||
MALLOC_DEFINE(M_IOV, "iov", "large iov's");
|
||
static int doselect(int nd, fd_set *in, fd_set *ou, fd_set *ex,
|
||
struct timeval *tv, int *res);
|
||
static int pollscan (struct proc *, struct pollfd *, u_int, int *);
|
||
static int selscan (struct proc *, fd_mask **, fd_mask **,
|
||
int, int *);
|
||
... | ... | |
int
|
||
sys_select(struct select_args *uap)
|
||
{
|
||
struct timeval ktv;
|
||
struct timeval *ktvp;
|
||
int error;
|
||
/*
|
||
* Get timeout if any.
|
||
*/
|
||
if (uap->tv != NULL) {
|
||
error = copyin(uap->tv, &ktv, sizeof (ktv));
|
||
if (error)
|
||
return (error);
|
||
error = itimerfix(&ktv);
|
||
if (error)
|
||
return (error);
|
||
ktvp = &ktv;
|
||
} else {
|
||
ktvp = NULL;
|
||
}
|
||
/*
|
||
* Do real work.
|
||
*/
|
||
error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktvp,
|
||
&uap->sysmsg_result);
|
||
/*
|
||
* XXX write back updated timeout value to userland if any.
|
||
*/
|
||
return (error);
|
||
}
|
||
/*
|
||
* Pselect system call.
|
||
*/
|
||
int
|
||
sys_pselect(struct pselect_args *uap)
|
||
{
|
||
struct timespec kts;
|
||
struct timeval ktv;
|
||
struct timeval *ktvp;
|
||
sigset_t sigmask;
|
||
sigset_t osigmask;
|
||
int error;
|
||
/*
|
||
* Get timeout if any and convert it.
|
||
* Round up during conversion to avoid timeout going off early.
|
||
*/
|
||
if (uap->ts != NULL) {
|
||
error = copyin(uap->ts, &kts, sizeof (kts));
|
||
if (error)
|
||
return (error);
|
||
ktv.tv_sec = kts.tv_sec;
|
||
ktv.tv_usec = (kts.tv_nsec + 999) / 1000;
|
||
error = itimerfix(&ktv);
|
||
if (error)
|
||
return (error);
|
||
ktvp = &ktv;
|
||
} else {
|
||
ktvp = NULL;
|
||
}
|
||
/*
|
||
* Install temporary signal mask if any.
|
||
*/
|
||
if (uap->sigmask != NULL) {
|
||
error = copyin(uap->sigmask, &sigmask, sizeof(sigmask));
|
||
if (error)
|
||
return (error);
|
||
(void) kern_sigprocmask(SIG_SETMASK, &sigmask, &osigmask);
|
||
}
|
||
/*
|
||
* Do real job.
|
||
*/
|
||
error = doselect(uap->nd, uap->in, uap->ou, uap->ex, ktvp,
|
||
&uap->sysmsg_result);
|
||
/*
|
||
* Restore previous signal mask if necessary.
|
||
*/
|
||
if (uap->sigmask != NULL) {
|
||
(void) kern_sigprocmask(SIG_SETMASK, &osigmask, NULL);
|
||
}
|
||
return (error);
|
||
}
|
||
/*
|
||
* Common code for sys_select() and sys_pselect().
|
||
*
|
||
* in, out and ex are userland pointers. tv must point to validated
|
||
* kernel-side timeout value or NULL for infinite timeout. res must
|
||
* point to syscall return value.
|
||
*/
|
||
static int
|
||
doselect(int nd, fd_set *in, fd_set *ou, fd_set *ex, struct timeval *tv,
|
||
int *res)
|
||
{
|
||
struct lwp *lp = curthread->td_lwp;
|
||
struct proc *p = curproc;
|
||
... | ... | |
int ncoll, error, timo;
|
||
u_int nbufbytes, ncpbytes, nfdbits;
|
||
if (uap->nd < 0)
|
||
if (nd < 0)
|
||
return (EINVAL);
|
||
if (uap->nd > p->p_fd->fd_nfiles)
|
||
uap->nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */
|
||
if (nd > p->p_fd->fd_nfiles)
|
||
nd = p->p_fd->fd_nfiles; /* forgiving; slightly wrong */
|
||
/*
|
||
* Allocate just enough bits for the non-null fd_sets. Use the
|
||
* preallocated auto buffer if possible.
|
||
*/
|
||
nfdbits = roundup(uap->nd, NFDBITS);
|
||
nfdbits = roundup(nd, NFDBITS);
|
||
ncpbytes = nfdbits / NBBY;
|
||
nbufbytes = 0;
|
||
if (uap->in != NULL)
|
||
if (in != NULL)
|
||
nbufbytes += 2 * ncpbytes;
|
||
if (uap->ou != NULL)
|
||
if (ou != NULL)
|
||
nbufbytes += 2 * ncpbytes;
|
||
if (uap->ex != NULL)
|
||
if (ex != NULL)
|
||
nbufbytes += 2 * ncpbytes;
|
||
if (nbufbytes <= sizeof s_selbits)
|
||
selbits = &s_selbits[0];
|
||
... | ... | |
sbp = selbits;
|
||
#define getbits(name, x) \
|
||
do { \
|
||
if (uap->name == NULL) \
|
||
if (name == NULL) \
|
||
ibits[x] = NULL; \
|
||
else { \
|
||
ibits[x] = sbp + nbufbytes / 2 / sizeof *sbp; \
|
||
obits[x] = sbp; \
|
||
sbp += ncpbytes / sizeof *sbp; \
|
||
error = copyin(uap->name, ibits[x], ncpbytes); \
|
||
error = copyin(name, ibits[x], ncpbytes); \
|
||
if (error != 0) \
|
||
goto done; \
|
||
} \
|
||
... | ... | |
if (nbufbytes != 0)
|
||
bzero(selbits, nbufbytes / 2);
|
||
if (uap->tv) {
|
||
error = copyin((caddr_t)uap->tv, (caddr_t)&atv,
|
||
sizeof (atv));
|
||
if (error)
|
||
goto done;
|
||
if (itimerfix(&atv)) {
|
||
error = EINVAL;
|
||
goto done;
|
||
}
|
||
if (tv != NULL) {
|
||
atv = *tv;
|
||
getmicrouptime(&rtv);
|
||
timevaladd(&atv, &rtv);
|
||
} else {
|
||
... | ... | |
retry:
|
||
ncoll = nselcoll;
|
||
lp->lwp_flag |= LWP_SELECT;
|
||
error = selscan(p, ibits, obits, uap->nd, &uap->sysmsg_result);
|
||
if (error || uap->sysmsg_result)
|
||
error = selscan(p, ibits, obits, nd, res);
|
||
if (error || *res)
|
||
goto done;
|
||
if (atv.tv_sec || atv.tv_usec) {
|
||
getmicrouptime(&rtv);
|
||
if (timevalcmp(&rtv, &atv, >=))
|
||
if (timevalcmp(&rtv, &atv, >=))
|
||
goto done;
|
||
ttv = atv;
|
||
timevalsub(&ttv, &rtv);
|
||
... | ... | |
if (error == EWOULDBLOCK)
|
||
error = 0;
|
||
#define putbits(name, x) \
|
||
if (uap->name && (error2 = copyout(obits[x], uap->name, ncpbytes))) \
|
||
if (name && (error2 = copyout(obits[x], name, ncpbytes))) \
|
||
error = error2;
|
||
if (error == 0) {
|
||
int error2;
|
dfly/src/sys/kern/syscalls.master 2007-12-25 13:10:32.000000000 +0100 | ||
---|---|---|
496 STD BSD { lwpid_t lwp_gettid(void); }
|
||
497 STD BSD { int lwp_kill(pid_t pid, lwpid_t tid, int signum); }
|
||
498 STD BSD { int lwp_rtprio(int function, pid_t pid, lwpid_t tid, struct rtprio *rtp); }
|
||
499 STD BSD { int pselect(int nd, fd_set *in, fd_set *ou, \
|
||
fd_set *ex, const struct timespec *ts, \
|
||
const sigset_t *sigmask); }
|
dfly/src/include/unistd.h 2007-12-25 13:10:32.000000000 +0100 | ||
---|---|---|
struct timeval; /* select(2) */
|
||
int select(int, fd_set * __restrict, fd_set * __restrict,
|
||
fd_set * __restrict, struct timeval * __restrict);
|
||
struct timespec; /* pselect(2) */
|
||
int pselect(int, fd_set * __restrict, fd_set * __restrict,
|
||
fd_set * __restrict, const struct timespec * __restrict,
|
||
const sigset_t * __restrict);
|
||
#endif
|
||
int setdomainname(const char *, int);
|
||
int setegid(gid_t);
|
dfly/src/sys/sys/select.h 2007-12-25 13:10:33.000000000 +0100 | ||
---|---|---|
struct timeval;
|
||
int select(int, fd_set * __restrict, fd_set * __restrict,
|
||
fd_set * __restrict, struct timeval * __restrict);
|
||
struct timespec;
|
||
int pselect(int, fd_set * __restrict, fd_set * __restrict,
|
||
fd_set * __restrict, const struct timespec * __restrict,
|
||
const sigset_t * __restrict);
|
||
#endif
|
||
__END_DECLS
|
||
dfly/src/lib/libthread_xu/thread/thr_syscalls.c 2007-12-25 13:10:33.000000000 +0100 | ||
---|---|---|
extern int __creat(const char *, mode_t);
|
||
extern int __pause(void);
|
||
extern int __pselect(int, fd_set *, fd_set *, fd_set *,
|
||
extern int __sys_pselect(int, fd_set *, fd_set *, fd_set *,
|
||
const struct timespec *, const sigset_t *);
|
||
extern unsigned __sleep(unsigned int);
|
||
extern int __system(const char *);
|
||
... | ... | |
}
|
||
__strong_reference(__poll, poll);
|
||
#if 0
|
||
int
|
||
_pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||
__pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
|
||
const struct timespec *timo, const sigset_t *mask)
|
||
{
|
||
struct pthread *curthread = tls_get_curthread();
|
||
... | ... | |
int ret;
|
||
oldcancel = _thr_cancel_enter(curthread);
|
||
ret = __pselect(count, rfds, wfds, efds, timo, mask);
|
||
ret = __sys_pselect(count, rfds, wfds, efds, timo, mask);
|
||
_thr_cancel_leave(curthread, oldcancel);
|
||
return (ret);
|
||
}
|
||
__strong_reference(_pselect, pselect);
|
||
#endif
|
||
__strong_reference(__pselect, pselect);
|
||
int
|
dfly/src/lib/libc_r/uthread/uthread_select.c 2007-12-25 13:18:13.000000000 +0100 | ||
---|---|---|
return ret;
|
||
}
|
||
int
|
||
pselect(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||
const struct timespec *timeout, const sigset_t *mask)
|
||
{
|
||
sigset_t omask;
|
||
struct timeval tv;
|
||
struct timeval *tvp;
|
||
int ret;
|
||
_thread_enter_cancellation_point();
|
||
if (timeout != NULL) {
|
||
tv.tv_sec = timeout->tv_sec;
|
||
tv.tv_usec = (timeout->tv_nsec + 999) / 1000;
|
||
tvp = &tv;
|
||
} else {
|
||
tvp = NULL;
|
||
}
|
||
/*
|
||
* XXX The masking/select/unmasking sequence below is not atomic. See
|
||
* man page.
|
||
*
|
||
* The Right Thing would be to mask/unmask signals kernel-side. We do
|
||
* this for single-threaded and libthread_xu processes but this is far
|
||
* from trivial for libc_r because select() is actually a poll()
|
||
* wrapper there and not using poll() would involve complex changes in
|
||
* the user thread scheduler. We're deprecating libc_r in favor of
|
||
* libthread_xu so the usefulness of such a change is questionable.
|
||
*/
|
||
if (mask != NULL)
|
||
(void) sigprocmask(SIG_SETMASK, mask, &omask);
|
||
ret = _select(numfds, readfds, writefds, exceptfds, tvp);
|
||
if (mask != NULL)
|
||
(void) sigprocmask(SIG_SETMASK, &omask, NULL);
|
||
_thread_leave_cancellation_point();
|
||
return ret;
|
||
}
|
dfly/src/lib/libc/sys/Makefile.inc 2007-12-25 13:10:33.000000000 +0100 | ||
---|---|---|
sigstack.2 sigsuspend.2 socket.2 socketpair.2 stat.2 statfs.2 \
|
||
swapon.2 symlink.2 sync.2 sysarch.2 syscall.2 syslink.2 \
|
||
truncate.2 tls.2 umask.2 umtx.2 undelete.2 \
|
||
unlink.2 utimes.2 upc_register.2 usched_set.2 uuidgen.2 vfork.2 wait.2 write.2
|
||
unlink.2 utimes.2 upc_register.2 usched_set.2 uuidgen.2 vfork.2 \
|
||
wait.2 write.2 pselect.2
|
||
.if !defined(NO_P1003_1B)
|
||
MAN+= sched_get_priority_max.2 sched_setparam.2 \
|
||
sched_setscheduler.2 sched_yield.2
|
dfly/src/lib/libc/sys/pselect.2 2007-12-25 13:13:39.000000000 +0100 | ||
---|---|---|
.\"
|
||
.\" Copyright 2002 Massachusetts Institute of Technology
|
||
.\"
|
||
.\" Permission to use, copy, modify, and distribute this software and
|
||
.\" its documentation for any purpose and without fee is hereby
|
||
.\" granted, provided that both the above copyright notice and this
|
||
.\" permission notice appear in all copies, that both the above
|
||
.\" copyright notice and this permission notice appear in all
|
||
.\" supporting documentation, and that the name of M.I.T. not be used
|
||
.\" in advertising or publicity pertaining to distribution of the
|
||
.\" software without specific, written prior permission. M.I.T. makes
|
||
.\" no representations about the suitability of this software for any
|
||
.\" purpose. It is provided "as is" without express or implied
|
||
.\" warranty.
|
||
.\"
|
||
.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
|
||
.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
|
||
.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||
.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
|
||
.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||
.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||
.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||
.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||
.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||
.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||
.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||
.\" SUCH DAMAGE.
|
||
.\"
|
||
.\" $FreeBSD: src/lib/libc/gen/pselect.3,v 1.4 2002/12/18 10:13:54 ru Exp $
|
||
.\"
|
||
.Dd December 24, 2007
|
||
.Dt PSELECT 2
|
||
.Os
|
||
.Sh NAME
|
||
.Nm pselect
|
||
.Nd synchronous I/O multiplexing a la POSIX.1g
|
||
.Sh LIBRARY
|
||
.Lb libc
|
||
.Sh SYNOPSIS
|
||
.In sys/select.h
|
||
.Ft int
|
||
.Fo pselect
|
||
.Fa "int nfds"
|
||
.Fa "fd_set * restrict readfds"
|
||
.Fa "fd_set * restrict writefds"
|
||
.Fa "fd_set * restrict exceptfds"
|
||
.Fa "const struct timespec * restrict timeout"
|
||
.Fa "const sigset_t * restrict newsigmask"
|
||
.Fc
|
||
.Sh DESCRIPTION
|
||
The
|
||
.Fn pselect
|
||
function was introduced by
|
||
.St -p1003.1g-2000
|
||
as a slightly stronger version of
|
||
.Xr select 2 .
|
||
The
|
||
.Fa nfds , readfds , writefds ,
|
||
and
|
||
.Fa exceptfds
|
||
arguments are all identical to the analogous arguments of
|
||
.Fn select .
|
||
The
|
||
.Fa timeout
|
||
argument in
|
||
.Fn pselect
|
||
points to a
|
||
.Vt "const struct timespec"
|
||
rather than the (modifiable)
|
||
.Vt "struct timeval"
|
||
used by
|
||
.Fn select ;
|
||
as in
|
||
.Fn select ,
|
||
a null pointer may be passed to indicate that
|
||
.Fn pselect
|
||
should wait indefinitely.
|
||
Finally,
|
||
.Fa newsigmask
|
||
specifies a signal mask which is set while waiting for input.
|
||
When
|
||
.Fn pselect
|
||
returns, the original signal mask is restored.
|
||
.Pp
|
||
See
|
||
.Xr select 2
|
||
for a more detailed discussion of the semantics of this interface, and
|
||
for macros used to manipulate the
|
||
.Vt "fd_set"
|
||
data type.
|
||
.Sh RETURN VALUES
|
||
The
|
||
.Fn pselect
|
||
function returns the same values and under the same conditions as
|
||
.Fn select .
|
||
.Sh ERRORS
|
||
The
|
||
.Fn pselect
|
||
function may fail for any of the reasons documented for
|
||
.Xr select 2
|
||
and (if a signal mask is provided)
|
||
.Xr sigprocmask 2 .
|
||
.Sh SEE ALSO
|
||
.Xr kqueue 2 ,
|
||
.Xr poll 2 ,
|
||
.Xr select 2 ,
|
||
.Xr sigprocmask 2
|
||
.Sh STANDARDS
|
||
The
|
||
.Fn pselect
|
||
function conforms to
|
||
.St -p1003.1-2001 .
|
||
.Sh BUGS
|
||
The
|
||
.Fn pselect
|
||
implementation in libc_r (user multi-threading) does not mask signals, calls
|
||
.Fn select ,
|
||
and restores the original signal mask atomically. A calling user thread
|
||
using
|
||
.Fn pselect
|
||
to block until either a signal occurs or some descriptor changes may therefore
|
||
block forever.
|
||
The
|
||
.Fn pselect
|
||
implementations in libthread_xu (kernel multi-threading) and libc
|
||
(single-threading) operate atomically and are therefore race-free.
|
||
.Sh HISTORY
|
||
The
|
||
.Fn pselect
|
||
function first appeared in
|
||
.Dx 1.11 .
|
||
.Sh AUTHORS
|
||
This manual page was originally written by
|
||
.An Garrett Wollman Aq wollman@FreeBSD.org
|
||
for FreeBSD and later modified for DragonFly.
|
dfly/src/lib/libbind/port_after.h 2007-12-25 13:11:50.000000000 +0100 | ||
---|---|---|
#include <inttypes.h>
|
||
#endif
|
||
#define NEED_PSELECT
|
||
#define HAVE_SA_LEN 1
|
||
#define HAVE_MINIMUM_IFREQ 1
|
||
#undef NEED_DAEMON
|