diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -859,14 +859,24 @@ { struct kq_timer_cb_data *kc; unsigned int old __unused; + bool pending; kc = kn->kn_ptr.p_v; - callout_drain(&kc->c); - if ((kc->flags & KQ_TIMER_CB_ENQUEUED) != 0) { + do { + callout_drain(&kc->c); + + /* + * kqtimer_proc_continue() might have rescheduled this callout. + * Double-check, using the process mutex as an interlock. + */ PROC_LOCK(kc->p); - TAILQ_REMOVE(&kc->p->p_kqtim_stop, kc, link); + if ((kc->flags & KQ_TIMER_CB_ENQUEUED) != 0) { + kc->flags &= ~KQ_TIMER_CB_ENQUEUED; + TAILQ_REMOVE(&kc->p->p_kqtim_stop, kc, link); + } + pending = callout_pending(&kc->c); PROC_UNLOCK(kc->p); - } + } while (pending); free(kc, M_KQUEUE); old = atomic_fetchadd_int(&kq_ncallouts, -1); KASSERT(old > 0, ("Number of callouts cannot become negative"));