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$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd November 4, 2013
|
.Dd April 7, 2014
|
||||||
.Dt KQUEUE 2
|
.Dt KQUEUE 2
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -412,6 +412,24 @@ and the child process will not signal a NOTE_CHILD event.
|
|||||||
On return,
|
On return,
|
||||||
.Va fflags
|
.Va fflags
|
||||||
contains the events which triggered the filter.
|
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
|
.It EVFILT_SIGNAL
|
||||||
Takes the signal number to monitor as the identifier and returns
|
Takes the signal number to monitor as the identifier and returns
|
||||||
when the given signal is delivered to the process.
|
when the given signal is delivered to the process.
|
||||||
|
@ -32,7 +32,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd April 4, 2014
|
.Dd April 7, 2014
|
||||||
.Dt PDFORK 2
|
.Dt PDFORK 2
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -117,6 +117,13 @@ and
|
|||||||
allow waiting for process state transitions; currently only
|
allow waiting for process state transitions; currently only
|
||||||
.Dv POLLHUP
|
.Dv POLLHUP
|
||||||
is defined, and will be raised when the process dies.
|
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
|
.Pp
|
||||||
.Xr close 2
|
.Xr close 2
|
||||||
will close the process descriptor unless
|
will close the process descriptor unless
|
||||||
|
@ -290,7 +290,7 @@ static struct {
|
|||||||
{ &proc_filtops }, /* EVFILT_PROC */
|
{ &proc_filtops }, /* EVFILT_PROC */
|
||||||
{ &sig_filtops }, /* EVFILT_SIGNAL */
|
{ &sig_filtops }, /* EVFILT_SIGNAL */
|
||||||
{ &timer_filtops }, /* EVFILT_TIMER */
|
{ &timer_filtops }, /* EVFILT_TIMER */
|
||||||
{ &null_filtops }, /* former EVFILT_NETDEV */
|
{ &file_filtops }, /* EVFILT_PROCDESC */
|
||||||
{ &fs_filtops }, /* EVFILT_FS */
|
{ &fs_filtops }, /* EVFILT_FS */
|
||||||
{ &null_filtops }, /* EVFILT_LIO */
|
{ &null_filtops }, /* EVFILT_LIO */
|
||||||
{ &user_filtops }, /* EVFILT_USER */
|
{ &user_filtops }, /* EVFILT_USER */
|
||||||
@ -417,27 +417,22 @@ filt_procdetach(struct knote *kn)
|
|||||||
static int
|
static int
|
||||||
filt_proc(struct knote *kn, long hint)
|
filt_proc(struct knote *kn, long hint)
|
||||||
{
|
{
|
||||||
struct proc *p = kn->kn_ptr.p_proc;
|
struct proc *p;
|
||||||
u_int event;
|
u_int event;
|
||||||
|
|
||||||
/*
|
p = kn->kn_ptr.p_proc;
|
||||||
* mask off extra data
|
/* Mask off extra data. */
|
||||||
*/
|
|
||||||
event = (u_int)hint & NOTE_PCTRLMASK;
|
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)
|
if (kn->kn_sfflags & event)
|
||||||
kn->kn_fflags |= 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 (event == NOTE_EXIT) {
|
||||||
if (!(kn->kn_status & KN_DETACHED))
|
if (!(kn->kn_status & KN_DETACHED))
|
||||||
knlist_remove_inevent(&p->p_klist, kn);
|
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;
|
kn->kn_ptr.p_proc = NULL;
|
||||||
if (kn->kn_fflags & NOTE_EXIT)
|
if (kn->kn_fflags & NOTE_EXIT)
|
||||||
kn->kn_data = p->p_xstat;
|
kn->kn_data = p->p_xstat;
|
||||||
|
@ -236,6 +236,7 @@ procdesc_new(struct proc *p, int flags)
|
|||||||
if (flags & PD_DAEMON)
|
if (flags & PD_DAEMON)
|
||||||
pd->pd_flags |= PDF_DAEMON;
|
pd->pd_flags |= PDF_DAEMON;
|
||||||
PROCDESC_LOCK_INIT(pd);
|
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
|
* 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),
|
KASSERT((pd->pd_flags & PDF_CLOSED),
|
||||||
("procdesc_free: !PDF_CLOSED"));
|
("procdesc_free: !PDF_CLOSED"));
|
||||||
|
|
||||||
|
knlist_destroy(&pd->pd_selinfo.si_note);
|
||||||
PROCDESC_LOCK_DESTROY(pd);
|
PROCDESC_LOCK_DESTROY(pd);
|
||||||
uma_zfree(procdesc_zone, pd);
|
uma_zfree(procdesc_zone, pd);
|
||||||
}
|
}
|
||||||
@ -296,6 +298,7 @@ procdesc_exit(struct proc *p)
|
|||||||
("procdesc_exit: closed && parent not init"));
|
("procdesc_exit: closed && parent not init"));
|
||||||
|
|
||||||
pd->pd_flags |= PDF_EXITED;
|
pd->pd_flags |= PDF_EXITED;
|
||||||
|
pd->pd_xstat = p->p_xstat;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the process descriptor has been closed, then we have nothing
|
* 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;
|
pd->pd_flags &= ~PDF_SELECTED;
|
||||||
selwakeup(&pd->pd_selinfo);
|
selwakeup(&pd->pd_selinfo);
|
||||||
}
|
}
|
||||||
|
KNOTE_LOCKED(&pd->pd_selinfo.si_note, NOTE_EXIT);
|
||||||
PROCDESC_UNLOCK(pd);
|
PROCDESC_UNLOCK(pd);
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
@ -460,11 +464,71 @@ procdesc_poll(struct file *fp, int events, struct ucred *active_cred,
|
|||||||
return (revents);
|
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
|
static int
|
||||||
procdesc_kqfilter(struct file *fp, struct knote *kn)
|
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
|
static int
|
||||||
|
@ -38,7 +38,7 @@
|
|||||||
#define EVFILT_PROC (-5) /* attached to struct proc */
|
#define EVFILT_PROC (-5) /* attached to struct proc */
|
||||||
#define EVFILT_SIGNAL (-6) /* attached to struct proc */
|
#define EVFILT_SIGNAL (-6) /* attached to struct proc */
|
||||||
#define EVFILT_TIMER (-7) /* timers */
|
#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_FS (-9) /* filesystem events */
|
||||||
#define EVFILT_LIO (-10) /* attached to lio requests */
|
#define EVFILT_LIO (-10) /* attached to lio requests */
|
||||||
#define EVFILT_USER (-11) /* User events */
|
#define EVFILT_USER (-11) /* User events */
|
||||||
@ -120,7 +120,7 @@ struct kevent {
|
|||||||
#define NOTE_REVOKE 0x0040 /* vnode access was revoked */
|
#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_EXIT 0x80000000 /* process exited */
|
||||||
#define NOTE_FORK 0x40000000 /* process forked */
|
#define NOTE_FORK 0x40000000 /* process forked */
|
||||||
|
@ -68,6 +68,7 @@ struct procdesc {
|
|||||||
* In-flight data and notification of events.
|
* In-flight data and notification of events.
|
||||||
*/
|
*/
|
||||||
int pd_flags; /* (p) PD_ flags. */
|
int pd_flags; /* (p) PD_ flags. */
|
||||||
|
u_short pd_xstat; /* (p) Exit status. */
|
||||||
struct selinfo pd_selinfo; /* (p) Event notification. */
|
struct selinfo pd_selinfo; /* (p) Event notification. */
|
||||||
struct mtx pd_lock; /* Protect data + events. */
|
struct mtx pd_lock; /* Protect data + events. */
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user