git: 4ce8f2940a6a - stable/15 - kqueue: Add NOTE_REAP

Dag-Erling Smørgrav <[email protected]> Mon, 03 Aug 2026 11:38:39 +0000
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a707dbf.1c6e9.4a98cdc2__20354.3663186551$1785757150$gmane$org@gitrepo.freebsd.org>
The branch stable/15 has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=4ce8f2940a6a62b4d79b54d9d9a0c1acaca0ad5c

commit 4ce8f2940a6a62b4d79b54d9d9a0c1acaca0ad5c
Author:     Dag-Erling Smørgrav <[email protected]>
AuthorDate: 2026-07-27 10:15:26 +0000
Commit:     Dag-Erling Smørgrav <[email protected]>
CommitDate: 2026-08-03 11:32:12 +0000

    kqueue: Add NOTE_REAP
    
    Add a NOTE_REAP event for EVFILTER_PROC which provides a notification
    when the process is reaped.
    
    MFC after:      1 week
    Sponsored by:   Klara, Inc.
    Sponsored by:   NetApp, Inc.
    Reviewed by:    kib, markj
    Differential Revision:  https://reviews.freebsd.org/D58313
    
    (cherry picked from commit 2bacbbecb165dd761ea7ec2fc35630db61508cdf)
---
 lib/libsys/kqueue.2      | 10 ++++++++--
 lib/libsysdecode/flags.c |  4 ++--
 sys/kern/kern_event.c    | 13 ++++++++-----
 sys/kern/kern_exit.c     |  1 +
 sys/kern/sys_procdesc.c  |  9 ++++++---
 sys/sys/event.h          | 11 ++++-------
 6 files changed, 29 insertions(+), 19 deletions(-)

diff --git a/lib/libsys/kqueue.2 b/lib/libsys/kqueue.2
index 6e2d2df40ead..b596a705e08f 100644
--- 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 @@ The exit status will be stored in
 .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
index f8e26e6a9dae..c46e8ec607b9 100644
--- a/lib/libsysdecode/flags.c
+++ b/lib/libsysdecode/flags.c
@@ -375,8 +375,8 @@ static struct name_table kevent_vnode_fflags[] = {
 };
 
 static struct name_table kevent_proc_fflags[] = {
-	X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_TRACK) X(NOTE_TRACKERR)
-	X(NOTE_CHILD) XEND
+	X(NOTE_EXIT) X(NOTE_FORK) X(NOTE_EXEC) X(NOTE_REAP)
+	X(NOTE_TRACK) X(NOTE_TRACKERR) X(NOTE_CHILD) XEND
 };
 
 static struct name_table kevent_timer_fflags[] = {
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c
index 8e2dd0eb3492..2a1269ec6e3c 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -445,7 +445,7 @@ filt_procattach(struct knote *kn)
 	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 @@ filt_procattach(struct knote *kn)
 		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 @@ filt_proc(struct knote *kn, long hint)
 	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
index 8f9007752b3b..757428826f96 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1054,6 +1054,7 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options)
 	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
index a06d29b91ba8..953816077269 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -473,11 +473,14 @@ procdesc_kqops_event(struct knote *kn, long hint)
 	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) {
+	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
index a863cd20f45d..16fc829fc8ea 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -205,7 +205,10 @@ struct freebsd11_kevent32 {
 #define	NOTE_EXIT	0x80000000		/* process exited */
 #define	NOTE_FORK	0x40000000		/* process forked */
 #define	NOTE_EXEC	0x20000000		/* process exec'd */
-#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	0xec000000		/* mask for hint bits */
 #define	NOTE_PDATAMASK	0x000fffff		/* mask for pid */
 
 /* additional flags for EVFILT_PROC */
@@ -259,12 +262,6 @@ struct knlist {
 
 #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