$RodHat_

Topic · 18 articles

File Descriptors & IPC

The Unix promise was that everything is a file. For forty years that was a lie about processes, timers, signals, and anonymous memory. Linux spent the 2.6 and 5.x series quietly making it true, and the result is that most of the races you papered over with PID files and self-pipes now have a proper fd-based answer.

Start with pidfd and fd passing, because they change how you think about handles. Then the event fds, which kill the self-pipe trick. Then the zero-copy calls, which move data without it ever touching your buffers. The Tales at the bottom are what happens when nobody on the team knows any of this.

Start here

Read these first, in this order.

  1. 01

    Tip · 2026-08-26

    pidfd: Unix finally has a handle on your processes (only took 50 years)

    Since Linux 5.3, pidfd_open() returns a file descriptor that refers to a specific process, not a PID number. File descriptors don't get recycled. The race you've been papering over with SIGCHLD handlers for decades is now actually fixable.

  2. 02

    Tip · 2026-09-02

    SCM_RIGHTS: send an open file descriptor to another process over a Unix socket

    You can pass a live, open file descriptor to another process via Unix domain socket ancillary data. Not a path, not a number — the actual kernel file description, with whatever offset and flags it already has. The mechanism is POSIX, predates Linux, and almost nobody uses it directly.

  3. 03

    Tip · 2026-08-27

    memfd_create and file sealing: an anonymous file nobody can modify (including you)

    memfd_create() gives you a file descriptor backed by anonymous memory, with no filesystem, no path, no name. Add F_SEAL_WRITE and the kernel refuses all future write access. Pass it across process boundaries via SCM_RIGHTS or pidfd_getfd. It's the right way to share immutable data between processes.

  4. 04

    Tip · 2026-08-31

    close_range: one syscall instead of a million EBADFs

    Linux 5.9 finally shipped what FreeBSD had since 8.0. close_range() closes or cloexec-marks a range of file descriptors atomically. The old pre-exec fd cleanup loop burning a million close() calls is dead. Here is how to use it.

  5. 05

    Tip · 2026-09-04

    timerfd, signalfd, eventfd: every event source is a file descriptor now

    Linux 2.6 added three syscalls that turn timers, signals, and counters into readable file descriptors. The self-pipe trick can finally die. Here is the correct way to fold timers and signals into an epoll loop without writing a single signal handler.

  6. 06

    Tip · 2026-09-01

    splice and tee: zero-copy data movement, 2.6.17 edition

    splice(2) and tee(2) have been in Linux since 2006. They move data through the kernel page cache without a userspace copy. How to use them for log fanout, network sends, and pipeline work that does not belong in the era of read/write loops.

The syscalls underneath

Version introduced, sourced from the man page. Full cards in the syscall reference, or check your kernel.

InterfaceSinceWhat it does
pidfd_open(2)Linux 5.3Get a file descriptor that refers to a process, immune to PID reuse.
pidfd_send_signal(2)Linux 5.1Send a signal to the process a pidfd refers to, without PID-reuse races.
pidfd_getfd(2)Linux 5.6Duplicate a file descriptor out of another process, addressed by its pidfd.
SCM_RIGHTSunknownPass open file descriptors to another process over a UNIX domain socket.
memfd_create(2)Linux 3.17Create an anonymous RAM-backed file with no path, optionally sealable.
close_range(2)Linux 5.9Close, or mark close-on-exec, every file descriptor in a range in one call.
timerfd_create(2)Linux 2.6.25Create a timer that reports expirations through a readable file descriptor.
signalfd(2)Linux 2.6.22Accept signals by reading a file descriptor instead of running a handler.
eventfd(2)Linux 2.6.22Create a kernel-backed 64-bit counter fd for wakeups between threads or processes.
splice(2)Linux 2.6.17Move data between a pipe and another fd without copying through userspace.
tee(2)Linux 2.6.17Duplicate data from one pipe into another without consuming it from the source.
copy_file_range(2)Linux 4.5Copy a range of bytes between two file descriptors entirely inside the kernel, with server-side offload on NFS 4.2 and reflink on btrfs.
statx(2)Linux 4.11Extended stat: request specific fields, get birth time, inode attribute flags and mount ID.
fanotify_init(2)Linux 2.6.37Create an fanotify group: VFS-level file access events with live fds and blockable opens.
fsopen(2)Linux 5.2Open a filesystem context: step one of the fd-based mount API (fsconfig, fsmount, move_mount).
futex(2)Linux 2.6.0Fast userspace locking: wait on or wake threads sleeping on a 32-bit word in memory.

More console tips (8)

Rod's tales (4)

Other topics