xv6, line by line
user/init.c

user/init.c

C · 54 lines · annotated 100% · user program / library · upstream

About this file

/init is the first user program, process 1. The kernel creates its process in userinit and loads this program into it in forkret (kernel/proc.c:532); every other process descends from it.

It has two jobs:

  1. Give the system a console. It opens the console device as descriptors 0, 1 and 2 (standard input, output and error). Every later process inherits these through fork, which is why programs can print without opening anything.
  2. Keep a shell running and reap orphans. It starts /sh, then waits forever. When the shell exits it starts a new one. Meanwhile its wait also collects every process whose parent died first, which the kernel hands to init (reparent). Without this, such processes would stay zombies forever.

init must never exit: kexit panics the whole kernel if it tries.

Read before: kernel/proc.c (userinit, kwait, reparent). Read next: user/sh.c.

1// init: The initial user-level program
12char *argv[] = {"sh", 0};
14int
15main(void)
17 int pid, wpid;
19 if (open("console", O_RDWR) < 0) {
20 mknod("console", CONSOLE, 0);
21 open("console", O_RDWR);
22 }
23 dup(0); // stdout
24 dup(0); // stderr
26 for (;;) {
27 printf("init: starting sh\n");
28 pid = fork();
29 if (pid < 0) {
30 printf("init: fork failed\n");
31 exit(1);
32 }
33 if (pid == 0) {
34 exec("sh", argv);
35 printf("init: exec sh failed\n");
36 exit(1);
37 }
39 for (;;) {
40 // this call to wait() returns if the shell exits,
41 // or if a parentless process exits.
42 wpid = wait((int *)0);
43 if (wpid == pid) {
44 // the shell exited; restart it.
45 break;
46 } else if (wpid < 0) {
47 printf("init: wait returned an error\n");
48 exit(1);
49 } else {
50 // it was a parentless process; do nothing.
51 }
52 }
53 }