The branch main has been updated by kib:

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

commit 7da4edd300984abe67ff503828c1674a28e4b8b0
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-28 00:31:51 +0000
Commit:     Konstantin Belousov <[email protected]>
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 *);

Reply via email to