I’ve spent some time over the last few weeks reading about the various *nix init systems: venerable SysV, interim replacement Upstart, controversial monolith systemd, Apple’s proprietary launchd, and niche variants like runit and Epoch. Lots of history, lots of flame wars.
One key takeaway: socket activation is a breathtakingly elegant way to parallelize system startup. In every modern operating system, boot consists of starting hundreds of processes and waiting for them to initialize. Most depend on each other, and many init systems encode these dependencies by hand, waiting for each process to initialize completely before starting the next. Not surprisingly, this is heavyweight, slow, and a maintenance burden.
The key insight was that processes generally interact with each other over sockets, usually AF_UNIX (ie files), occasionally AF_INET and others. If a process isn’t yet listening on a socket, connecting to it will fail, so a given process can’t start until the processes it depends on are ready and listening.
As usual in computer science, the solution was adding a level of indirection. If a process attempts to connect to a socket that isn’t ready, don’t fail! Instead, accept the connection, buffer any data the process sends, and when it tries to read, block it. When a service later listens on the socket, connect the blocking client, forward the buffered data, and let things continue like normal.
This does two things. First, it lets you start more processes in parallel, which speeds up startup. Second, it removes much of the need to hand-code dependencies, especially their orderings. If a process can naturally block until its dependencies start, there’s no harm in starting it early, and no need to know exactly which processes to start when.
This isn’t a new idea. inetd did this for network-facing services way back in 1986. launchd has used it to speed up Mac OS startup times for decades. And now systemd does it in more and more Linux distros.
At this point, I’m obliged to note that systemd has provoked a debate in the Linux community that has only snowballed over time. It’s probably good software, but it’s gradually taken over more and more functionality that was historically provided by other services, contrary to the beloved Unix philosophy “do one thing well.”
I have no idea which side is right. I just know that socket activation is a beautiful solution to a hard problem. Sometimes, that’s enough.