summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authored <ed@FreeBSD.org>2014-04-07 18:10:49 +0000
committered <ed@FreeBSD.org>2014-04-07 18:10:49 +0000
commit87c17a9c6666c07778d84cde29bff0fe8830ca77 (patch)
tree86add6f815ce421c32d599a69a835b29dee9b881
parentb9ab124041f69613e738fb1f1f6916cca7b0f786 (diff)
downloadFreeBSD-src-87c17a9c6666c07778d84cde29bff0fe8830ca77.zip
FreeBSD-src-87c17a9c6666c07778d84cde29bff0fe8830ca77.tar.gz
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@
-rw-r--r--lib/libc/sys/kqueue.220
-rw-r--r--lib/libc/sys/pdfork.29
-rw-r--r--sys/kern/kern_event.c19
-rw-r--r--sys/kern/sys_procdesc.c66
-rw-r--r--sys/sys/event.h4
-rw-r--r--sys/sys/procdesc.h1
6 files changed, 102 insertions, 17 deletions
diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2
index 75c8207..1b2951e 100644
--- a/lib/libc/sys/kqueue.2
+++ b/lib/libc/sys/kqueue.2
@@ -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 NOTE_CHILD event.
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.
diff --git a/lib/libc/sys/pdfork.2 b/lib/libc/sys/pdfork.2
index 87f2c8c..a489515 100644
--- a/lib/libc/sys/pdfork.2
+++ b/lib/libc/sys/pdfork.2
@@ -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
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index fadb8fd..9b095b0 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -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;
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index 0c2743f..1039dac 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -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 events, struct ucred *active_cred,
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
diff --git a/sys/sys/event.h b/sys/sys/event.h
index 3b765c0..1f27c4d 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -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 */
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
index d7b3f2a..b48b79a 100644
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -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. */
};
OpenPOWER on IntegriCloud