git: b58c9e8cf6ac - stable/14 - kqueue: Add NOTE_REAP

Dag-Erling Smørgrav <[email protected]> Mon, 03 Aug 2026 11:38:44 +0000
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a707dc4.1c122.4e1cdebd__7454.19715983502$1785757225$gmane$org@gitrepo.freebsd.org>
The branch stable/14 has been updated by des:

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

commit b58c9e8cf6acef2774ebb87dd79eecfa31618d6a
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:13 +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/libc/sys/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/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2
index d6e949baa24c..e4e4c85d8a77 100644
--- a/lib/libc/sys/kqueue.2
+++ b/lib/libc/sys/kqueue.2
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd March 26, 2023
+.Dd July 22, 2026
 .Dt KQUEUE 2
 .Os
 .Sh NAME
@@ -516,9 +516,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 32829d35dbe0..018dfef5f5c2 100644
--- a/lib/libsysdecode/flags.c
+++ b/lib/libsysdecode/flags.c
@@ -367,8 +367,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 e2f44aea27b4..a735dfaa97df 100644
--- a/sys/kern/kern_event.c
+++ b/sys/kern/kern_event.c
@@ -421,7 +421,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);
@@ -446,7 +446,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. */
 	}
 	/*
@@ -508,12 +508,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 baa5cad2bdc8..3cfb55fe3711 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -987,6 +987,7 @@ proc_reap(struct thread *td, struct proc *p, int *status, int options)
 	proc_id_clear(PROC_ID_PID, p->p_pid);
 
 	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 f1aeb4066fa4..c6781aac2523 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -468,11 +468,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 a1cd224a960e..246ebdedd004 100644
--- a/sys/sys/event.h
+++ b/sys/sys/event.h
@@ -203,7 +203,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 */
@@ -248,12 +251,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