The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=4d707825bf62ee73a32b615846eff9c4a9bda538
commit 4d707825bf62ee73a32b615846eff9c4a9bda538 Author: Konstantin Belousov <[email protected]> AuthorDate: 2026-01-08 03:37:42 +0000 Commit: Konstantin Belousov <[email protected]> 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,
