diff options
author | Davide Italiano <davide@FreeBSD.org> | 2013-03-04 16:55:16 +0000 |
---|---|---|
committer | Davide Italiano <davide@FreeBSD.org> | 2013-03-04 16:55:16 +0000 |
commit | 40e794ab19fb0c33b697878465b9a0936d203d1e (patch) | |
tree | a1cc456aac4c1f6cd7ca417811c7724b55728475 | |
parent | cf5e4fe6bb7b91ecf38a5d8e7231d064fa788e33 (diff) | |
download | src-40e794ab19fb0c33b697878465b9a0936d203d1e.tar.gz src-40e794ab19fb0c33b697878465b9a0936d203d1e.zip |
MFcalloutng:
- Rewrite kevent() timeout implementation to allow sub-tick precision.
- Make the interval timings for EVFILT_TIMER more accurate. This also
removes an hack introduced in r238424.
Sponsored by: Google Summer of Code 2012, iXsystems inc.
Tested by: flo, marius, ian, markj, Fabian Keil
Notes
Notes:
svn path=/head/; revision=247804
-rw-r--r-- | sys/kern/kern_event.c | 82 |
1 files changed, 29 insertions, 53 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 6a920ca6e50e..82db54e17b7a 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -517,39 +517,28 @@ knote_fork(struct knlist *list, int pid) * XXX: EVFILT_TIMER should perhaps live in kern_time.c beside the * interval timer support code. */ -static int -timertoticks(intptr_t data) +static __inline sbintime_t +timer2sbintime(intptr_t data) { - struct timeval tv; - int tticks; - - tv.tv_sec = data / 1000; - tv.tv_usec = (data % 1000) * 1000; - tticks = tvtohz(&tv); - return tticks; + return (SBT_1MS * data); } static void filt_timerexpire(void *knx) { - struct knote *kn = knx; struct callout *calloutp; + struct knote *kn; + kn = knx; kn->kn_data++; KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */ - /* - * timertoticks() uses tvtohz() which always adds 1 to allow - * for the time until the next clock interrupt being strictly - * less than 1 clock tick. We don't want that here since we - * want to appear to be in sync with the clock interrupt even - * when we're delayed. - */ if ((kn->kn_flags & EV_ONESHOT) != EV_ONESHOT) { calloutp = (struct callout *)kn->kn_hook; - callout_reset_curcpu(calloutp, timertoticks(kn->kn_sdata) - 1, - filt_timerexpire, kn); + callout_reset_sbt_on(calloutp, + timer2sbintime(kn->kn_sdata), 0 /* 1ms? */, + filt_timerexpire, kn, PCPU_GET(cpuid), 0); } } @@ -573,8 +562,9 @@ filt_timerattach(struct knote *kn) calloutp = malloc(sizeof(*calloutp), M_KQUEUE, M_WAITOK); callout_init(calloutp, CALLOUT_MPSAFE); kn->kn_hook = calloutp; - callout_reset_curcpu(calloutp, timertoticks(kn->kn_sdata), - filt_timerexpire, kn); + callout_reset_sbt_on(calloutp, + timer2sbintime(kn->kn_sdata), 0 /* 1ms? */, + filt_timerexpire, kn, PCPU_GET(cpuid), 0); return (0); } @@ -1319,10 +1309,9 @@ kqueue_scan(struct kqueue *kq, int maxevents, struct kevent_copyops *k_ops, const struct timespec *tsp, struct kevent *keva, struct thread *td) { struct kevent *kevp; - struct timeval atv, rtv, ttv; struct knote *kn, *marker; - int count, timeout, nkev, error, influx; - int haskqglobal, touch; + sbintime_t asbt, rsbt; + int count, error, haskqglobal, influx, nkev, touch; count = maxevents; nkev = 0; @@ -1332,24 +1321,23 @@ kqueue_scan(struct kqueue *kq, int maxevents, struct kevent_copyops *k_ops, if (maxevents == 0) goto done_nl; + rsbt = 0; if (tsp != NULL) { - TIMESPEC_TO_TIMEVAL(&atv, tsp); - if (itimerfix(&atv)) { + if (tsp->tv_sec < 0 || tsp->tv_nsec < 0 || + tsp->tv_nsec > 1000000000) { error = EINVAL; goto done_nl; } - if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) - timeout = -1; - else - timeout = atv.tv_sec > 24 * 60 * 60 ? - 24 * 60 * 60 * hz : tvtohz(&atv); - getmicrouptime(&rtv); - timevaladd(&atv, &rtv); - } else { - atv.tv_sec = 0; - atv.tv_usec = 0; - timeout = 0; - } + if (timespecisset(tsp)) { + rsbt = tstosbt(*tsp); + if (TIMESEL(&asbt, rsbt)) + asbt += tc_tick_sbt; + asbt += rsbt; + rsbt >>= tc_precexp; + } else + asbt = -1; + } else + asbt = 0; marker = knote_alloc(1); if (marker == NULL) { error = ENOMEM; @@ -1357,28 +1345,16 @@ kqueue_scan(struct kqueue *kq, int maxevents, struct kevent_copyops *k_ops, } marker->kn_status = KN_MARKER; KQ_LOCK(kq); - goto start; retry: - if (atv.tv_sec || atv.tv_usec) { - getmicrouptime(&rtv); - if (timevalcmp(&rtv, &atv, >=)) - goto done; - ttv = atv; - timevalsub(&ttv, &rtv); - timeout = ttv.tv_sec > 24 * 60 * 60 ? - 24 * 60 * 60 * hz : tvtohz(&ttv); - } - -start: kevp = keva; if (kq->kq_count == 0) { - if (timeout < 0) { + if (asbt == -1) { error = EWOULDBLOCK; } else { kq->kq_state |= KQ_SLEEP; - error = msleep(kq, &kq->kq_lock, PSOCK | PCATCH, - "kqread", timeout); + error = msleep_sbt(kq, &kq->kq_lock, PSOCK | PCATCH, + "kqread", asbt, rsbt, C_ABSOLUTE); } if (error == 0) goto retry; |