summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authordavide <davide@FreeBSD.org>2013-03-04 16:41:27 +0000
committerdavide <davide@FreeBSD.org>2013-03-04 16:41:27 +0000
commit473ef72351629f04c8d9190784bbc0ca6a13847e (patch)
tree8d6fe5f8929fb0b74461daf5e2d62437f8250f71
parent0aca596713f4cc3791a44511f7f609d1bedeb766 (diff)
downloadFreeBSD-src-473ef72351629f04c8d9190784bbc0ca6a13847e.zip
FreeBSD-src-473ef72351629f04c8d9190784bbc0ca6a13847e.tar.gz
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
-rw-r--r--sys/kern/sys_generic.c83
1 files changed, 36 insertions, 47 deletions
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 39f33f3..3893515 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -103,7 +103,7 @@ static int dofilewrite(struct thread *, int, struct file *, struct uio *,
off_t, int);
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 *);
/*
@@ -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 *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);
@@ -1042,35 +1043,29 @@ 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;
+ rsbt = tvtosbt(rtv);
+ precision = rsbt;
+ precision >>= tc_precexp;
+ if (TIMESEL(&asbt, rsbt))
+ asbt += tc_tick_sbt;
+ asbt += rsbt;
+ } 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);
@@ -1278,9 +1273,9 @@ sys_poll(td, uap)
{
struct pollfd *bits;
struct pollfd smallbits[32];
- struct timeval atv, rtv, ttv;
- int error, timo;
+ sbintime_t asbt, precision, rsbt;
u_int nfds;
+ int error;
size_t ni;
nfds = uap->nfds;
@@ -1294,36 +1289,27 @@ sys_poll(td, uap)
error = copyin(uap->fds, bits, ni);
if (error)
goto done;
+ precision = 0;
if (uap->timeout != INFTIM) {
- atv.tv_sec = uap->timeout / 1000;
- atv.tv_usec = (uap->timeout % 1000) * 1000;
- if (itimerfix(&atv)) {
+ if (uap->timeout < 0) {
error = EINVAL;
goto done;
}
- getmicrouptime(&rtv);
- timevaladd(&atv, &rtv);
- } else {
- atv.tv_sec = 0;
- atv.tv_usec = 0;
- }
- timo = 0;
+ rsbt = SBT_1MS * uap->timeout;
+ precision = rsbt;
+ precision >>= tc_precexp;
+ if (TIMESEL(&asbt, rsbt))
+ asbt += tc_tick_sbt;
+ asbt += rsbt;
+ } else
+ asbt = -1;
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, asbt, precision);
if (error)
break;
error = pollrescan(td);
@@ -1667,7 +1653,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;
@@ -1686,8 +1672,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);
OpenPOWER on IntegriCloud