X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/8ad349bb6ed4a0be06e34c92be0d98b92e078db4..5d5c5d0d5b79ade9a973d55186ffda2638ba2b6e:/bsd/kern/kern_event.c?ds=sidebyside diff --git a/bsd/kern/kern_event.c b/bsd/kern/kern_event.c index a7586e3f5..296705c77 100644 --- a/bsd/kern/kern_event.c +++ b/bsd/kern/kern_event.c @@ -81,6 +81,7 @@ #include #include #include +#include #include #include @@ -419,6 +420,7 @@ filt_procattach(struct knote *kn) } kn->kn_flags |= EV_CLEAR; /* automatically set */ + kn->kn_hookid = 1; /* mark exit not seen */ /* * internal flag indicating registration done by kernel @@ -439,11 +441,12 @@ filt_procattach(struct knote *kn) /* * The knote may be attached to a different process, which may exit, - * leaving nothing for the knote to be attached to. So when the process - * exits, the knote is marked as DETACHED and also flagged as ONESHOT so - * it will be deleted when read out. However, as part of the knote deletion, - * this routine is called, so a check is needed to avoid actually performing - * a detach, because the original process does not exist any more. + * leaving nothing for the knote to be attached to. In that case, + * we wont be able to find the process from its pid. But the exit + * code may still be processing the knote list for the target process. + * We may have to wait for that processing to complete before we can + * return (and presumably free the knote) without actually removing + * it from the dead process' knote list. */ static void filt_procdetach(struct knote *kn) @@ -454,66 +457,81 @@ filt_procdetach(struct knote *kn) funnel_state = thread_funnel_set(kernel_flock, TRUE); p = pfind(kn->kn_id); - if (p != (struct proc *)NULL) + if (p != (struct proc *)NULL) { KNOTE_DETACH(&p->p_klist, kn); - + } else if (kn->kn_hookid != 0) { /* if not NOTE_EXIT yet */ + kn->kn_hookid = -1; /* we are detaching but... */ + assert_wait(&kn->kn_hook, THREAD_UNINT); /* have to wait */ + thread_block(THREAD_CONTINUE_NULL); + } thread_funnel_set(kernel_flock, funnel_state); } static int filt_proc(struct knote *kn, long hint) { - u_int event; - int funnel_state; - funnel_state = thread_funnel_set(kernel_flock, TRUE); + if (hint != 0) { + u_int event; - /* - * mask off extra data - */ - event = (u_int)hint & NOTE_PCTRLMASK; + /* must hold the funnel when coming from below */ + assert(thread_funnel_get() != (funnel_t)0); - /* - * if the user is interested in this event, record it. - */ - if (kn->kn_sfflags & event) - kn->kn_fflags |= event; + /* + * mask off extra data + */ + event = (u_int)hint & NOTE_PCTRLMASK; - /* - * process is gone, so flag the event as finished. - */ - if (event == NOTE_EXIT) { - kn->kn_flags |= (EV_EOF | EV_ONESHOT); - thread_funnel_set(kernel_flock, funnel_state); - return (1); - } + /* + * if the user is interested in this event, record it. + */ + if (kn->kn_sfflags & event) + kn->kn_fflags |= event; - /* - * 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; + /* + * process is gone, so flag the event as finished. + * + * If someone was trying to detach, but couldn't + * find the proc to complete the detach, wake them + * up (nothing will ever need to walk the per-proc + * knote list again - so its safe for them to dump + * the knote now). + */ + if (event == NOTE_EXIT) { + boolean_t detaching = (kn->kn_hookid == -1); + + kn->kn_hookid = 0; + kn->kn_flags |= (EV_EOF | EV_ONESHOT); + if (detaching) + thread_wakeup(&kn->kn_hookid); + return (1); + } /* - * register knote with new process. + * 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. */ - kev.ident = hint & NOTE_PDATAMASK; /* 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 = kevent_register(kn->kn_kq, &kev, NULL); - if (error) - kn->kn_fflags |= NOTE_TRACKERR; + if ((event == NOTE_FORK) && (kn->kn_sfflags & NOTE_TRACK)) { + struct kevent kev; + int error; + + /* + * register knote with new process. + */ + kev.ident = hint & NOTE_PDATAMASK; /* 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 = kevent_register(kn->kn_kq, &kev, NULL); + if (error) + kn->kn_fflags |= NOTE_TRACKERR; + } } - event = kn->kn_fflags; - thread_funnel_set(kernel_flock, funnel_state); - return (event != 0); + return (kn->kn_fflags != 0); /* atomic check - no funnel needed from above */ } /* @@ -1955,13 +1973,11 @@ knote_init(void) /* allocate kq lock group attribute and group */ kq_lck_grp_attr= lck_grp_attr_alloc_init(); - lck_grp_attr_setstat(kq_lck_grp_attr); kq_lck_grp = lck_grp_alloc_init("kqueue", kq_lck_grp_attr); /* Allocate kq lock attribute */ kq_lck_attr = lck_attr_alloc_init(); - lck_attr_setdefault(kq_lck_attr); /* Initialize the timer filter lock */ lck_mtx_init(&_filt_timerlock, kq_lck_grp, kq_lck_attr); @@ -2055,7 +2071,6 @@ kern_event_init(void) * allocate the lock attribute for mutexes */ evt_mtx_attr = lck_attr_alloc_init(); - lck_attr_setdefault(evt_mtx_attr); evt_mutex = lck_mtx_alloc_init(evt_mtx_grp, evt_mtx_attr); if (evt_mutex == NULL) return (ENOMEM); @@ -2280,4 +2295,23 @@ kev_control(struct socket *so, +int +fill_kqueueinfo(struct kqueue *kq, struct kqueue_info * kinfo) +{ + struct stat * st; + + /* No need for the funnel as fd is kept alive */ + + st = &kinfo->kq_stat; + + st->st_size = kq->kq_count; + st->st_blksize = sizeof(struct kevent); + st->st_mode = S_IFIFO; + if (kq->kq_state & KQ_SEL) + kinfo->kq_state |= PROC_KQUEUE_SELECT; + if (kq->kq_state & KQ_SLEEP) + kinfo->kq_state |= PROC_KQUEUE_SLEEP; + + return(0); +}