pidfd Prevents PID Reuse From Becoming an Authorization Bug
Unix process identifiers are small integers, and the kernel reuses them. A monitoring agent that records PID 4242, waits for a user decision and later sends a signal to PID 4242 may act on a different process. The same mistake appears in cleanup routines, supervisors and administrative tools. A PID is a lookup key for the current process table, not a durable process identity.
Linux PID file descriptors address that gap. pidfd_open() returns a descriptor tied to a specific task. Operations such as poll(), epoll, pidfd_send_signal() and waitid() can use it without another lookup by number. If the original task exits, the descriptor continues to identify that exited task rather than silently pointing to a reused PID.
The mechanism changes how a program should be structured. Store the pidfd when the process is identified. Monitor it for exit. Use it for the later signal or wait operation. If the pidfd cannot be obtained at identification time, the program still has a race between reading /proc and opening the descriptor. Obtaining the descriptor from clone() or another controlled process-creation path avoids that gap.
int pfd = syscall(SYS_pidfd_open, pid, 0); if (pfd < 0) { perror("pidfd_open"); exit(1); } A pidfd is not a capability that bypasses credential checks. The caller still needs permission to signal or inspect the target. Container and user-namespace boundaries still apply. The descriptor should carry O_CLOEXEC, and the service should close it when the lifecycle record is complete.
One subtle issue is process versus thread identity. A PID file descriptor can refer to a thread or a thread-group leader depending on how it was obtained. Monitoring code should know whether it is tracking a thread or the group. Sending a signal can likewise target the process or group according to the operation. Mixing those concepts produces behavior that looks intermittent because thread IDs are also reused.
Error handling should distinguish "the process already exited" from a permission failure or an unsupported kernel feature. A supervisor can treat exit as a normal state transition. Permission failure needs an operator response. A feature-probe failure needs a fallback that does not quietly restore PID-number signaling.
PID reuse is rare enough to survive casual testing and common enough to appear in long-running systems. A deterministic test should create child processes in a loop, keep the pidfd, terminate the child and verify that later operations are tied to the recorded process rather than a new child that receives the same number.
The design rule is to make process identity explicit in the state model. Keep the pidfd beside the job record, report its lifetime and close it deliberately. A numeric PID can remain useful for display and logs, but it should not be the authority for a delayed action.
