Author: ed
Date: Mon Apr  7 18:10:49 2014
New Revision: 264231
URL: http://svnweb.freebsd.org/changeset/base/264231

Log:
  Implement kqueue(2) for procdesc(4).
  
  kqueue(2) already supports EVFILT_PROC. Add an EVFILT_PROCDESC that
  behaves the same, but operates on a procdesc(4) instead. Only implement
  NOTE_EXIT for now. The nice thing about NOTE_EXIT is that it also
  returns the exit status of the process, meaning that we can now obtain
  this value, even if pdwait4(2) is still unimplemented.
  
  Notes:
  
  - Simply reuse EVFILT_NETDEV for EVFILT_PROCDESC. As both of these will
    be used on totally different descriptor types, this should not clash.
  
  - Let procdesc_kqops_event() reuse the same structure as filt_proc().
    The only difference is that procdesc_kqops_event() should also be able
    to deal with the case where the process was already terminated after
    registration. Simply test this when hint == 0.
  
  - Fix some style(9) issues in filt_proc() to keep it consistent with the
    newly added procdesc_kqops_event().
  
  - Save the exit status of the process in pd->pd_xstat, as we cannot pick
    up the proctree_lock from within procdesc_kqops_event().
  
  Discussed on: arch@
  Reviewed by:  kib@

Modified:
  head/lib/libc/sys/kqueue.2
  head/lib/libc/sys/pdfork.2
  head/sys/kern/kern_event.c
  head/sys/kern/sys_procdesc.c
  head/sys/sys/event.h
  head/sys/sys/procdesc.h

Modified: head/lib/libc/sys/kqueue.2
==============================================================================
--- head/lib/libc/sys/kqueue.2  Mon Apr  7 16:38:31 2014        (r264230)
+++ head/lib/libc/sys/kqueue.2  Mon Apr  7 18:10:49 2014        (r264231)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd November 4, 2013
+.Dd April 7, 2014
 .Dt KQUEUE 2
 .Os
 .Sh NAME
@@ -412,6 +412,24 @@ and the child process will not signal a 
 On return,
 .Va fflags
 contains the events which triggered the filter.
+.It EVFILT_PROCDESC
+Takes the process descriptor created by
+.Xr pdfork 2
+to monitor as the identifier and the events to watch for in
+.Va fflags ,
+and returns when the associated process performs one or more of the
+requested events.
+The events to monitor are:
+.Bl -tag -width XXNOTE_EXIT
+.It NOTE_EXIT
+The process has exited.
+The exit status will be stored in
+.Va data .
+.El
+.Pp
+On return,
+.Va fflags
+contains the events which triggered the filter.
 .It EVFILT_SIGNAL
 Takes the signal number to monitor as the identifier and returns
 when the given signal is delivered to the process.

Modified: head/lib/libc/sys/pdfork.2
==============================================================================
--- head/lib/libc/sys/pdfork.2  Mon Apr  7 16:38:31 2014        (r264230)
+++ head/lib/libc/sys/pdfork.2  Mon Apr  7 18:10:49 2014        (r264231)
@@ -32,7 +32,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd April 4, 2014
+.Dd April 7, 2014
 .Dt PDFORK 2
 .Os
 .Sh NAME
@@ -117,6 +117,13 @@ and
 allow waiting for process state transitions; currently only
 .Dv POLLHUP
 is defined, and will be raised when the process dies.
+Process state transitions can also be monitored using
+.Xr kqueue 2
+filter
+.Dv EVFILT_PROCDESC ;
+currently only
+.Dv NOTE_EXIT
+is implemented.
 .Pp
 .Xr close 2
 will close the process descriptor unless

