pidfd_open(2)
Get a file descriptor that refers to a process, immune to PID reuse.
- Since
- Linux 5.3check your kernel →
- glibc
- glibc 2.36
- System
- Linux
- Man page
- pidfd_open(2)
Synopsis
#include <sys/syscall.h>
#include <unistd.h>
int syscall(SYS_pidfd_open, pid_t pid, unsigned int flags);Rod's take
A PID is a number the kernel will hand to someone else the moment your child dies, and kill(2) has trusted that number since Edition 6. pidfd_open gives you a reference instead. Poll it, signal it, waitid(P_PIDFD) on it, and you're talking to the process you meant, not whatever inherited the slot. Fine print: open it after fork() and it's only race-free if nobody else reaped the child and SIGCHLD isn't ignored; otherwise use clone3 with CLONE_PIDFD. PIDs for logging, pidfds for control. Fifty years late, but correct.
Flags and arguments that matter
| Name | What it does |
|---|---|
| PIDFD_NONBLOCKLinux 5.10 | waitid(2) on the fd returns EAGAIN instead of blocking if the task hasn't terminated. |
| PIDFD_THREADLinux 6.9 | Refer to a specific thread rather than a thread-group leader. |
| poll/epoll | The fd turns readable (EPOLLIN) when the process exits and becomes a zombie; EPOLLHUP once it is reaped. |
| waitid(P_PIDFD) | If the pidfd refers to your child, wait on it by fd instead of by PID. |
Errors you will actually hit
| errno | Meaning |
|---|---|
| ESRCH | The process specified by pid does not exist. |
| EINVAL | flags is not valid, or pid is not valid. |
| EMFILE | Per-process open file descriptor limit reached. |
| ENODEV | The anonymous inode filesystem is not available in this kernel. |
Example
int pfd = syscall(SYS_pidfd_open, pid, 0);
if (pfd < 0)
err(1, "pidfd_open"); /* ESRCH: already gone */
struct pollfd p = { .fd = pfd, .events = POLLIN };
poll(&p, 1, -1); /* readable once it exits */
siginfo_t info = {0};
waitid(P_PIDFD, pfd, &info, WEXITED); /* only if it's your child */
close(pfd);Trimmed from the full walkthrough in pidfd: Unix finally has a handle on your processes (only took 50 years).
BSD equivalent
FreeBSD: process descriptors created at fork time with pdfork(2), plus pdgetpid(2) and EVFILT_PROCDESC in kqueue(2) (FreeBSD 9.0). OpenBSD: none.
The long version, from the console
Sources
- pidfd_open(2), man7.org
- pdfork(2), FreeBSD
- kqueue(2), FreeBSD
- glibc 2.36 NEWS (pidfd_open, pidfd_getfd, pidfd_send_signal added)
Version numbers are read off the cited man pages, not memory. Spot one that's wrong? Tell Rod.
