git: 4d707825bf62 - main - Add pdwait(2)

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 25 Jan 2026 15:56:58 UTC
The branch main has been updated by kib:

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

commit 4d707825bf62ee73a32b615846eff9c4a9bda538
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-01-08 03:37:42 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-01-25 15:54:02 +0000

    Add pdwait(2)
    
    Reviewed by:    asomers, markj
    Tested by:      pho
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D54592
---
 sys/compat/freebsd32/freebsd32_misc.c |  31 ++++++++++
 sys/kern/kern_exit.c                  | 105 ++++++++++++++++++++++++++++++++++
 sys/kern/sys_procdesc.c               |   4 ++
 sys/kern/syscalls.master              |  10 ++++
 sys/sys/syscallsubr.h                 |   2 +
 5 files changed, 152 insertions(+)

diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 8a2c179926d8..c76c9d5c1838 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -281,6 +281,37 @@ freebsd32_wait6(struct thread *td, struct freebsd32_wait6_args *uap)
 	return (error);
 }
 
+int
+freebsd32_pdwait(struct thread *td, struct freebsd32_pdwait_args *uap)
+{
+	struct __wrusage32 wru32;
+	struct __wrusage wru, *wrup;
+	struct __siginfo32 si32;
+	struct __siginfo si, *sip;
+	int error, status;
+
+	wrup = uap->wrusage != NULL ? &wru : NULL;
+	if (uap->info != NULL) {
+		sip = &si;
+		bzero(sip, sizeof(*sip));
+	} else {
+		sip = NULL;
+	}
+	error = kern_pdwait(td, uap->fd, &status, uap->options, wrup, sip);
+	if (uap->status != NULL && error == 0)
+		error = copyout(&status, uap->status, sizeof(status));
+	if (uap->wrusage != NULL && error == 0) {
+		freebsd32_rusage_out(&wru.wru_self, &wru32.wru_self);
+		freebsd32_rusage_out(&wru.wru_children, &wru32.wru_children);
+		error = copyout(&wru32, uap->wrusage, sizeof(wru32));
+	}
+	if (uap->info != NULL && error == 0) {
+		siginfo_to_siginfo32 (&si, &si32);
+		error = copyout(&si32, uap->info, sizeof(si32));
+	}
+	return (error);
+}
+
 #ifdef COMPAT_FREEBSD4
 static void
 copy_statfs(struct statfs *in, struct ostatfs32 *out)
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index beb29e890bd7..18ea3a7bd29d 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -906,6 +906,33 @@ sys_wait6(struct thread *td, struct wait6_args *uap)
 	return (error);
 }
 
+int
+sys_pdwait(struct thread *td, struct pdwait_args *uap)
+{
+	struct __wrusage wru, *wrup;
+	siginfo_t si, *sip;
+	int error, status;
+
+	wrup = uap->wrusage != NULL ? &wru : NULL;
+
+	if (uap->info != NULL) {
+		sip = &si;
+		bzero(sip, sizeof(*sip));
+	} else {
+		sip = NULL;
+	}
+
+	error = kern_pdwait(td, uap->fd, &status, uap->options, wrup, sip);
+
+	if (uap->status != NULL && error == 0)
+		error = copyout(&status, uap->status, sizeof(status));
+	if (uap->wrusage != NULL && error == 0)
+		error = copyout(&wru, uap->wrusage, sizeof(wru));
+	if (uap->info != NULL && error == 0)
+		error = copyout(&si, uap->info, sizeof(si));
+	return (error);
+}
+
 /*
  * Reap the remains of a zombie process and optionally return status and
  * rusage.  Asserts and will release both the proctree_lock and the process
@@ -1476,6 +1503,84 @@ loop_locked:
 	goto loop;
 }
 
+int
+kern_pdwait(struct thread *td, int fd, int *status,
+    int options, struct __wrusage *wrusage, siginfo_t *siginfo)
+{
+	struct proc *p;
+	struct file *fp;
+	struct procdesc *pd;
+	int error;
+
+	AUDIT_ARG_FD(fd);
+	AUDIT_ARG_VALUE(options);
+
+	error = wait6_checkopt(options);
+	if (error != 0)
+		return (error);
+
+	error = fget(td, fd, &cap_pdwait_rights, &fp);
+	if (error != 0)
+		return (error);
+	if (fp->f_type != DTYPE_PROCDESC) {
+		error = EINVAL;
+		goto exit_unlocked;
+	}
+	pd = fp->f_data;
+
+	for (;;) {
+		/* We own a reference on the procdesc file. */
+		KASSERT((pd->pd_flags & PDF_CLOSED) == 0,
+		    ("PDF_CLOSED proc %p procdesc %p pd flags %#x",
+		    p, pd, pd->pd_flags));
+
+		sx_xlock(&proctree_lock);
+		p = pd->pd_proc;
+		if (p == NULL) {
+			error = ESRCH;
+			goto exit_tree_locked;
+		}
+		PROC_LOCK(p);
+
+		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;
+
+		if ((options & WNOHANG) != 0) {
+			error = EWOULDBLOCK;
+			break;
+		}
+
+		PROC_UNLOCK(p);
+		error = sx_sleep(&p->p_procdesc, &proctree_lock,
+		    PWAIT | PCATCH | PDROP, "pdwait", 0);
+		if (error != 0)
+			goto exit_unlocked;
+	}
+
+	PROC_UNLOCK(p);
+exit_tree_locked:
+	sx_xunlock(&proctree_lock);
+exit_unlocked:
+	fdrop(fp, td);
+	return (error);
+}
+
 void
 proc_add_orphan(struct proc *child, struct proc *parent)
 {
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index 4f5b08003735..ec3b37f96148 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -75,6 +75,7 @@
 #include <sys/procdesc.h>
 #include <sys/resourcevar.h>
 #include <sys/stat.h>
+#include <sys/syscallsubr.h>
 #include <sys/sysproto.h>
 #include <sys/sysctl.h>
 #include <sys/systm.h>
@@ -321,6 +322,9 @@ procdesc_exit(struct proc *p)
 	}
 	KNOTE_LOCKED(&pd->pd_selinfo.si_note, NOTE_EXIT);
 	PROCDESC_UNLOCK(pd);
+
+	/* Wakeup all waiters for this procdesc' process exit. */
+	wakeup(&p->p_procdesc);
 	return (0);
 }
 
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index 1d0608297913..8a30e5931a0e 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -3411,4 +3411,14 @@
 		);
 	}
 
+601	AUE_PDWAIT	STD|CAPENABLED {
+		int pdwait(
+		    int fd,
+		    _Out_opt_ int *status,
+		    int options,
+		    _Out_opt_ _Contains_long_ struct __wrusage *wrusage,
+		    _Out_opt_ _Contains_long_ptr_ struct __siginfo *info
+		);
+	}
+
 ; vim: syntax=off
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index 4ddd2eba25c8..e2bbbc188553 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -286,6 +286,8 @@ int	kern_posix_fallocate(struct thread *td, int fd, off_t offset,
 	    off_t len);
 int	kern_fspacectl(struct thread *td, int fd, int cmd,
 	    const struct spacectl_range *, int flags, struct spacectl_range *);
+int	kern_pdwait(struct thread *td, int fd, int *status,
+	    int options, struct __wrusage *wrusage, siginfo_t *sip);
 int	kern_procctl(struct thread *td, enum idtype idtype, id_t id, int com,
 	    void *data);
 int	kern_pread(struct thread *td, int fd, void *buf, size_t nbyte,