BSD kqueue is a mountain of technical debt (2021)

Overall view of the article and “technical debt” claim

  • Many commenters say the piece asserts that kqueue is “technical debt” without actually demonstrating it.
  • Several feel the headline is clickbait or overdramatic; the body reads more like a neutral history/comparison than proof of a “mountain of debt.”
  • Multiple people argue “technical debt” is misused and has become almost meaningless in this context.

kqueue vs epoll: design, extensibility, and composability

  • One side: epoll’s fd-centric model is seen as more composable:
    • New kernel objects just expose a file descriptor and automatically work with epoll, poll, select, and future event APIs.
    • You can pass fds between processes, read structured event data via read(), close them to free resources, and reuse generic tooling.
  • Counterpoint: kqueue’s filter model is also generic:
    • Drivers implement filters like EVFILT_READ/WRITE once, and BSDs even layer poll/select on top of kqueue internally.
    • New event types can either define new filters or reuse existing ones; no inherent need to grow kqueue itself.
    • Non-fd events (proc, timer, signal) are simpler in kqueue than Linux’s proliferation of *fd APIs.
  • Some note that Linux needed timerfd, signalfd, etc. specifically to make those things epoll-able, which others call “ugly” or its own form of debt.

Bugs, pitfalls, and “brokenness”

  • Linked critiques of epoll highlight:
    • Edge-triggered behavior that’s easy to misuse.
    • Confusing semantics around file descriptors vs open file descriptions, including events leaking across process boundaries and continuing for fds you no longer hold.
  • Others list signalfd and pidfd as messy or non-capability-based, contrasting with BSD process descriptors.

Async vs sync I/O and portability

  • Broad agreement that async I/O APIs are fragmented and hard to use portably; runtimes (libuv, language async runtimes) pay the price.
  • Debate over sync vs async:
    • Some argue synchronous I/O and threads suffice for most workloads and are easier to reason about.
    • Others counter that full-duplex protocols and high-concurrency servers push you toward async/event-driven models.

io_uring and “modern reality”

  • io_uring is discussed as a newer, ring-buffered, completion-based design:
    • Intended to reduce syscall overhead, which matters more on modern hardware and post-Spectre/Meltdown mitigations.
    • Seen as powerful but complex and security-prone; some hardened distros reportedly disable it.