#include /** ** 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! }