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
168
169
|
#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!
}
|