BSD processes and the POSIX interface
This part of XNU turns Mach tasks and threads into processes with PIDs, parent/child relationships, credentials, file descriptors, signals, and system calls. It also provides event delivery and the kernel side of pthread workqueues. BSD runs in the kernel address space and calls Mach directly; it is not a separate user process serving POSIX requests.
These pages describe the supplied xnu-12377.121.6 source snapshot. Configuration guards matter: a declaration in syscalls.master does not establish that a feature is enabled in a particular shipped kernel. No running-kernel experiments or kernel build were performed for this chapter.
For descriptor storage, read filedesc tables and slot publication and fileproc/fileglob allocation and lifetime beside descriptor operations. The companions separate movable arrays, per-descriptor I/O holds, shared offsets/references, guarded variants and final endpoint close.
Read in this order
For the structures behind these operations, use the process and its protected data and the task and its shared RO data. They follow zone allocation, validated access, field updates and the two sides of final reclamation; the RO update walkthrough carries those writes into the selected pmap backend.
Thread and uthread storage follows BSD initialization, credential caches, process associations and their cleanup. Credential storage and replacement supplies the allocation, uniquing and ownership model behind UID/GID changes and exec identity publication.
- Process objects and lifetime: the initial map of
proc,task,thread, anduthread; continue with Fork, spawn, exec, exit, and wait for publication gates, failure paths, reference drains, and reaping. - System calls, signals, and exceptions: syscall entry and the exception bridge; continue with Signal posting, handler entry, and sigreturn for target selection, AST processing, ARM64 frames, and validation.
- File descriptors: allocation, replacement and close: reserved slots, table growth,
fileproc/fileglobownership, constructor publication,dup2replacement, I/O drains, guarded operations and fileport transfer. - Events, pthreads, and workqueues: the initial event/thread map; continue with Kqueue, knote, and workloop lifetimes for registration, posting, delivery, drop, owner, and servicer protocols.
- Pthread boundaries, workqueue service, and cancellation: request admission, creator selection, binding, worker reuse/parking, cancellation, join wake, and teardown.
- Asynchronous file I/O: request ownership, both worker paths, cancellation races, result consumption, and close/exec/exit drains.
- Complete BSD syscall catalog: dispatch/argument/result state, every master-table slot and conditional alternative, and each active call's purpose and local mechanism. Compare the separate Mach namespaces and AST flavor catalog.
For exec's identity changes, read Exec identity and inherited state: set-ID predicates, group membership, MAC transitions, Mach inheritance resets, descriptor repair, credential publication and task tokens follow separate decisions. Continue with Exec arguments and the initial user stack for argument extraction, interpreter rewriting, byte budgets, Apple entries and a worked ARM64 startup layout. ARM64 thread-state conversion continues the signal-return route through pointer conversion and saved-state installation.
Process inspection and snapshots follows proc_info from selectors and process identity checks into descriptor lists and typed descriptor details. Its concurrent example distinguishes a retained object during one query from identity across separate queries.
For local communication and terminals, continue with:
| Chapter | Mechanism |
|---|---|
| Pipes and UNIX socket rights | Buffer ownership, atomic writes, peer closure, descriptor transfer and collection of unreachable rights cycles |
| User-address wait and wake | Private/shared keys, protected comparison, unfair-lock inheritance, wake selection and final-waiter cleanup |
| POSIX named IPC | Named semaphore creation/wait/unlink and shared-memory name, descriptor, memory-entry and mapping lifetime |
| System V IPC | Message storage and copy failure, semaphore vectors and undo, segment IDs, attachments and removal |
| TTY and PTY lifecycle | Terminal input/output queues, canonical/raw completion, PTY dispatch, job control and hangup/reclamation |
The objects that connect the layers
Mermaid source
flowchart TB
U[Userspace: POSIX and pthread calls] --> S[BSD syscall dispatch]
S --> P[proc: PID, family, files, signal actions]
S --> UT[uthread: syscall state and pending signals]
P --- RO[proc_ro: identity and credential association]
RO --- T[Mach task: VM map and IPC space]
UT --- TH[Mach thread: scheduling and machine state]
TH --> T
P --> FD[filedesc → fileproc → fileglob]
FD --> V[Vnodes / sockets / pipes / kqueues]
V --> K[Knotes and event delivery]
K --> W[Workqueue thread requests]
W --> TH
The stable distinction is process policy versus execution mechanism. proc stores the Unix process model; task owns the Mach execution environment; thread is scheduled; uthread supplies BSD state for that thread. The implementation deliberately ties their lifetimes together without making their roles interchangeable. Current credential pointers are in thread_ro, so older descriptions placing a uu_ucred field in uthread do not match this snapshot.
| Boundary | Concrete connection | Continue reading |
|---|---|---|
| Mach execution | fork_create_child() calls task_create_internal() and creates the main thread; final Mach thread termination calls proc_exit() |
Runtime |
| Virtual memory | Fork requests memory inheritance; exec loads a new Mach-O map | VM |
| Mach IPC | Task/thread ports become accessible after initialization; exception messages become signals; workloops receive Mach-port events | IPC |
| Filesystems | Exec resolves a vnode; descriptors dispatch through fileops; filedesc holds current/root directories |
VFS |
| Networking | Socket descriptors share the descriptor machinery; local sockets transport descriptor references | Networking |
| Security | Credentials, MAC checks, executable policy, and audit hooks appear throughout process transitions | Security |
| Architecture | Trap entry and signal frames use saved machine state | Platform |
Sources inspected and limits
“Deep” below means structures and selected complete control/lifetime paths were read. It does not mean every line of these large files was audited.
| Source area | Inspection | Remaining limits |
|---|---|---|
proc_internal.h, proc_ro.h, user.h, kern_proc.c |
Deep: fields, references, PID lookup, exec drains, proc/task relationship | Process groups, personas, accounting, and all reference-debug cases were not exhaustively traced |
kern_fork.c, kern_exec.c, kern_exit.c |
Deep: creation/rollback, spawn action and credential ordering, shadow-proc exec publication/gates/failure, exit ownership, ordered teardown, wait/reap | Mach-O parser and every spawn attribute/failure branch are outside this chapter |
systemcalls.c, syscalls.master, kern_sig.c, ux_exception.c |
Deep: ARM dispatcher, restart/error return, posting/AST handling, ARM64 frame construction and sigreturn validation, exception translation | x86/ARM32 signal frames and libsyscall generation were surveyed; full ptrace/job-control behavior remains broader |
kern_descrip.c, sys_generic.c, descriptor headers |
Deep: reservation/table-growth retry, construction/publication/rollback, lookup/drop, fork copying, dup2 replacement, I/O drain and final close, selected guard predicates and fileport lifetime |
Every fcntl command, guard-change combination and endpoint-specific drain remains broader; AIO and local IPC have separate focused guides |
kern_aio.c |
Deep selected paths: request/ref ownership, validation/enqueue, both workers, completion/consumption, cancellation queue-removal race, close/exec/exit/pool drains | Every batch, fsync dependency, AIO filter, and worker-admission transition is not audited |
kern_event.c, event headers, pthread_workqueue.c, pthread_shims.c |
Deep selected paths: knote register/post/process/drop, fd close, dynamic workloop owner/servicer/retain/turnstile, requests/admission, worker creation/park/exit, pthread boundary | Every filter, work-interval/cooperative scheduling policy, and priority/parking race remains broader; external pthread implementation is absent |
sys_pipe.c, uipc_usrreq.c, sys_ulock.c |
Pipe buffering/wait/close, UNIX rights conversion and cycle collection, ulock key/compare/inheritance/wake/cleanup | Selected implementation paths, not a formal concurrency proof; userspace lock algorithms remain external |
POSIX/SysV IPC files, tty.c, tty_dev.c, tty_ptmx.c |
Named IPC namespace and backing lifetime, SysV queues/vectors/undo/attachments, TTY queues/job control and PTY teardown | Configuration-dependent IPC families; physical terminal drivers and userspace terminal emulation remain external |
The principal code-reading trap is treating historical comments as the current object layout. Confirm descriptions against declarations and executable branches: exec now replaces a proc/task pair, filedesc is embedded in proc, and some pthread operations cross a function-table boundary into separately supplied code.