Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_event.c
Show First 20 Lines • Show All 670 Lines • ▼ Show 20 Lines | #endif | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
return (-1); | return (-1); | ||||
} | } | ||||
struct kq_timer_cb_data { | struct kq_timer_cb_data { | ||||
struct callout c; | struct callout c; | ||||
struct proc *p; | |||||
struct knote *kn; | |||||
int cpuid; | |||||
TAILQ_ENTRY(kq_timer_cb_data) link; | |||||
sbintime_t next; /* next timer event fires at */ | sbintime_t next; /* next timer event fires at */ | ||||
sbintime_t to; /* precalculated timer period, 0 for abs */ | sbintime_t to; /* precalculated timer period, 0 for abs */ | ||||
}; | }; | ||||
static void | static void | ||||
kqtimer_sched_callout(struct kq_timer_cb_data *kc) | |||||
{ | |||||
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kc->kn, | |||||
kc->cpuid, C_ABSOLUTE); | |||||
} | |||||
void | |||||
kqtimer_proc_continue(struct proc *p) | |||||
markj: I would use "continue" instead of the past tense "continued". | |||||
{ | |||||
struct kq_timer_cb_data *kc, *kc1; | |||||
struct bintime bt; | |||||
sbintime_t now; | |||||
PROC_LOCK_ASSERT(p, MA_OWNED); | |||||
getboottimebin(&bt); | |||||
now = bttosbt(bt); | |||||
Done Inline ActionsWhy not sbinuptime()? markj: Why not sbinuptime()? | |||||
Done Inline Actionssbinuptime() returns relative time since boot, while getboottimebin() provides absolute time. Timers are set in abs time, and I need it there. kib: sbinuptime() returns relative time since boot, while getboottimebin() provides absolute time. | |||||
TAILQ_FOREACH_SAFE(kc, &p->p_kqtim_stop, link, kc1) { | |||||
TAILQ_REMOVE(&p->p_kqtim_stop, kc, link); | |||||
if (kc->next <= now) | |||||
filt_timerexpire(kc->kn); | |||||
else | |||||
kqtimer_sched_callout(kc); | |||||
} | |||||
} | |||||
static void | |||||
filt_timerexpire(void *knx) | filt_timerexpire(void *knx) | ||||
{ | { | ||||
struct knote *kn; | struct knote *kn; | ||||
struct kq_timer_cb_data *kc; | struct kq_timer_cb_data *kc; | ||||
struct proc *p; | |||||
sbintime_t now; | |||||
kn = knx; | kn = knx; | ||||
kc = kn->kn_ptr.p_v; | |||||
if ((kn->kn_flags & EV_ONESHOT) != 0 || kc->to == 0) { | |||||
kn->kn_data++; | kn->kn_data++; | ||||
KNOTE_ACTIVATE(kn, 0); | |||||
return; | |||||
} | |||||
for (now = sbinuptime(); kc->next <= now; kc->next += kc->to) | |||||
kn->kn_data++; | |||||
KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */ | KNOTE_ACTIVATE(kn, 0); /* XXX - handle locking */ | ||||
if ((kn->kn_flags & EV_ONESHOT) != 0) | /* | ||||
* Initial check for stopped kc->p is racy. It is fine to | |||||
* miss the set of the stop flags, at worst we would schedule | |||||
* one more callout. On the other hand, it is not fine to not | |||||
* schedule when we we missed clearing of the flags, we | |||||
* recheck them under the lock and observe consistent state. | |||||
*/ | |||||
p = kc->p; | |||||
if (P_SHOULDSTOP(p) || P_KILLED(p)) { | |||||
PROC_LOCK(p); | |||||
if (P_SHOULDSTOP(p) || P_KILLED(p)) { | |||||
TAILQ_INSERT_TAIL(&p->p_kqtim_stop, kc, link); | |||||
PROC_UNLOCK(p); | |||||
return; | return; | ||||
kc = kn->kn_ptr.p_v; | |||||
if (kc->to == 0) | |||||
return; | |||||
kc->next += kc->to; | |||||
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn, | |||||
PCPU_GET(cpuid), C_ABSOLUTE); | |||||
} | } | ||||
Done Inline ActionsConsider using a local variable for kc->p. markj: Consider using a local variable for `kc->p`. | |||||
PROC_UNLOCK(p); | |||||
} | |||||
kqtimer_sched_callout(kc); | |||||
} | |||||
/* | /* | ||||
* data contains amount of time to sleep | * data contains amount of time to sleep | ||||
*/ | */ | ||||
static int | static int | ||||
filt_timervalidate(struct knote *kn, sbintime_t *to) | filt_timervalidate(struct knote *kn, sbintime_t *to) | ||||
{ | { | ||||
struct bintime bt; | struct bintime bt; | ||||
Show All 38 Lines | do { | ||||
if (ncallouts >= kq_calloutmax) | if (ncallouts >= kq_calloutmax) | ||||
return (ENOMEM); | return (ENOMEM); | ||||
} while (!atomic_cmpset_int(&kq_ncallouts, ncallouts, ncallouts + 1)); | } while (!atomic_cmpset_int(&kq_ncallouts, ncallouts, ncallouts + 1)); | ||||
if ((kn->kn_sfflags & NOTE_ABSTIME) == 0) | if ((kn->kn_sfflags & NOTE_ABSTIME) == 0) | ||||
kn->kn_flags |= EV_CLEAR; /* automatically set */ | kn->kn_flags |= EV_CLEAR; /* automatically set */ | ||||
kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */ | kn->kn_status &= ~KN_DETACHED; /* knlist_add clears it */ | ||||
kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK); | kn->kn_ptr.p_v = kc = malloc(sizeof(*kc), M_KQUEUE, M_WAITOK); | ||||
kc->kn = kn; | |||||
kc->p = curproc; | |||||
kc->cpuid = PCPU_GET(cpuid); | |||||
callout_init(&kc->c, 1); | callout_init(&kc->c, 1); | ||||
filt_timerstart(kn, to); | filt_timerstart(kn, to); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
filt_timerstart(struct knote *kn, sbintime_t to) | filt_timerstart(struct knote *kn, sbintime_t to) | ||||
{ | { | ||||
struct kq_timer_cb_data *kc; | struct kq_timer_cb_data *kc; | ||||
kc = kn->kn_ptr.p_v; | kc = kn->kn_ptr.p_v; | ||||
if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) { | if ((kn->kn_sfflags & NOTE_ABSTIME) != 0) { | ||||
kc->next = to; | kc->next = to; | ||||
kc->to = 0; | kc->to = 0; | ||||
} else { | } else { | ||||
kc->next = to + sbinuptime(); | kc->next = to + sbinuptime(); | ||||
kc->to = to; | kc->to = to; | ||||
} | } | ||||
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kn, | kqtimer_sched_callout(kc); | ||||
PCPU_GET(cpuid), C_ABSOLUTE); | |||||
} | } | ||||
static void | static void | ||||
filt_timerdetach(struct knote *kn) | filt_timerdetach(struct knote *kn) | ||||
{ | { | ||||
struct kq_timer_cb_data *kc; | struct kq_timer_cb_data *kc; | ||||
unsigned int old __unused; | unsigned int old __unused; | ||||
▲ Show 20 Lines • Show All 1,946 Lines • Show Last 20 Lines |
I would use "continue" instead of the past tense "continued".