Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 01 Aug 2026 12:19:25 +0000
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 7da4edd30098 - main - pdwait(2): change handling of the exited processes
Message-ID:  <6a6de44d.1d6b4.7899d7a8@gitrepo.freebsd.org>

index | next in thread | raw e-mail

The branch main has been updated by kib:

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

commit 7da4edd300984abe67ff503828c1674a28e4b8b0
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-07-28 00:31:51 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-08-01 10:41:35 +0000

    pdwait(2): change handling of the exited processes
    
    Instead of accessing the struct proc and gathering data from it,
    memoize the data needed for pdwait() on exited process in struct
    procdesc, at the time of process termination.
    
    This allows unlimited number of calls to pdwait(2) on procdesc for
    terminated process.
    
    Change the locking requirements for pd_flags to proctree_lock. This does
    not modify the pre-patch locking regime, but the change requires it.
    
    Reviewed by:    markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D58407
---
 sys/kern/kern_exit.c    | 27 ++++++++++++++++++---------
 sys/kern/sys_procdesc.c | 29 +++++++++++++++++++++++++----
 sys/sys/procdesc.h      | 11 +++++++++--
 3 files changed, 52 insertions(+), 15 deletions(-)

diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 2e8e95e33d8c..b61fb7bcf2f1 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1578,29 +1578,38 @@ kern_pdwait(struct thread *td, int fd, int *status,
 		    ("closed proc %p procdesc %p pd flags %#x",
 		    pd->pd_proc, pd, pd->pd_flags));
 
+		if ((pd->pd_flags & PDF_EXITED) != 0) {
+			if ((options & WEXITED) == 0) {
+				error = ESRCH;
+				goto exit_tree_locked;
+			}
+			procdesc_fill_winfo(pd, false);
+			*status = KW_EXITCODE(pd->pd_xexit, pd->pd_xsig);
+			if (wrusage != NULL) {
+				memcpy(wrusage, &pd->pd_wrusage,
+				    sizeof(*wrusage));
+			}
+			if (siginfo != NULL) {
+				memcpy(siginfo, &pd->pd_siginfo,
+				    sizeof(*siginfo));
+			}
+			goto exit_tree_locked;
+		}
 		p = pd->pd_proc;
 		if (p == NULL) {
 			error = ESRCH;
 			goto exit_tree_locked;
 		}
 		PROC_LOCK(p);
+		MPASS(p->p_state != PRS_ZOMBIE);
 
 		error = p_canwait(td, p);
 		if (error != 0)
 			break;
-		if ((options & WEXITED) == 0 && p->p_state == PRS_ZOMBIE) {
-			error = ESRCH;
-			break;
-		}
 
 		wait_fill_siginfo(p, siginfo);
 		wait_fill_wrusage(p, wrusage);
 
-		if (p->p_state == PRS_ZOMBIE) {
-			proc_reap(td, p, status, options);
-			goto exit_unlocked;
-		}
-
 		if (wait6_check_alive(td, options, p, status, siginfo))
 			goto exit_unlocked;
 
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index 608771b9f38c..a605633fbca5 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -295,7 +295,8 @@ procdesc_exit(struct proc *p)
 	KASSERT(pd->pd_fpcount > 0, ("%s: closed procdesc %p", __func__, pd));
 
 	pd->pd_flags |= PDF_EXITED;
-	pd->pd_xstat = KW_EXITCODE(p->p_xexit, p->p_xsig);
+	pd->pd_xexit = p->p_xexit;
+	pd->pd_xsig = p->p_xsig;
 
 	selwakeup(&pd->pd_selinfo);
 	KNOTE_LOCKED(&pd->pd_selinfo.si_note, NOTE_EXIT | NOTE_PDSIGCHLD);
@@ -337,6 +338,25 @@ procdesc_fork(struct proc *p, pid_t child_pid)
 	PROC_UNLOCK(p);
 }
 
