kern/user/progTUV.c

167 lines
3.5 KiB
C

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