/**
 * File: cleanup-orders.c
 * --------------------------
 * The following program spawns off 8 children,
 * each of which returns a different exit status.
 * It then has 2 options to wait on the children
 * to finish.
 */

#include <unistd.h>     // for fork
#include <stdio.h>      // for printf
#include <sys/wait.h>   // for waitpid
#include <stdbool.h>    // for 'true'
#include <errno.h>      // for errno, ECHILD

static const int kNumChildren = 8;

void waitInForkOrder(pid_t children[], int count);
void waitInFinishOrder();


int main(int argc, char *argv[]) {
    // store all child PIDs
    pid_t children[kNumChildren];

    // Spawn kNumChildren children that just exit
    for (size_t i = 0; i < kNumChildren; i++) {
        children[i] = fork();  // omitted error checking
        if (children[i] == 0) {
            // first sleeps longest, then 1sec less, etc.
            sleep(kNumChildren - i);
            // can just return since we are in main
            return 111 + i;
        }
    }

    // Uncomment exactly one of these to test cleaning up children in different orders
    waitInForkOrder(children, kNumChildren);
    //waitInFinishOrder();  // no need to pass in PIDs

    return 0;
}

// Wait for the children in the order they were spawned
void waitInForkOrder(pid_t children[], int count) {
    for (size_t i = 0; i < count; i++) {
        int status;
        pid_t pid = waitpid(children[i], &status, 0);

        // omitted error checking to ensure pid == children[i]

        // Print out the child's exit information (omitted: checking exit status is 111 + i)
        if (WIFEXITED(status)) {
            printf("Child with PID %d exited: status %d\n", children[i], WEXITSTATUS(status));
        } else {
            printf("Child with PID %d exited abnormally.\n", children[i]);
        }
    }
}

// Wait for the children in the order they finish
void waitInFinishOrder() {
    while (true) {
        // Wait for one of our children
        int status;
        pid_t pid = waitpid(-1, &status, 0);

        /* If waitpid returns -1 and errno is ECHILD, that means no more children.
         * If waitpid returns -1 otherwise, that means an error occurred (not handled here).
         */
        if (pid == -1 && errno == ECHILD) {
            break;
        }

        // Print out the child's exit information
        if (WIFEXITED(status)) {
            printf("Child with PID %d exited: status %d\n", pid, WEXITSTATUS(status));
        } else {
            printf("Child with PID %d exited abnormally.\n", pid);
        }
    }
}
