Search code examples
unixinitprocess-management

Does the UNIX init process always run


I have a question regarding how the init process in UNIX works. As i understand it the init process is the first to start and then other processes fork off it.

Say we start the init process then fork a child process which we call exec on with a new program which happens to cause the child to wait for some I/O input. Now the parent init process could wait on the child but if it did that then there are no other processes to be run. Conversely if the init process does not wait and instead falls into a waiting loop or something then when the child is resumed the parent is now taking up processor time doing nothing.

What is the best way to manage this problem? Should the init process simply always run an infinite loop and we not worry about the wasted resources? Or is there a better way.

Any help would be much appreciated, Ben


Solution

  • Process 1 must never exit; many (all?) implementations of Unix will force a system crash if it does.

    However, process 1 doesn't need to do anything more than this (I'm assuming the kernel opens fds 0, 1, and 2 on the console before transferring control to user space - check your kernel's documentation for that and other details of the bootstrap environment, if you're actually gonna write init yourself):

    #include <sys/types.h>
    #include <sys/wait.h>
    #include <unistd.h>
    #include <stdio.h>
    
    int main(void)
    {
        pid_t child = fork();
        if (child == -1) {
            perror("init: fork");
            return 1;
        }
        if (child == 0) {
            execl("/etc/rc", "/etc/rc", (char*)0);
            perror("/etc/rc");
            return 1;
        }
        for (;;)
            wait(0);
    }
    

    After starting /etc/rc it does go into an infinite loop, calling wait over and over again, and throwing away the results. But wait is a blocking system call. Each time it's called the kernel will take the CPU away from process 1 and give it to a process that has useful work to do; wait will only return when there is an exited child to report. (If there are no processes with useful work to do, the CPU will be put into a low-power "sleep" state until some external event, e.g. a human typing on the keyboard or a network packet arriving, gives a running process some work to do.)

    With this minimal init, it is entirely /etc/rc's responsibility to start up all of the programs needed to make the computer do something useful, and those programs' responsibility to keep running as long as needed; if it should come to pass that every process other than this one exits, it'll just sleep in wait forever. More sophisticated implementations will do more, e.g. restarting network servers if they crash.