MFcalloutng:
Fix kern_select() and sys_poll() so that they can handle sub-tick precision for timeouts (in the same fashion it was done for nanosleep() in r247797). Sponsored by: Google Summer of Code 2012, iXsystems inc. Tested by: flo, marius, ian, markj, Fabian Keil
This commit is contained in:
parent
4601bab1fb
commit
cf5e4fe6bb
@ -103,7 +103,7 @@ static int dofilewrite(struct thread *, int, struct file *, struct uio *,
|
|||||||
off_t, int);
|
off_t, int);
|
||||||
static void doselwakeup(struct selinfo *, int);
|
static void doselwakeup(struct selinfo *, int);
|
||||||
static void seltdinit(struct thread *);
|
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 *);
|
static void seltdclear(struct thread *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -950,9 +950,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 s_selbits[howmany(2048, NFDBITS)];
|
||||||
fd_mask *ibits[3], *obits[3], *selbits, *sbp;
|
fd_mask *ibits[3], *obits[3], *selbits, *sbp;
|
||||||
struct timeval atv, rtv, ttv;
|
struct timeval rtv;
|
||||||
int error, lf, ndu, timo;
|
sbintime_t asbt, precision, rsbt;
|
||||||
u_int nbufbytes, ncpbytes, ncpubytes, nfdbits;
|
u_int nbufbytes, ncpbytes, ncpubytes, nfdbits;
|
||||||
|
int error, lf, ndu;
|
||||||
|
|
||||||
if (nd < 0)
|
if (nd < 0)
|
||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
@ -1042,35 +1043,29 @@ kern_select(struct thread *td, int nd, fd_set *fd_in, fd_set *fd_ou,
|
|||||||
if (nbufbytes != 0)
|
if (nbufbytes != 0)
|
||||||
bzero(selbits, nbufbytes / 2);
|
bzero(selbits, nbufbytes / 2);
|
||||||
|
|
||||||
|
precision = 0;
|
||||||
if (tvp != NULL) {
|
if (tvp != NULL) {
|
||||||
atv = *tvp;
|
rtv = *tvp;
|
||||||
if (itimerfix(&atv)) {
|
if (rtv.tv_sec < 0 || rtv.tv_usec < 0 ||
|
||||||
|
rtv.tv_usec >= 1000000) {
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
getmicrouptime(&rtv);
|
rsbt = tvtosbt(rtv);
|
||||||
timevaladd(&atv, &rtv);
|
precision = rsbt;
|
||||||
} else {
|
precision >>= tc_precexp;
|
||||||
atv.tv_sec = 0;
|
if (TIMESEL(&asbt, rsbt))
|
||||||
atv.tv_usec = 0;
|
asbt += tc_tick_sbt;
|
||||||
}
|
asbt += rsbt;
|
||||||
timo = 0;
|
} else
|
||||||
|
asbt = -1;
|
||||||
seltdinit(td);
|
seltdinit(td);
|
||||||
/* Iterate until the timeout expires or descriptors become ready. */
|
/* Iterate until the timeout expires or descriptors become ready. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
error = selscan(td, ibits, obits, nd);
|
error = selscan(td, ibits, obits, nd);
|
||||||
if (error || td->td_retval[0] != 0)
|
if (error || td->td_retval[0] != 0)
|
||||||
break;
|
break;
|
||||||
if (atv.tv_sec || atv.tv_usec) {
|
error = seltdwait(td, asbt, precision);
|
||||||
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);
|
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
error = selrescan(td, ibits, obits);
|
error = selrescan(td, ibits, obits);
|
||||||
@ -1278,9 +1273,9 @@ sys_poll(td, uap)
|
|||||||
{
|
{
|
||||||
struct pollfd *bits;
|
struct pollfd *bits;
|
||||||
struct pollfd smallbits[32];
|
struct pollfd smallbits[32];
|
||||||
struct timeval atv, rtv, ttv;
|
sbintime_t asbt, precision, rsbt;
|
||||||
int error, timo;
|
|
||||||
u_int nfds;
|
u_int nfds;
|
||||||
|
int error;
|
||||||
size_t ni;
|
size_t ni;
|
||||||
|
|
||||||
nfds = uap->nfds;
|
nfds = uap->nfds;
|
||||||
@ -1294,36 +1289,27 @@ sys_poll(td, uap)
|
|||||||
error = copyin(uap->fds, bits, ni);
|
error = copyin(uap->fds, bits, ni);
|
||||||
if (error)
|
if (error)
|
||||||
goto done;
|
goto done;
|
||||||
|
precision = 0;
|
||||||
if (uap->timeout != INFTIM) {
|
if (uap->timeout != INFTIM) {
|
||||||
atv.tv_sec = uap->timeout / 1000;
|
if (uap->timeout < 0) {
|
||||||
atv.tv_usec = (uap->timeout % 1000) * 1000;
|
|
||||||
if (itimerfix(&atv)) {
|
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
getmicrouptime(&rtv);
|
rsbt = SBT_1MS * uap->timeout;
|
||||||
timevaladd(&atv, &rtv);
|
precision = rsbt;
|
||||||
} else {
|
precision >>= tc_precexp;
|
||||||
atv.tv_sec = 0;
|
if (TIMESEL(&asbt, rsbt))
|
||||||
atv.tv_usec = 0;
|
asbt += tc_tick_sbt;
|
||||||
}
|
asbt += rsbt;
|
||||||
timo = 0;
|
} else
|
||||||
|
asbt = -1;
|
||||||
seltdinit(td);
|
seltdinit(td);
|
||||||
/* Iterate until the timeout expires or descriptors become ready. */
|
/* Iterate until the timeout expires or descriptors become ready. */
|
||||||
for (;;) {
|
for (;;) {
|
||||||
error = pollscan(td, bits, nfds);
|
error = pollscan(td, bits, nfds);
|
||||||
if (error || td->td_retval[0] != 0)
|
if (error || td->td_retval[0] != 0)
|
||||||
break;
|
break;
|
||||||
if (atv.tv_sec || atv.tv_usec) {
|
error = seltdwait(td, asbt, precision);
|
||||||
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);
|
|
||||||
if (error)
|
if (error)
|
||||||
break;
|
break;
|
||||||
error = pollrescan(td);
|
error = pollrescan(td);
|
||||||
@ -1667,7 +1653,7 @@ out:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
seltdwait(struct thread *td, int timo)
|
seltdwait(struct thread *td, sbintime_t sbt, sbintime_t precision)
|
||||||
{
|
{
|
||||||
struct seltd *stp;
|
struct seltd *stp;
|
||||||
int error;
|
int error;
|
||||||
@ -1686,8 +1672,11 @@ seltdwait(struct thread *td, int timo)
|
|||||||
mtx_unlock(&stp->st_mtx);
|
mtx_unlock(&stp->st_mtx);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
if (timo > 0)
|
if (sbt == 0)
|
||||||
error = cv_timedwait_sig(&stp->st_wait, &stp->st_mtx, timo);
|
error = EWOULDBLOCK;
|
||||||
|
else if (sbt != -1)
|
||||||
|
error = cv_timedwait_sig_sbt(&stp->st_wait, &stp->st_mtx,
|
||||||
|
sbt, precision, C_ABSOLUTE);
|
||||||
else
|
else
|
||||||
error = cv_wait_sig(&stp->st_wait, &stp->st_mtx);
|
error = cv_wait_sig(&stp->st_wait, &stp->st_mtx);
|
||||||
mtx_unlock(&stp->st_mtx);
|
mtx_unlock(&stp->st_mtx);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user