xv6, line by line
user/forktest.c

user/forktest.c

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

About this file

forktest is a stress test for the process table. It calls fork until the kernel refuses, then checks that the kernel refused gracefully: fork returned -1 instead of crashing or handing out a slot twice, and every child that was created can be collected with wait, no more and no fewer.

The table has NPROC = 64 slots (kernel/param.h). Each child exits at once, but an exited child stays a zombie, still holding its slot, until its parent calls wait. Since the parent does not wait during the loop, the table fills up. With only init, sh and forktest running, exactly 61 forks succeed (64 − 3) before allocproc finds no UNUSED slot and returns 0 (kernel/proc.c:122), so kfork returns -1.

The program is built differently from every other user program: the Makefile links it with only ulib.o and usys.o (no printf, no malloc) and without the user linker script (Makefile:117; see the note there). That is why it defines its own print.

Expected output:

$ forktest
fork test
fork test OK

Read before: user/zombie.c. Read next: kernel/proc.c (kfork, kwait); user/usertests.c has a similar test with the same name.

1// Test that fork fails gracefully.
2// Tiny executable so that the limit can be filling the proc table.
8#define N 1000
10void
11print(const char *s)
13 write(1, s, strlen(s));
16void
19 int n, pid;
21 print("fork test\n");
23 for (n = 0; n < N; n++) {
24 pid = fork();
25 if (pid < 0)
26 break;
27 if (pid == 0)
28 exit(0);
29 }
31 if (n == N) {
32 print("fork claimed to work N times!\n");
33 exit(1);
34 }
36 for (; n > 0; n--) {
37 if (wait(0) < 0) {
38 print("wait stopped early\n");
39 exit(1);
40 }
41 }
43 if (wait(0) != -1) {
44 print("wait got too many\n");
45 exit(1);
46 }
48 print("fork test OK\n");
51int
52main(void)
55 exit(0);