diff options
-rw-r--r-- | sys/kern/kern_event.c | 82 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 6 | ||||
-rw-r--r-- | sys/sys/event.h | 1 |
3 files changed, 70 insertions, 19 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 36331be..ab3cbb7 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -403,30 +403,82 @@ filt_proc(struct knote *kn, long hint) return (1); } - /* - * process forked, and user wants to track the new process, - * so attach a new knote to it, and immediately report an - * event with the parent's pid. - */ - if ((event == NOTE_FORK) && (kn->kn_sfflags & NOTE_TRACK)) { - struct kevent kev; - int error; + return (kn->kn_fflags != 0); +} + +/* + * Called when the process forked. It mostly does the same as the + * knote(), activating all knotes registered to be activated when the + * process forked. Additionally, for each knote attached to the + * parent, check whether user wants to track the new process. If so + * attach a new knote to it, and immediately report an event with the + * child's pid. + */ +void +knote_fork(struct knlist *list, int pid) +{ + struct kqueue *kq; + struct knote *kn; + struct kevent kev; + int error; + + if (list == NULL) + return; + list->kl_lock(list->kl_lockarg); + + SLIST_FOREACH(kn, &list->kl_list, kn_selnext) { + if ((kn->kn_status & KN_INFLUX) == KN_INFLUX) + continue; + kq = kn->kn_kq; + KQ_LOCK(kq); + if ((kn->kn_status & KN_INFLUX) == KN_INFLUX) { + KQ_UNLOCK(kq); + continue; + } + + /* + * The same as knote(), activate the event. + */ + if ((kn->kn_sfflags & NOTE_TRACK) == 0) { + kn->kn_status |= KN_HASKQLOCK; + if (kn->kn_fop->f_event(kn, NOTE_FORK | pid)) + KNOTE_ACTIVATE(kn, 1); + kn->kn_status &= ~KN_HASKQLOCK; + KQ_UNLOCK(kq); + continue; + } /* - * register knote with new process. + * The NOTE_TRACK case. In addition to the activation + * of the event, we need to register new event to + * track the child. Drop the locks in preparation for + * the call to kqueue_register(). */ - kev.ident = hint & NOTE_PDATAMASK; /* pid */ + kn->kn_status |= KN_INFLUX; + KQ_UNLOCK(kq); + list->kl_unlock(list->kl_lockarg); + + /* + * Activate existing knote and register a knote with + * new process. + */ + kev.ident = pid; kev.filter = kn->kn_filter; kev.flags = kn->kn_flags | EV_ADD | EV_ENABLE | EV_FLAG1; kev.fflags = kn->kn_sfflags; - kev.data = kn->kn_id; /* parent */ - kev.udata = kn->kn_kevent.udata; /* preserve udata */ - error = kqueue_register(kn->kn_kq, &kev, NULL, 0); + kev.data = kn->kn_id; /* parent */ + kev.udata = kn->kn_kevent.udata;/* preserve udata */ + error = kqueue_register(kq, &kev, NULL, 0); + if (kn->kn_fop->f_event(kn, NOTE_FORK | pid)) + KNOTE_ACTIVATE(kn, 0); if (error) kn->kn_fflags |= NOTE_TRACKERR; + KQ_LOCK(kq); + kn->kn_status &= ~KN_INFLUX; + KQ_UNLOCK_FLUX(kq); + list->kl_lock(list->kl_lockarg); } - - return (kn->kn_fflags != 0); + list->kl_unlock(list->kl_lockarg); } static int diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 8387532..6da07d4 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -728,14 +728,12 @@ again: */ PROC_LOCK(p1); _PRELE(p1); + PROC_UNLOCK(p1); /* * Tell any interested parties about the new process. */ - KNOTE_LOCKED(&p1->p_klist, NOTE_FORK | p2->p_pid); - - PROC_UNLOCK(p1); - + knote_fork(&p1->p_klist, p2->p_pid); SDT_PROBE(proc, kernel, , create, p2, p1, flags, 0, 0); /* diff --git a/sys/sys/event.h b/sys/sys/event.h index 81edb10..37b0a77 100644 --- a/sys/sys/event.h +++ b/sys/sys/event.h @@ -205,6 +205,7 @@ struct proc; struct knlist; extern void knote(struct knlist *list, long hint, int islocked); +extern void knote_fork(struct knlist *list, int pid); extern void knlist_add(struct knlist *knl, struct knote *kn, int islocked); extern void knlist_remove(struct knlist *knl, struct knote *kn, int islocked); extern void knlist_remove_inevent(struct knlist *knl, struct knote *kn); |