]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_event.c
xnu-792.13.8.tar.gz
[apple/xnu.git] / bsd / kern / kern_event.c
index a7586e3f5da0cd4cde9fe475a3f7000aafdd0a1d..296705c77444fea9f2c8f95225eccaa6d542839f 100644 (file)
@@ -81,6 +81,7 @@
 #include <sys/sysproto.h>
 #include <sys/user.h>
 #include <string.h>
+#include <sys/proc_info.h>
 
 #include <kern/lock.h>
 #include <kern/clock.h>
@@ -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);
+}