Modified: head/sys/kern/kern_event.c
==============================================================================
--- head/sys/kern/kern_event.c  Mon Apr  7 16:38:31 2014        (r264230)
+++ head/sys/kern/kern_event.c  Mon Apr  7 18:10:49 2014        (r264231)
@@ -290,7 +290,7 @@ static struct {
        { &proc_filtops },                      /* EVFILT_PROC */
        { &sig_filtops },                       /* EVFILT_SIGNAL */
        { &timer_filtops },                     /* EVFILT_TIMER */
-       { &null_filtops },                      /* former EVFILT_NETDEV */
+       { &file_filtops },                      /* EVFILT_PROCDESC */
        { &fs_filtops },                        /* EVFILT_FS */
        { &null_filtops },                      /* EVFILT_LIO */
        { &user_filtops },                      /* EVFILT_USER */
@@ -417,27 +417,22 @@ filt_procdetach(struct knote *kn)
 static int
 filt_proc(struct knote *kn, long hint)
 {
-       struct proc *p = kn->kn_ptr.p_proc;
+       struct proc *p;
        u_int event;
 
-       /*
-        * mask off extra data
-        */
+       p = kn->kn_ptr.p_proc;
+       /* Mask off extra data. */
        event = (u_int)hint & NOTE_PCTRLMASK;
 
-       /*
-        * if the user is interested in this event, record it.
-        */
+       /* If the user is interested in this event, record it. */
        if (kn->kn_sfflags & event)
                kn->kn_fflags |= event;
 
-       /*
-        * process is gone, so flag the event as finished.
-        */
+       /* Process is gone, so flag the event as finished. */
        if (event == NOTE_EXIT) {
                if (!(kn->kn_status & KN_DETACHED))
                        knlist_remove_inevent(&p->p_klist, kn);
-               kn->kn_flags |= (EV_EOF | EV_ONESHOT);
+               kn->kn_flags |= EV_EOF | EV_ONESHOT;
                kn->kn_ptr.p_proc = NULL;
                if (kn->kn_fflags & NOTE_EXIT)
                        kn->kn_data = p->p_xstat;

Modified: head/sys/kern/sys_procdesc.c
==============================================================================
--- head/sys/kern/sys_procdesc.c        Mon Apr  7 16:38:31 2014        
(r264230)
+++ head/sys/kern/sys_procdesc.c        Mon Apr  7 18:10:49 2014        
(r264231)
@@ -236,6 +236,7 @@ procdesc_new(struct proc *p, int flags)
        if (flags & PD_DAEMON)
                pd->pd_flags |= PDF_DAEMON;
        PROCDESC_LOCK_INIT(pd);
+       knlist_init_mtx(&pd->pd_selinfo.si_note, &pd->pd_lock);
 
        /*
         * Process descriptors start out with two references: one from their
@@ -270,6 +271,7 @@ procdesc_free(struct procdesc *pd)
                KASSERT((pd->pd_flags & PDF_CLOSED),
                    ("procdesc_free: !PDF_CLOSED"));
 
+               knlist_destroy(&pd->pd_selinfo.si_note);
                PROCDESC_LOCK_DESTROY(pd);
                uma_zfree(procdesc_zone, pd);
        }
@@ -296,6 +298,7 @@ procdesc_exit(struct proc *p)
            ("procdesc_exit: closed && parent not init"));
 
        pd->pd_flags |= PDF_EXITED;
+       pd->pd_xstat = p->p_xstat;
 
        /*
         * If the process descriptor has been closed, then we have nothing
@@ -314,6 +317,7 @@ procdesc_exit(struct proc *p)
                pd->pd_flags &= ~PDF_SELECTED;
                selwakeup(&pd->pd_selinfo);
        }
+       KNOTE_LOCKED(&pd->pd_selinfo.si_note, NOTE_EXIT);
        PROCDESC_UNLOCK(pd);
        return (0);
 }
@@ -460,11 +464,71 @@ procdesc_poll(struct file *fp, int event
        return (revents);
 }
 
+static void
+procdesc_kqops_detach(struct knote *kn)
+{
+       struct procdesc *pd;
+
+       pd = kn->kn_fp->f_data;
+       knlist_remove(&pd->pd_selinfo.si_note, kn, 0);
+}
+
+static int
+procdesc_kqops_event(struct knote *kn, long hint)
+{
+       struct procdesc *pd;
+       u_int event;
+
+       pd = kn->kn_fp->f_data;
+       if (hint == 0) {
+               /*
+                * Initial test after registration. Generate a NOTE_EXIT in
+                * case the process already terminated before registration.
+                */
+               event = pd->pd_flags & PDF_EXITED ? NOTE_EXIT : 0;
+       } else {
+               /* Mask off extra data. */
+               event = (u_int)hint & NOTE_PCTRLMASK;
+       }
+
+       /* If the user is interested in this event, record it. */
+       if (kn->kn_sfflags & event)
+               kn->kn_fflags |= event;
+
+       /* Process is gone, so flag the event as finished. */
+       if (event == NOTE_EXIT) {
+               kn->kn_flags |= EV_EOF | EV_ONESHOT;
+               if (kn->kn_fflags & NOTE_EXIT)
+                       kn->kn_data = pd->pd_xstat;
+               if (kn->kn_fflags == 0)
+                       kn->kn_flags |= EV_DROP;
+               return (1);
+       }
+
+       return (kn->kn_fflags != 0);
+}
+
+static struct filterops procdesc_kqops = {
+       .f_isfd = 1,
+       .f_detach = procdesc_kqops_detach,
+       .f_event = procdesc_kqops_event,
+};
+
 static int
 procdesc_kqfilter(struct file *fp, struct knote *kn)
 {
+       struct procdesc *pd;
 
-       return (EOPNOTSUPP);
+       pd = fp->f_data;
+       switch (kn->kn_filter) {
+       case EVFILT_PROCDESC:
+               kn->kn_fop = &procdesc_kqops;
+               kn->kn_flags |= EV_CLEAR;
+               knlist_add(&pd->pd_selinfo.si_note, kn, 0);
+               return (0);
+       default:
+               return (EINVAL);
+       }
 }
 
 static int

Modified: head/sys/sys/event.h
==============================================================================
--- head/sys/sys/event.h        Mon Apr  7 16:38:31 2014        (r264230)
+++ head/sys/sys/event.h        Mon Apr  7 18:10:49 2014        (r264231)
@@ -38,7 +38,7 @@
 #define EVFILT_PROC            (-5)    /* attached to struct proc */
 #define EVFILT_SIGNAL          (-6)    /* attached to struct proc */
 #define EVFILT_TIMER           (-7)    /* timers */
-/*     EVFILT_NETDEV           (-8)       no longer supported */
+#define EVFILT_PROCDESC                (-8)    /* attached to process 
descriptors */
 #define EVFILT_FS              (-9)    /* filesystem events */
 #define EVFILT_LIO             (-10)   /* attached to lio requests */
 #define EVFILT_USER            (-11)   /* User events */
@@ -120,7 +120,7 @@ struct kevent {
 #define        NOTE_REVOKE     0x0040                  /* vnode access was 
revoked */
 
 /*
- * data/hint flags for EVFILT_PROC, shared with userspace
+ * data/hint flags for EVFILT_PROC and EVFILT_PROCDESC, shared with userspace
  */
 #define        NOTE_EXIT       0x80000000              /* process exited */
 #define        NOTE_FORK       0x40000000              /* process forked */

Modified: head/sys/sys/procdesc.h
==============================================================================
--- head/sys/sys/procdesc.h     Mon Apr  7 16:38:31 2014        (r264230)
+++ head/sys/sys/procdesc.h     Mon Apr  7 18:10:49 2014        (r264231)
@@ -68,6 +68,7 @@ struct procdesc {
         * In-flight data and notification of events.
         */
        int              pd_flags;              /* (p) PD_ flags. */
+       u_short          pd_xstat;              /* (p) Exit status. */
        struct selinfo   pd_selinfo;            /* (p) Event notification. */
        struct mtx       pd_lock;               /* Protect data + events. */
 };
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to