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:
parent
cf5e4fe6bb
commit
40e794ab19
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=247804
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user