Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_event.c
Show First 20 Lines • Show All 674 Lines • ▼ Show 20 Lines | #endif | ||||
return (-1); | return (-1); | ||||
} | } | ||||
struct kq_timer_cb_data { | struct kq_timer_cb_data { | ||||
struct callout c; | struct callout c; | ||||
struct proc *p; | struct proc *p; | ||||
struct knote *kn; | struct knote *kn; | ||||
int cpuid; | int cpuid; | ||||
int flags; | |||||
TAILQ_ENTRY(kq_timer_cb_data) link; | 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 */ | ||||
}; | }; | ||||
#define KQ_TIMER_CB_ENQUEUED 0x01 | |||||
static void | static void | ||||
kqtimer_sched_callout(struct kq_timer_cb_data *kc) | kqtimer_sched_callout(struct kq_timer_cb_data *kc) | ||||
{ | { | ||||
callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kc->kn, | callout_reset_sbt_on(&kc->c, kc->next, 0, filt_timerexpire, kc->kn, | ||||
kc->cpuid, C_ABSOLUTE); | kc->cpuid, C_ABSOLUTE); | ||||
} | } | ||||
void | void | ||||
kqtimer_proc_continue(struct proc *p) | kqtimer_proc_continue(struct proc *p) | ||||
{ | { | ||||
struct kq_timer_cb_data *kc, *kc1; | struct kq_timer_cb_data *kc, *kc1; | ||||
struct bintime bt; | struct bintime bt; | ||||
sbintime_t now; | sbintime_t now; | ||||
PROC_LOCK_ASSERT(p, MA_OWNED); | PROC_LOCK_ASSERT(p, MA_OWNED); | ||||
getboottimebin(&bt); | getboottimebin(&bt); | ||||
now = bttosbt(bt); | now = bttosbt(bt); | ||||
TAILQ_FOREACH_SAFE(kc, &p->p_kqtim_stop, link, kc1) { | TAILQ_FOREACH_SAFE(kc, &p->p_kqtim_stop, link, kc1) { | ||||
TAILQ_REMOVE(&p->p_kqtim_stop, kc, link); | TAILQ_REMOVE(&p->p_kqtim_stop, kc, link); | ||||
kc->flags &= ~KQ_TIMER_CB_ENQUEUED; | |||||
if (kc->next <= now) | if (kc->next <= now) | ||||
filt_timerexpire_l(kc->kn, true); | filt_timerexpire_l(kc->kn, true); | ||||
else | else | ||||
kqtimer_sched_callout(kc); | kqtimer_sched_callout(kc); | ||||
} | } | ||||
} | } | ||||
static void | static void | ||||
Show All 31 Lines | filt_timerexpire_l(struct knote *kn, bool proc_locked) | ||||
* schedule when we we missed clearing of the flags, we | * schedule when we we missed clearing of the flags, we | ||||
* recheck them under the lock and observe consistent state. | * recheck them under the lock and observe consistent state. | ||||
*/ | */ | ||||
p = kc->p; | p = kc->p; | ||||
if (P_SHOULDSTOP(p) || P_KILLED(p)) { | if (P_SHOULDSTOP(p) || P_KILLED(p)) { | ||||
if (!proc_locked) | if (!proc_locked) | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (P_SHOULDSTOP(p) || P_KILLED(p)) { | if (P_SHOULDSTOP(p) || P_KILLED(p)) { | ||||
if ((kc->flags & KQ_TIMER_CB_ENQUEUED) == 0) { | |||||
kc->flags |= KQ_TIMER_CB_ENQUEUED; | |||||
TAILQ_INSERT_TAIL(&p->p_kqtim_stop, kc, link); | TAILQ_INSERT_TAIL(&p->p_kqtim_stop, kc, link); | ||||
} | |||||
if (!proc_locked) | if (!proc_locked) | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
return; | return; | ||||
} | } | ||||
if (!proc_locked) | if (!proc_locked) | ||||
PROC_UNLOCK(p); | PROC_UNLOCK(p); | ||||
} | } | ||||
kqtimer_sched_callout(kc); | kqtimer_sched_callout(kc); | ||||
▲ Show 20 Lines • Show All 56 Lines • ▼ Show 20 Lines | filt_timerattach(struct knote *kn) | ||||
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->kn = kn; | ||||
kc->p = curproc; | kc->p = curproc; | ||||
kc->cpuid = PCPU_GET(cpuid); | kc->cpuid = PCPU_GET(cpuid); | ||||
kc->flags = 0; | |||||
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) | ||||
Show All 14 Lines | |||||
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; | ||||
kc = kn->kn_ptr.p_v; | kc = kn->kn_ptr.p_v; | ||||
callout_drain(&kc->c); | callout_drain(&kc->c); | ||||
if ((kc->flags & KQ_TIMER_CB_ENQUEUED) != 0) { | |||||
PROC_LOCK(kc->p); | |||||
TAILQ_REMOVE(&kc->p->p_kqtim_stop, kc, link); | |||||
kib: Do you need to clear the flag there as well? I think it is safer to do, even if the timer… | |||||
Done Inline Actionskc is freed immediately after this, so a thread holding a reference to it would perform a use-after-free. Do you see some need for reference counting? markj: `kc` is freed immediately after this, so a thread holding a reference to it would perform a use… | |||||
Not Done Inline ActionsNo, I misread the code. I do not think that so far kc's need refcounting. kib: No, I misread the code. I do not think that so far kc's need refcounting. | |||||
PROC_UNLOCK(kc->p); | |||||
} | |||||
free(kc, M_KQUEUE); | free(kc, M_KQUEUE); | ||||
old = atomic_fetchadd_int(&kq_ncallouts, -1); | old = atomic_fetchadd_int(&kq_ncallouts, -1); | ||||
KASSERT(old > 0, ("Number of callouts cannot become negative")); | KASSERT(old > 0, ("Number of callouts cannot become negative")); | ||||
kn->kn_status |= KN_DETACHED; /* knlist_remove sets it */ | kn->kn_status |= KN_DETACHED; /* knlist_remove sets it */ | ||||
} | } | ||||
static void | static void | ||||
filt_timertouch(struct knote *kn, struct kevent *kev, u_long type) | filt_timertouch(struct knote *kn, struct kevent *kev, u_long type) | ||||
▲ Show 20 Lines • Show All 1,936 Lines • Show Last 20 Lines |
Do you need to clear the flag there as well? I think it is safer to do, even if the timer cannot be reached by p_kqtim_stop iteration.