diff --git a/lib/libsys/kqueue.2 b/lib/libsys/kqueue.2 --- a/lib/libsys/kqueue.2 +++ b/lib/libsys/kqueue.2 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd January 24, 2026 +.Dd July 22, 2026 .Dt KQUEUE 2 .Os .Sh NAME @@ -543,9 +543,15 @@ .Va data in the same format as the status returned by .Xr wait 2 . +.It Dv NOTE_REAP +The process has been reaped by a call to the +.Xr wait 2 +family of functions. .It Dv NOTE_FORK The process has called -.Fn fork . +.Xr fork 2 +or +.Xr vfork 2 . .It Dv NOTE_EXEC The process has executed a new process via .Xr execve 2 diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c --- a/lib/libsysdecode/flags.c +++ b/lib/libsysdecode/flags.c @@ -377,7 +377,7 @@ }; static struct name_table kevent_proc_fflags[] = { - X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_PDSIGCHLD) + X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_PDSIGCHLD) X(NOTE_REAP) X(NOTE_TRACK) X(NOTE_TRACKERR) X(NOTE_CHILD) XEND }; diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -445,7 +445,7 @@ bool exiting, immediate; exiting = immediate = false; - if (kn->kn_sfflags & NOTE_EXIT) + if (kn->kn_sfflags & (NOTE_EXIT | NOTE_REAP)) p = pfind_any(kn->kn_id); else p = pfind(kn->kn_id); @@ -470,7 +470,7 @@ kn->kn_flags &= ~EV_FLAG2; kn->kn_data = kn->kn_sdata; /* ppid */ kn->kn_fflags = NOTE_CHILD; - kn->kn_sfflags &= ~(NOTE_EXIT | NOTE_EXEC | NOTE_FORK); + kn->kn_sfflags &= ~NOTE_PCTRLMASK; immediate = true; /* Force immediate activation of child note. */ } /* @@ -532,12 +532,15 @@ if ((kn->kn_sfflags & event) != 0) kn->kn_fflags |= kn->kn_sfflags & event; + /* Report exit status */ + if ((kn->kn_fflags & NOTE_EXIT) != 0) + kn->kn_data = KW_EXITCODE(p->p_xexit, p->p_xsig); + /* Process is gone, so flag the event as finished. */ - if ((event & NOTE_EXIT) != 0) { + if ((event & NOTE_REAP) != 0 || + ((event & NOTE_EXIT) != 0 && (kn->kn_sfflags & NOTE_REAP) == 0)) { kn->kn_flags |= EV_EOF | EV_ONESHOT; kn->kn_ptr.p_proc = NULL; - if (kn->kn_fflags & NOTE_EXIT) - kn->kn_data = KW_EXITCODE(p->p_xexit, p->p_xsig); if (kn->kn_fflags == 0) kn->kn_flags |= EV_DROP; return (1); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1055,6 +1055,7 @@ sx_xunlock(&proctree_lock); PROC_LOCK(p); + KNOTE_LOCKED(p->p_klist, NOTE_REAP); knlist_detach(p->p_klist); p->p_klist = NULL; PROC_UNLOCK(p); diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c --- a/sys/kern/sys_procdesc.c +++ b/sys/kern/sys_procdesc.c @@ -507,11 +507,14 @@ if ((kn->kn_sfflags & event) != 0) kn->kn_fflags |= kn->kn_sfflags & event; + /* Report exit status */ + if ((kn->kn_fflags & NOTE_EXIT) != 0) + kn->kn_data = pd->pd_xstat; + /* Process is gone, so flag the event as finished. */ - if ((event & NOTE_EXIT) != 0) { + if ((event & NOTE_REAP) != 0 || + ((event & NOTE_EXIT) != 0 && (kn->kn_sfflags & NOTE_REAP) == 0)) { 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); diff --git a/sys/sys/event.h b/sys/sys/event.h --- a/sys/sys/event.h +++ b/sys/sys/event.h @@ -209,7 +209,10 @@ #define NOTE_EXEC 0x20000000 /* proc: process exec'd */ #define NOTE_PDSIGCHLD 0x10000000 /* procdesc: pdwait() info available */ -#define NOTE_PCTRLMASK 0xf0000000 /* mask for hint bits */ +#define NOTE_SIGNAL 0x08000000 /* process received a signal, + shared with EVFIL_SIGNAL */ +#define NOTE_REAP 0x04000000 /* process reaped */ +#define NOTE_PCTRLMASK 0xfc000000 /* mask for hint bits */ #define NOTE_PDATAMASK 0x000fffff /* mask for pid */ /* additional flags for EVFILT_PROC */ @@ -263,12 +266,6 @@ #define KNLIST_EMPTY(list) SLIST_EMPTY(&(list)->kl_list) -/* - * Flag indicating hint is a signal. Used by EVFILT_SIGNAL, and also - * shared by EVFILT_PROC (all knotes attached to p->p_klist) - */ -#define NOTE_SIGNAL 0x08000000 - /* * Hint values for the optional f_touch event filter. If f_touch is not set * to NULL and f_isfd is zero the f_touch filter will be called with the type