Date: Mon, 7 Apr 2014 18:10:49 +0000 (UTC) From: Ed Schouten <ed@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r264231 - in head: lib/libc/sys sys/kern sys/sys Message-ID: <201404071810.s37IAn6k075919@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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. */ };
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201404071810.s37IAn6k075919>