release processing KN only when kq_scan has >0 max events. Because calling kevent with =0 max events doesn't mean all events are processed. This results in a subtle race of pre-releasing unprocessed knotes.
This commit is contained in:
parent
d535232e92
commit
61067bc214
@ -2044,6 +2044,7 @@ kqueue_register(struct kqueue *kq, struct kevq *kevq, struct kevent *kev, struct
|
||||
KQ_UNLOCK(kq);
|
||||
|
||||
knote_drop(kn, td);
|
||||
CTR3(KTR_KQ, "kqueue_register: kq %p deleted kn %p, fd %d", kq, kn, kev->ident);
|
||||
goto done;
|
||||
}
|
||||
|
||||
@ -3068,11 +3069,6 @@ kqueue_scan(struct kevq *kevq, int maxevents, struct kevent_copyops *k_ops,
|
||||
error = 0;
|
||||
haskqglobal = 0;
|
||||
|
||||
KEVQ_LOCK(kevq);
|
||||
/* release processing knotes first */
|
||||
kevq_rel_proc_kn(kevq);
|
||||
KEVQ_UNLOCK(kevq);
|
||||
|
||||
// it's important that this is done before activate
|
||||
if (maxevents == 0)
|
||||
goto done_nl;
|
||||
@ -3082,6 +3078,11 @@ kqueue_scan(struct kevq *kevq, int maxevents, struct kevent_copyops *k_ops,
|
||||
kevq_activate(kevq, td);
|
||||
}
|
||||
|
||||
KEVQ_LOCK(kevq);
|
||||
/* release processing knotes first */
|
||||
kevq_rel_proc_kn(kevq);
|
||||
KEVQ_UNLOCK(kevq);
|
||||
|
||||
/* adjust max events according to the target frequency */
|
||||
if ((kq->kq_flags & KQ_FLAG_MULTI) && kq->kq_tfreq > 0 && kevq->kevq_avg_lat > 0) {
|
||||
/* expected events per syscall
|
||||
@ -4199,7 +4200,7 @@ knote_activate(struct knote *kn)
|
||||
|
||||
KQ_NOTOWNED(kq);
|
||||
|
||||
CTR2(KTR_KQ, "knote_activate: kn %p, flags %d", kn, kn->kn_status);
|
||||
CTR3(KTR_KQ, "knote_activate: kn %p, fd %d, flags %d", kn, kn->kn_id, kn->kn_status);
|
||||
KN_FLUX_NOTOWNED(kn);
|
||||
KASSERT(kn_in_flux(kn), ("knote %p not in flux", kn));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user