Changeset View
Standalone View
sys/kern/kern_event.c
| Show First 20 Lines • Show All 621 Lines • ▼ Show 20 Lines | SLIST_FOREACH(kn, &list->kl_list, kn_selnext) { | ||||||||||
| */ | */ | ||||||||||
| kev.ident = pid; | kev.ident = pid; | ||||||||||
| kev.filter = kn->kn_filter; | kev.filter = kn->kn_filter; | ||||||||||
| kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1; | kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1; | ||||||||||
| kev.fflags = kn->kn_sfflags; | kev.fflags = kn->kn_sfflags; | ||||||||||
| kev.data = kn->kn_id; /* parent */ | kev.data = kn->kn_id; /* parent */ | ||||||||||
| kev.udata = kn->kn_kevent.udata;/* preserve udata */ | kev.udata = kn->kn_kevent.udata;/* preserve udata */ | ||||||||||
| error = kqueue_register(kq, &kev, NULL, M_NOWAIT); | error = kqueue_register(kq, &kev, NULL, M_NOWAIT); | ||||||||||
| /* | |||||||||||
| * Serialize updates to the kn_kevent fields with threads | |||||||||||
kibUnsubmitted Done Inline Actions
kib: | |||||||||||
| * scanning the queue. | |||||||||||
| */ | |||||||||||
| list->kl_lock(list->kl_lockarg); | |||||||||||
| if (error) | if (error) | ||||||||||
| kn->kn_fflags |= NOTE_TRACKERR; | kn->kn_fflags |= NOTE_TRACKERR; | ||||||||||
Not Done Inline ActionsWht do we need the knote list locked for kn_fflags modifications? kib: Wht do we need the knote list locked for kn_fflags modifications? | |||||||||||
Done Inline ActionsIsn't kn->kn_event effectively serialized by the knote list lock? I started reading the case in the kqueue_scan() loop where we handle EV_CLEAR and I don't see how this update is serialized against those stores. markj: Isn't kn->kn_event effectively serialized by the knote list lock? I started reading the case in… | |||||||||||
Not Done Inline ActionsYou mean, that practically all modifications of kn_kevent are happen to occur under the kn list lock? Sometimes the lock used as kn list lock is rw (e.g. for vnodes), and updates to kn_kevent can occur while lock is taken in shared mode. E.g. for vnode reads. This should not invalidate the change above, since kn_lock() should be always exclusive in such cases, but it is not obvious to me that the statement about kn_kevent serialization is true. Anyway, please add a comment. kib: You mean, that practically all modifications of kn_kevent are happen to occur under the kn list… | |||||||||||
Done Inline Actions
Hmm, but the f_event implementations for vnodes (filt_vfsread(), filt_vfswrite(), filt_vfsvnode()) all acquire the vnode interlock internally, so they serialize with each other, and vfs_knllock() acquires the exclusive vnode lock, so I think updates are still serialized. Or am I missing something? markj: > Sometimes the lock used as kn list lock is rw (e.g. for vnodes), and updates to kn_kevent can… | |||||||||||
Not Done Inline ActionsYes, interlock there helps, using the common part of exclusive vnode lock vs. shared vnode lock + interlock. What I tried to say is that kn list lock probably not should be considered as kn_kevent lock due to this detail, in general. kib: Yes, interlock there helps, using the common part of exclusive vnode lock vs. shared vnode lock… | |||||||||||
| if (kn->kn_fop->f_event(kn, NOTE_FORK)) | if (kn->kn_fop->f_event(kn, NOTE_FORK)) { | ||||||||||
| KNOTE_ACTIVATE(kn, 0); | |||||||||||
| list->kl_lock(list->kl_lockarg); | |||||||||||
| KQ_LOCK(kq); | KQ_LOCK(kq); | ||||||||||
| KNOTE_ACTIVATE(kn, 1); | |||||||||||
| } else { | |||||||||||
| KQ_LOCK(kq); | |||||||||||
| } | |||||||||||
| kn_leave_flux(kn); | kn_leave_flux(kn); | ||||||||||
| KQ_UNLOCK_FLUX(kq); | KQ_UNLOCK_FLUX(kq); | ||||||||||
| } | } | ||||||||||
| } | } | ||||||||||
| int | int | ||||||||||
| filt_jailattach(struct knote *kn) | filt_jailattach(struct knote *kn) | ||||||||||
| { | { | ||||||||||
| ▲ Show 20 Lines • Show All 2,726 Lines • Show Last 20 Lines | |||||||||||