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@
This commit is contained in:
parent
29aa8ff1dd
commit
38219d6acd
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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. */
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user