1
0
mirror of https://git.FreeBSD.org/src.git synced 2025-01-09 13:42:56 +00:00

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
This commit is contained in:
Davide Italiano 2013-03-04 16:55:16 +00:00
parent cf5e4fe6bb
commit 40e794ab19
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=247804

View File

@ -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;