+void
+procdesc_fill_winfo(struct procdesc *pd, bool proc_locked)
+{
+	struct proc *p;
+
+	sx_assert(&proctree_lock, SA_XLOCKED);
+
+	if ((pd->pd_flags & (PDF_EXITED | PDF_EXIT_INFO)) == PDF_EXITED) {
+		pd->pd_flags |= PDF_EXIT_INFO;
+		p = pd->pd_proc;
+		if (!proc_locked)
+			PROC_LOCK(p);
+		wait_fill_siginfo(p, &pd->pd_siginfo);
+		wait_fill_wrusage(p, &pd->pd_wrusage);
+		if (!proc_locked)
+			PROC_UNLOCK(p);
+	}
+}
+
 /*
  * When a process descriptor is reaped, perhaps as a result of close(), release
  * the process's reference on the process descriptor.
@@ -350,6 +370,7 @@ procdesc_reap(struct proc *p)
 	KASSERT(p->p_procdesc != NULL, ("procdesc_reap: p_procdesc == NULL"));
 
 	pd = p->p_procdesc;
+	procdesc_fill_winfo(pd, false);
 	pd->pd_proc = NULL;
 	p->p_procdesc = NULL;
 	procdesc_free(pd);
@@ -458,7 +479,7 @@ procdesc_poll(struct file *fp, int events, struct ucred *active_cred,
 	revents = 0;
 	pd = fp->f_data;
 	PROCDESC_LOCK(pd);
-	if (pd->pd_flags & PDF_EXITED)
+	if ((atomic_load_int(&pd->pd_flags) & PDF_EXITED) != 0)
 		revents |= POLLHUP;
 	else
 		selrecord(td, &pd->pd_selinfo);
@@ -491,7 +512,7 @@ procdesc_kqops_event(struct knote *kn, long hint)
 		 * pending.
 		 */
 		p = pd->pd_proc;
-		if ((pd->pd_flags & PDF_EXITED) != 0)
+		if ((atomic_load_int(&pd->pd_flags) & PDF_EXITED) != 0)
 			event = NOTE_EXIT | NOTE_PDSIGCHLD;
 		else if ((atomic_load_int(&p->p_flag) & (P_STOPPED_SIG |
 		    P_STOPPED_TRACE)) != 0)
@@ -509,7 +530,7 @@ procdesc_kqops_event(struct knote *kn, long hint)
 
 	/* Report exit status */
 	if ((kn->kn_fflags & NOTE_EXIT) != 0)
-		kn->kn_data = pd->pd_xstat;
+		kn->kn_data = KW_EXITCODE(pd->pd_xexit, pd->pd_xsig);
 
 	/* Process is gone, so flag the event as finished. */
 	if ((event & NOTE_REAP) != 0 ||
diff --git a/sys/sys/procdesc.h b/sys/sys/procdesc.h
index bb486d9026ba..f912f8787fd9 100644
--- a/sys/sys/procdesc.h
+++ b/sys/sys/procdesc.h
@@ -71,10 +71,15 @@ struct procdesc {
 	/*
 	 * In-flight data and notification of events.
 	 */
-	int		 pd_flags;		/* (p) PD_ flags. */
-	u_short		 pd_xstat;		/* (p) Exit status. */
+	int		 pd_flags;		/* (t) PD_ flags. */
 	struct selinfo	 pd_selinfo;		/* (p) Event notification. */
 	struct mtx	 pd_lock;		/* Protect data + events. */
+
+	/* Exit status. */
+	u_int		 pd_xexit;
+	u_int		 pd_xsig;
+	struct __wrusage pd_wrusage;
+	siginfo_t	 pd_siginfo;
 };
 
 /*
@@ -89,6 +94,7 @@ struct procdesc {
 /*
  * Flags for the pd_flags field.
  */
+#define	PDF_EXIT_INFO	0x00000001	/* Exit info calculated. */
 #define	PDF_EXITED	0x00000004	/* Process exited. */
 
 /*
@@ -111,6 +117,7 @@ void	 procdesc_new(struct proc *, int);
 void	 procdesc_finit(struct procdesc *, struct file *);
 pid_t	 procdesc_pid(struct file *);
 void	 procdesc_reap(struct proc *);
+void	 procdesc_fill_winfo(struct procdesc *pd, bool proc_locked);
 
 int	 procdesc_falloc(struct thread *, struct file **, int *, int,
 	    struct filecaps *);


home | help

Want to link to this message? Use this
URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?6a6de44d.1d6b4.7899d7a8>