summaryrefslogtreecommitdiff
path: root/user/progTUV.c
blob: 8e69a663aaa2cb22d73a8330768721b0a42d3a93 (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
#include <common.h>

/**
** User function main #6:  exit, fork, exec, kill, waitpid, sleep, write
**
** Reports, then loops spawing userW, sleeps, then waits for or kills
** all its children.
**
** Invoked as:  main6  x  c  b
**	 where x is the ID character
**		   c is the child count
**		   b is wait/kill indicator ('w', 'W', or 'k')
*/

#ifndef MAX_CHILDREN
#define MAX_CHILDREN 50
#endif

USERMAIN(main)
{
	int count = 3; // default child count
	char ch = '6'; // default character to print
	int nap = 8; // nap time
	bool_t waiting = true; // default is waiting by PID
	bool_t bypid = true;
	char buf[128];
	uint_t children[MAX_CHILDREN];
	int nkids = 0;
	char ch2[] = "*?*";

	// process the command-line arguments
	switch (argc) {
	case 4:
		waiting = argv[3][0] != 'k'; // 'w'/'W' -> wait, else -> kill
		bypid = argv[3][0] != 'w'; // 'W'/'k' -> by PID
		// FALL THROUGH
	case 3:
		count = str2int(argv[2], 10);
		// FALL THROUGH
	case 2:
		ch = argv[1][0];
		break;
	default:
		sprint(buf, "main6: 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");
	}

	// fix the secondary output message (for indicating errors)
	ch2[1] = ch;

	// announce our presence
	write(CHAN_SIO, &ch, 1);

	// set up the argument vector
	char *argsw[] = { "userW", "W", "10", "5", NULL };

	for (int i = 0; i < count; ++i) {
		int whom = spawn(ProgW, argsw);
		if (whom < 0) {
			swrites(ch2);
		} else {
			children[nkids++] = whom;
		}
	}

	// let the children start
	sleep(SEC_TO_MS(nap));

	// collect exit status information

	// current child index
	int n = 0;

	do {
		int this;
		int32_t status;

		// are we waiting for or killing it?
		if (waiting) {
			this = waitpid(bypid ? children[n] : 0, &status);
		} else {
			// always by PID
			this = kill(children[n]);
		}

		// what was the result?
		if (this < SUCCESS) {
			// uh-oh - something went wrong

			// "no children" means we're all done
			if (this != E_NO_CHILDREN) {
				if (waiting) {
					sprint(buf, "!! %c: waitpid(%d) status %d\n", ch,
						   bypid ? children[n] : 0, this);
				} else {
					sprint(buf, "!! %c: kill(%d) status %d\n", ch, children[n],
						   this);
				}
			} else {
				sprint(buf, "!! %c: no children\n", ch);
			}

			// regardless, we're outta here
			break;

		} else {
			// locate the child
			int ix = -1;

			// were we looking by PID?
			if (bypid) {
				// we should have just gotten the one we were looking for
				if (this != children[n]) {
					// uh-oh
					sprint(buf, "** %c: wait/kill PID %d, got %d\n", ch,
						   children[n], this);
					cwrites(buf);
				} else {
					ix = n;
				}
			}

			// either not looking by PID, or the lookup failed somehow
			if (ix < 0) {
				int i;
				for (i = 0; i < nkids; ++i) {
					if (children[i] == this) {
						ix = i;
						break;
					}
				}
			}

			// if ix == -1, the PID we received isn't in our list of children

			if (ix < 0) {
				// didn't find an entry for this PID???
				sprint(buf, "!! %c: child PID %d term, NOT FOUND\n", ch, this);

			} else {
				// found this PID in our list of children
				if (ix != n) {
					// ... but it's out of sequence
					sprint(buf, "== %c: child %d (%d,%d) status %d\n", ch, ix,
						   n, this, status);
				} else {
					sprint(buf, "== %c: child %d (%d) status %d\n", ch, ix,
						   this, status);
				}
			}
		}

		cwrites(buf);

		++n;

	} while (n < nkids);

	exit(0);

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