Here's another piece of info (just because I like talking to myself
in public): I posted a question about the Solaris behavior to the
OpenSolaris bugs forum:

http://www.opensolaris.org/jive/thread.jspa?threadID=14188

Martin Sebor wrote:
Martin Sebor wrote:

I took a closer look at the output produced by my little test program
(after making a small change to it where I moved the sleep(1) call in
the parent branch immediately above the waitpid call). Here's the
behavior I have observed on each of the following operating systems:


Here's a corrected interpretation of the results (the corrected
program is attached):

AIX:      only immediate children's times are returned
HP-UX:    only immediate children's times are returned
IRIX 6.5: only immediate children's times are returned
Linux:    only immediate children's times are returned
Solaris:  cumulative times of children and all their
          descendants are returned
Tru64:    only immediate children's times are returned

I was misled by the rapidly decreasing user times in test runs
that created increasing numbers of grandchildren. The decreasing
numbers actually make sense since more processes compete for the
CPU and thus get to use it less time (with the OS spending more
of its own time switching between them).

So I guess the only odd duck is Solaris which accumulates the
time used up by the child's children's despite the fact that
they were never waited on.

Martin


------------------------------------------------------------------------

#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

static void
print_usage (int who, int status)
{
    struct rusage usage = { 0 };
    getrusage (who, &usage);
    printf ("child exit status: %d\n"
            "usr time: %lu.%06lu\n"
            "sys time: %lu.%06lu\n",
            status,
            usage.ru_utime.tv_sec , usage.ru_utime.tv_usec,
            usage.ru_stime.tv_sec , usage.ru_stime.tv_usec);
}

int main (int argc, char *argv[])
{
    unsigned long signo = 1 < argc ? strtoul (argv [1], 0, 10) : 0;
    unsigned long nsec  = 2 < argc ? strtoul (argv [2], 0, 10) : 0;
    unsigned long nproc = 3 < argc ? strtoul (argv [3], 0, 10) : 0;
    unsigned long alrm  = 4 < argc ? strtoul (argv [4], 0, 10) : 0;
    pid_t child_id;

    printf ("child spawns %lu grandchildren in the same process group\n"
            "each child process sets a %lu second alarm and loops forever\n"
            "parent sleeps %lu seconds before sending signal %lu to group\n",
            nproc, alrm, nsec, signo);

    child_id = fork ();

    if (child_id) {
        int status;
        sleep (nsec);
        if (kill (-child_id, signo))
            fprintf (stderr, "kill(%d, %d) failed: %s\n",
                     -child_id, signo, strerror (errno));

        sleep (1);
        if (0 > waitpid (child_id, &status, 0))
            fprintf (stderr, "waitpid(%d, %p, 0) failed: %s\n",
                     child_id, &status, strerror (errno));

        while (nproc-- && 0 == kill (-child_id, signo));

        print_usage (RUSAGE_CHILDREN, status);
    }
    else {
        setsid ();

        if (10 < nproc)
            nproc = 10;

        while (nproc--)
            if (0 == fork ())
                break;

        alarm (alrm);

        for ( ; ; );
    }

    return 0;
}

Reply via email to