cprocessoperating-systemsystemd

Why are orphaned child processes not adopted by PID 1 in Linux, like it is claimed in a book I read?


I was reading "The Linux Programming Interface" book and got to this sentence (at the end of chapter 6.2):

If a child process becomes orphaned because its “birth” parent terminates, then the child is adopted by the init process, and subsequent calls to getppid() in the child return 1.

So I wrote some code to see this. Here is the code:

#include <unistd.h>
#include <stdio.h>

int main()
{
    printf("starting...\n");

    if (fork() == 0)
    {
        printf("Child PID: %d\n",getpid());
        printf("Child PPID: %d\n",getppid());
        printf("sleeping till the parent die:(\n");
        sleep(5);
        printf("Child new PPID: %d\n",getppid());
    }
    else
    {
        printf("Parent PID: %d\n",getpid());
    }

    return 0;
}

After running the code, I've got this output:

starting...
Parent PID: 16577
Child PID: 16578
Child PPID: 16577
sleeping till the parent die:(

Child new PPID: 2754

Not only is getppid() not returning 1, it looks like PID 1 is not even the init process, but instead a systemd process. And there are multiple of them: when I ran pgrep systemd, it output, among others, 1 and 2754.

Now I'm confused and these are my questions:


Solution

  • it looks like PID 1 is not even the init process, but instead a systemd process

    The systemd process is the init process. It is not the same software as traditional init, but it still does all the functions that init would normally do (and a bit more; it's not just a straight-up reimplementation of init).

    Although the "SysV init" has historically been the most popular init for Linux, it has never been the only one – it's a distro choice, so you also had init-ng, s6, Upstart, systemd, etc.

    And there are multiple of them: when I ran pgrep systemd, it output, among others, 1 and 2754.

    Service management is not uniquely restricted to init/pid1 – though pid1 has somewhat of an advantage due to being the default parent – but it is fairly common to have a "user-level" service manager that does roughly the same thing. For example, when you log in to GNOME, the initial process there is gnome-session – which is just another kind of service manager, doing nothing but starting overseeing various other GNOME components.

    So, naturally, systemd supports a mode where it can run as an ordinary non-pid1 process and manage services for one specific user (via systemctl --user). These days a large chunk of your GUI environment components gets started this way.

    (You didn't really see it with SysV-style init because its service management features were... lacking, with practically everything done via shell tools outside init proper. But both Upstart and systemd handle services directly within pid1.)

    Therefore,

    Not only is getppid() not returning 1

    As noted in the comments, Linux now provides an API for standalone service managers to become the new default parent (reaper) for their child processes. Systemd in its "per-user" mode uses this in order to more easily deal with services that try to "daemonize" (and therefore become orphaned).