summaryrefslogtreecommitdiff
path: root/user/progR.c
blob: 672318ba3d75ac6f44ce25cdc4dacf34e2bd4592 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include <common.h>

/**
** User function R:   exit, sleep, write, fork, getpid, getppid,
**
** Reports itself and its sequence number, along with its PID and
** its parent's PID. It then delays, forks, delays, reports again,
** and exits.
**
** Invoked as:  userR  x  n  [ s ]
**	 where x is the ID character
**		   n is the sequence number of the initial incarnation
**		   s is the initial delay time (defaults to 10)
*/

USERMAIN(main)
{
	char ch = 'r'; // default character to print
	int delay = 10; // initial delay count
	int seq = 99; // my sequence number
	char buf[128];

	// process the command-line arguments
	switch (argc) {
	case 4:
		delay = str2int(argv[3], 10);
		// FALL THROUGH
	case 3:
		seq = str2int(argv[2], 10);
		// FALL THROUGH
	case 2:
		ch = argv[1][0];
		break;
	default:
		sprint(buf, "userR: argc %d, args: ", argc);
		cwrites(buf);
		for (int i = 0; i <= argc; ++i) {
			sprint(buf, " %s", argv[argc] ? argv[argc] : "(null)");
			cwrites(buf);
		}
		cwrites("\n");
	}

	/*
	** C oddity: a label cannot immediately precede a declaration.
	**
	** Declarations are not considered "statements" in C. Prior to
	** C99, all declarations had to precede any statements inside a
	** block. Labels can only appear before statements.  C99 allowed
	** the mixing of declarations and statements, but did not relax
	** the requirement that labels precede only statements.
	**
	** That's why the declarations of these variables occur before the
	** label, but their initializations occur after the label.
	**
	** As the PSA says on TV, "The more you know..." :-)
	*/

	int32_t pid;
	int32_t ppid;

restart:

	// announce our presence
	pid = getpid();
	ppid = getppid();

	sprint(buf, " %c[%d,%d,%d]", ch, seq, pid, ppid);
	swrites(buf);

	sleep(SEC_TO_MS(delay));

	// create the next child in sequence
	if (seq < 5) {
		++seq;
		int32_t n = fork();
		switch (n) {
		case -1:
			// failure?
			sprint(buf, "** R[%d] fork code %d\n", pid, n);
			cwrites(buf);
			break;
		case 0:
			// child
			goto restart;
		default:
			// parent
			--seq;
			sleep(SEC_TO_MS(delay));
		}
	}

	// final report - PPID may change, but PID and seq shouldn't
	pid = getpid();
	ppid = getppid();
	sprint(buf, " %c[%d,%d,%d]", ch, seq, pid, ppid);
	swrites(buf);

	exit(0);

	return (42); // shut the compiler up!
}