PDFORK(2)
π¦ PDFORK(2) β the process descriptor situation, explained by your resident Unix girlie
okay so this one is from the System Calls Manual and honestly? it's giving "your child process but make it a file descriptor" π stay with me bestie, it's actually so good.
π LIBRARY π
Standard C Library (libc, -lc) β the usual ride-or-die.
β¨ SYNOPSIS β¨
#include <sys/procdesc.h>
pid_t
pdfork(int *fdp, int pdflags);
pid_t
pdrfork(int *fdp, int pdflags, int rfflags);
int
pdgetpid(int fd, pid_t *pidp);
int
pdkill(int fd, int signum);
int
pdwait(int fd, int *status, int options, struct __wrusage *wrusage,
struct __siginfo *info);
π DESCRIPTION π
okay so process descriptors are these iconic special file descriptors that literally represent processes. you make one with pdfork() β it's a variant of fork(2) β and if it works, it drops a process descriptor into the integer that fdp points at. π₯
the big slay here: processes created via pdfork() will not cause SIGCHLD on termination. no cap.
pdfork() accepts these pdflags:
PD_DAEMONβ instead of the default "terminate on close" behaviour, this lets the process live until it gets explicitly killed withkill(2). main character energy, honestly.
heads up bestie: this option is not permitted incapsicum(4)capability mode (go look atcap_enter(2)).
PD_CLOEXECβ sets close-on-exec on the process descriptor.
pdrfork() is the variant of pdfork() that also takes the rfflags argument, which controls how process resources get shared between the caller and the new process. like pdfork(), it writes the process descriptor referencing the created process into the location fdp points to. for the full rundown of possible rfflag flags, see rfork(2). β
β οΈpdrfork()requires that you specify both theRFPROCandRFPROCDESCflags, or theRFSPAWNflag. no vibes-based guessing allowed.
pdgetpid() queries the process ID (PID) inside the process descriptor fd. cute little lookup, love that for us. π«Ά
pdkill() is functionally identical to kill(2), except it takes a process descriptor fd instead of a PID. same energy, different paperwork.
pdwait() lets the calling thread wait and retrieve the status info on the process referenced by the fd process descriptor. for the behaviour spec, see the description of the wait6 system call. π
the following system calls also have effects that are specific to process descriptors:
fstat(2)queries the status of a process descriptor. currently only thest_mode,st_birthtime,st_atime,st_ctimeandst_mtimefields are defined. and here's the cute trick: if the owner read, write, and execute bits are set, then the process represented by the process descriptor is still alive. π«poll(2)andselect(2)let you wait for process state transitions. currently onlyPOLLHUPis defined, and it gets raised when the process dies. process state transitions can also be monitored with thekqueue(2)filterEVFILT_PROCDESC; currently onlyNOTE_EXITis implemented.close(2)closes the process descriptor unlessPD_DAEMONis set. if the process is still alive and this is the last reference to the process descriptor, the process gets terminated with the signalSIGKILL. π and ngl this part matters: the PID of the referenced process is not reused until the process descriptor is closed β whether or not the zombie process is reaped bypdwait(),wait6, or similar system calls.
πΈ RETURN VALUES πΈ
pdfork() and pdrfork() return a PID, 0 or -1, exactly as fork(2) does. classic.
pdgetpid(), pdkill(), and pdwait() return 0 on success and -1 on failure.
π₯ ERRORS π₯
these functions may return the same error numbers as their PID-based equivalents (e.g. pdfork() may return the same error numbers as fork(2)), plus these additions:
[EFAULT]β the copyout of the resulting file descriptor value to the memory pointed to byfdpfailed.
π okay this one is a whole thing. note that the child process was already created when this condition is detected, and the child continues execution, same as the parent. if you actually need to handle this error, it's advisable to memoize thegetpid()result before the call topdfork()orpdrfork(), and compare it to the value returned bygetpid()after, so you can see whether code is executing in the parent or the child. fr fr, do not skip this.
[EINVAL]β the signal number given topdkill()is invalid.[ENOTCAPABLE]β the process descriptor being operated on has insufficient rights (e.g.CAP_PDKILLforpdkill()).
π SEE ALSO π
close(2), fork(2), fstat(2), kill(2), kqueue(2), poll(2), wait4(2), capsicum(4), procdesc(4)
π HISTORY π
pdfork(), pdgetpid(), and pdkill() first appeared in FreeBSD 9.0. pdrfork() and pdwait() first appeared in FreeBSD 15.1.
support for process descriptors mode was developed as part of the TrustedBSD Project. π§
π AUTHORS π
these functions and the capability facility were created by Robert N. M. Watson <rwatson@FreeBSD.org> and Jonathan Anderson <jonathan@FreeBSD.org> at the University of Cambridge Computer Laboratory, with support from a grant from Google, Inc. the pdrfork() and pdwait() functions were developed by Konstantin Belousov <kib@FreeBSD.org> with input from Alan Somers <asomers@FreeBSD.org>. absolute legends, all of them. π«Ά
and that's the whole page bestie, ily, go fork responsibly π β¨
this slice of Debian-flavoured wisdom is dated April 19, 2026, and yes, the page itself is PDFORK(2) β now go read procdesc(4) and text me later π
π¦ where this page comes from
- freebsd 15.1: base 15.1
- Copyright (c) 2009-2010, 2012-2013 Robert N. M. Watson
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms