Projet_SETI_RISC-V/riscv-gnu-toolchain/gdb/gprofng/testsuite/gprofng.display/synprog/synprog.c
2023-03-06 14:48:14 +01:00

1823 lines
47 KiB
C

/* Copyright (C) 2021 Free Software Foundation, Inc.
Contributed by Oracle.
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, 51 Franklin Street - Fifth Floor, Boston,
MA 02110-1301, USA. */
/* synprog.c - synthetic program to use for testing performance tools */
#define _GNU_SOURCE
#include <sched.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/ucontext.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <sched.h>
#include <sys/resource.h>
#include <string.h>
#include <sys/mman.h>
#include <dlfcn.h>
#include <fcntl.h>
#include "stopwatch.h"
int get_ncpus ();
int get_clock_rate ();
void acct_init (char *); /* initialize accounting */
void iotrace_init (char *); /* initialize IO trace accounting */
void commandline (char *); /* routine execute a scenario */
void forkcopy (char *, int); /* fork copy of self to run string */
int clonecopy (void *);
#define CLONE_STACK_SIZE 8388608
#define CLONE_TLS_SIZE 4096
#define CLONE_RED_SIZE 4096
#define CLONE_IO 0x80000000 /* Clone io context */
void forkchild (char *); /* fork child to run string */
void reapchildren (void); /* reap all children */
void reapchild (int); /* reap a child after getting SIGCLD */
void check_sigmask (); /* check that SIGPROF and SIGEMT are not masked */
void masksig (); /* real code to mask SIGPROF and SIGEMT */
hrtime_t progstart;
hrtime_t progvstart;
hrtime_t gethrustime ();
static int include_system_time = 0;
static hrtime_t
getmyvtime ()
{
if (include_system_time == 0)
return gethrvtime ();
return gethrustime ();
}
void (*sigset (int sig, void (*disp)(int)))(int);
#define ITIMER_REALPROF ITIMER_REAL
/* Linux needs to have this defined for RTLD_NEXT and RTLD_DEFAULT */
/* If the first argument of `dlsym' or `dlvsym' is set to RTLD_NEXT */
#define RTLD_NEXT ((void *) -1l)
/* If the first argument to `dlsym' or `dlvsym' is set to RTLD_DEFAULT */
#define RTLD_DEFAULT ((void *) 0)
FILE *fid;
FILE *fid2;
double testtime = 3.0;
static char acct_file[128];
static char new_name[128];
static char child_name[128];
/* descendant process tracking */
static unsigned syn_fork = 0;
static unsigned syn_exec = 0;
static unsigned syn_combo = 0;
/* various behavior routines */
int bounce (int); /* bounce with a->b->a->b-> ... */
int callso (int); /* so load test */
int callsx (int); /* alternate so load test */
int correlate (int); /* test correlation with profiling */
int cputime (int); /* use a bunch of user cpu time (fp) */
int doabort (int); /* force a SEGV by dereferencing NULL */
int dousleep (int); /* loop with a usleep call */
int endcases (int); /* test various code construct endcases */
int fitos (int); /* test various code construct endcases */
int gpf (int); /* show gprof fallacy */
int hrv (int); /* gethrvtime calls */
int icputime (int); /* use a bunch of user cpu time (long) */
int iofile (int); /* do operations on a temporary file */
int iotest (int); /* do various io system calls */
int ioerror (int); /* do various erroneous io system calls */
int ldso (int); /* use a bunch of time in ld.so */
int masksignals (int); /* mask the SIGEMT and SIGPROF signals */
int memorymap (int); /* do mmap operation for io tracing */
int muldiv (int); /* do integer multiply/divide for a time */
int naptime (int); /* sleep for a time */
int pagethrash (int); /* thrash around in memory */
int recurse (int); /* recursion test */
int recursedeep (int); /* deep recursion test */
int sched (int); /* loop over sched_yield calls */
int sigtime (int); /* use a bunch of time in a signal handler */
int synccall (int); /* loop over sync() system calls */
int systime (int); /* use a bunch of system time */
int tailcallopt (int); /* tail call optimization test */
int underflow (int); /* force underflow arithmetic */
int unwindcases (int); /* test various unwind corner cases */
int itimer_realprof (int); /* mess with itimer ITIMER_REALPROF */
int sigprof (int); /* mess with SIGPROF sigaction */
int sigprofh (int); /* mess with SIGPROF handler */
int do_chdir (int); /* do a chdir() */
int do_exec (int); /* do an exec() call */
int do_popen (int); /* do a popen() call */
int do_system (int); /* do a system() call */
int do_forkexec (int); /* do a fork()+exec() call combo */
int
do_vforkexec (int); /* do a vfork()+exec() call combo */
/* lookup table for behavior scripts */
struct scripttab
{
char *name;
int (*function)(int);
char *acctname;
int param;
int noverify;
};
static int CLONE_FLAGS[] = {
SIGCHLD,
CLONE_FILES | CLONE_FS | CLONE_SYSVSEM | CLONE_IO | SIGCHLD
};
/* the default script */
static char DEFAULT_COMMAND[] =
"icpu.md.cpu.rec.recd.dousl.gpf.fitos.ec.tco.b.nap.uf."
"sys.sig.so.sx.so.sched.uwdc";
struct scripttab scripttab[] = {
{"abt", doabort, "doabort", 0, 0},
{"b", bounce, "bounce", 0, 0},
{"c", correlate, "correlate", 0, 0},
{"chdir", do_chdir, "chdir", 0, 0},
{"chdirX", do_chdir, "chdir", -1, 0},
{"cpu", cputime, "cputime", 0, 0},
{"dousl", dousleep, "dousleep", 0, 1},
{"ec", endcases, "endcases", 0, 0},
{"exec", do_exec, "exec", 0, 0},
{"execX", do_exec, "do_exec", -1, 0},
{"fitos", fitos, "fitos", 0, 1},
{"gpf", gpf, "gpf", 0, 0},
{"hrv", hrv, "hrv", 0, 0},
{"icpu", icputime, "icputime", 0, 0},
{"iofile", iofile, "iofile", 0, 0},
{"iotest", iotest, "iotest", 0, 0},
{"ioerror", ioerror, "ioerror", 0, 0},
{"itimer", itimer_realprof, "itimer", 1, 0},
{"itimer0", itimer_realprof, "itimer", 0, 0},
{"ldso", ldso, "ldso", 0, 0},
{"masksig", masksignals, "masksig", 0, 0},
{"md", muldiv, "muldiv", 0, 0},
{"memorymap", memorymap, "memorymap", 100, 0},
{"nap", naptime, "naptime", 0, 0},
{"pg", pagethrash, "pagethrash", 32, 0},
{"popen", do_popen, "popen", 0, 0},
{"popenX", do_popen, "popen", -1, 0},
{"rec", recurse, "recurse", 50, 0},
{"recd", recursedeep, "<Truncated-stack>", 500, 0},
{"sched", sched, "sched", 0, 1},
{"so", callso, "callso", 0, 0},
{"sx", callsx, "callsx", 0, 0},
{"sig", sigtime, "sigtime", 0, 1},
{"sigprof", sigprof, "sigprof", 1, 0},
{"sigprof0", sigprof, "sigprof", 0, 0},
{"sigprofh", sigprofh, "sigprofh", 1, 0},
{"sigprofh0", sigprofh, "sigprofh", 0, 0},
{"sync", synccall, "synccall", 0, 1},
{"sys", systime, "systime", 0, 1},
{"system", do_system, "system", 0, 0},
{"systemX", do_system, "do_system", -1, 0},
{"tco", tailcallopt, "tailcallopt", 0, 0},
{"uf", underflow, "underflow", 0, 1},
{"forkexec", do_forkexec, "forkexec", 0, 0},
{"vforkexec", do_vforkexec, "vforkexec", 0, 0},
{"uwdc", unwindcases, "unwindcases", 0, 0},
{NULL, NULL, NULL, 0, 0}
};
int
main (int argc, char **argv)
{
int i;
hrtime_t start;
hrtime_t vstart;
char *name;
char buf[1024];
char arglist[4096];
// need a more robust test of whether system HWC events are being counted
if (getenv ("TILDECLAUSE"))
include_system_time = 1;
progstart = gethrtime ();
progvstart = getmyvtime ();
name = getenv ("SP_COLLECTOR_TEST_TIMER");
if (name)
{
testtime = atof (name);
if (testtime <= 0)
testtime = 1.0;
}
name = getenv ("_SP_NAME");
if (name == NULL || strlen (name) == 0)
strcpy (acct_file, "synprog.acct");
else
strcpy (acct_file, name);
strcpy (arglist, argv[0]);
for (i = 1; i < argc; i++)
{
strcat (arglist, " ");
strcat (arglist, argv[i]);
}
sprintf (buf, "%s run", argv[0]);
wlog (buf, NULL);
int ncpus = get_ncpus ();
acct_init (acct_file);
iotrace_init ("synprog.acct2");
/* Start a timer */
start = gethrtime ();
vstart = getmyvtime ();
#ifndef NO_MS_ACCT
stpwtch_calibrate ();
#endif
if (argc == 1)
commandline (DEFAULT_COMMAND);
else
{
i = 2;
while (i < argc)
{
forkcopy (argv[i], i - 1);
i++;
}
/* do the last one ourself */
commandline (argv[1]);
}
reapchildren ();
whrvlog (gethrtime () - start, getmyvtime () - vstart, buf, NULL);
fflush (fid);
fflush (fid2);
fclose (fid);
fclose (fid2);
return 0;
}
/* acct_init: initialize accounting */
void
acct_init (char *acct_file)
{
fid = fopen (acct_file, "w");
if (fid == NULL)
{
fprintf (stderr, "Open of %s for output failed: %s\n",
acct_file, strerror (errno));
exit (1);
}
fprintf (fid, "MHz: %d\n", get_clock_rate ());
fprintf (fid, "X Incl. Total Incl. CPU Name\n");
fflush (fid);
/* write a record for <Unknown>, which should have zero times */
fprintf (fid, "X %6.3f %6.3f %s\n", 0.0, 0.0, "<Unknown>");
/* set up to reap any children */
(void) sigset (SIGCHLD, reapchild);
/* verify the signal mask */
}
/* iotrace_init: initialize IO trace accounting */
void
iotrace_init (char *acct_file)
{
fid2 = fopen (acct_file, "w");
if (fid2 == NULL)
{
fprintf (stderr, "Open of %s for output failed: %s\n",
acct_file, strerror (errno));
exit (1);
}
fprintf (fid2, "X Incl.BytesRead Incl.ReadCount ");
fprintf (fid2, "Incl.BytesWritten Incl.WriteCount ");
fprintf (fid2, "Incl.OtherIOCount Name\n");
fflush (fid2);
}
/* commandline -- process a command line string:
* verbs are separated by a . character; each verb is looked-up
* in a table, and the routine to process it, and argument fetched.
* the routine is called.
*/
void
commandline (char *cmdline)
{
char *p;
char *j;
char prevj;
struct scripttab *k;
char buf[1024];
hrtime_t pstart;
hrtime_t pvstart;
hrtime_t pend;
hrtime_t pvend;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog (" Begin commandline", cmdline);
p = cmdline;
while (*p != 0)
{
/* find the terminator for this verb (a . or NULL) */
j = p;
while (*j != 0 && *j != '.')
j++;
prevj = *j;
*j = 0;
/* now look up the phase in the table */
for (k = &scripttab[0];; k++)
{
if (k->name == NULL)
break;
if (strcmp (p, k->name) == 0)
{
/* found a match */
pstart = gethrtime ();
pvstart = getmyvtime ();
(k->function)(k->param);
pend = gethrtime ();
pvend = getmyvtime ();
fprintf (fid, "%c %6.3f %6.3f %s\n",
k->noverify == 0 ? 'X' : 'Y',
(double) (pend - pstart) / (double) 1000000000.,
(double) (pvend - pvstart) / (double) 1000000000.,
k->acctname);
fflush (fid);
break;
}
}
if (k->name == NULL)
{
sprintf (buf, "++ ignoring `%s'\n", p);
fprintf (stderr, buf);
}
/* continue processing */
*j = prevj;
p = j;
if (prevj != 0)
p++;
}
whrvlog (gethrtime () - start, getmyvtime () - vstart, "commandline", cmdline);
}
int
clonecopy (void * script)
{
syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
strcpy (acct_file, child_name);
/*printf("_SP_NAME=\"%s\" (for clone-child)\n", acct_file);*/
acct_init (acct_file);
/* execute the script */
commandline ((char *) script);
/* reap the child's descendants */
reapchild (0);
exit (0);
}
/* forkcopy -- fork a copy to run a script */
void
forkcopy (char *script, int child)
{
int child_pid;
if (strncmp ("clone", script, 5) == 0)
{
//clone instead of fork
/* Log the event */
wlog ("cloning copy ... ", script);
sprintf (child_name, "%s_C%d", acct_file, ++syn_fork);
/* clone a new process */
void * stack;
void * stack_space;
int stack_size = CLONE_STACK_SIZE;
stack_space = mmap (NULL, stack_size, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_GROWSDOWN | MAP_ANONYMOUS, -1, 0);
if ((void*) - 1 == stack_space)
{
fprintf (stderr, "Error: mmap returned -1\n");
exit (1);
}
mprotect (stack_space, CLONE_RED_SIZE, PROT_NONE);
stack = (char *) stack_space + stack_size - CLONE_TLS_SIZE; // stack grows back
child_pid = clone (clonecopy, stack, CLONE_FLAGS[(child + 1) % 2],
(void *) (script + sizeof ("clone") - 1));
if (child_pid < 0)
{
/* error, could not fork */
fprintf (stderr, "forkcopy: clone failed--error %d\n", errno);
exit (1);
}
fprintf (stderr, "child process %d cloned by %d.\n",
child_pid, (int) getpid ());
return;
}
/* Log the event */
wlog ("forking copy ... ", script);
sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
/* fork a new process */
child_pid = fork ();
if (child_pid < 0)
{
/* error, could not fork */
fprintf (stderr, "forkcopy: fork failed--error %d\n", errno);
exit (1);
}
else if (child_pid == 0)
{
syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
strcpy (acct_file, child_name);
acct_init (acct_file);
/* execute the script */
commandline (script);
/* reap the child's descendants */
reapchild (0);
exit (0);
}
fprintf (stderr, "child process %d forked by %d.\n",
child_pid, (int) getpid ());
}
void
forkchild (char * cmdline)
{
stopwatch_t *prog;
char mbuf[1024];
/* Start a stopwatch */
sprintf (mbuf, "%s pid[%d]", "Synprog child", (int) getpid ());
prog = stpwtch_alloc (mbuf, 0);
/* process this child's command-line */
commandline (cmdline);
/* reap the child's descendants */
reapchild (0);
/* Stop print, and free the stopwatch */
stpwtch_stop (prog);
stpwtch_print (prog);
free (prog);
exit (0);
}
/* reap a child process, called in response to SIGCLD */
void
reapchild (int sig)
{
int status;
int ret = wait (&status);
sigset (SIGCLD, reapchild);
}
/* reap all child processes prior to exit */
void
reapchildren ()
{
int status;
int ret;
/* wait for all children to exit */
for (;;)
{
while ((ret = wait (&status)) != (pid_t) - 1)
fprintf (stderr, "synprog: reap child %x\n", ret);
if (errno == EINTR)
continue;
if (errno == ECHILD)
return;
fprintf (stderr, "synprog: unexpected errno from wait() syscall -- %s\n",
strerror (errno));
}
}
/* doabort -- force a SEGV */
int
doabort (int k)
{
char *nullptr = NULL;
char c;
/* Log the event */
wlog ("start of doabort", NULL);
/* and dereference a NULL */
c = *nullptr;
/* this should never be reached */
return (int) c;
}
/* =============================================================== */
/* dousleep -- loop with a usleep */
int
dousleep (int k)
{
volatile double x;
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of dousleep", NULL);
do
{
x = 0.0;
for (int j = 0; j < 1000000; j++)
x = x + 1.0;
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "dousleep", NULL);
/* this should never be reached */
return (int) 0;
}
/* =============================================================== */
/* correlate -- generate CPU use, correlated with profiling clock */
static void csig_handler (int);
int
correlate (int k)
{
volatile float x; /* temp variable for f.p. calculation */
struct itimerval tval;
int retval;
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of correlate", NULL);
/* set up the signal handler */
sigset (SIGALRM, csig_handler);
/* set an itimer, to break out of the sleep loop */
tval.it_value.tv_sec = 0;
tval.it_value.tv_usec = 10000;
tval.it_interval.tv_sec = 0;
tval.it_interval.tv_usec = 10000;
retval = setitimer (ITIMER_REAL, &tval, 0);
if (retval != 0)
fprintf (stderr, "setitimer(ITIMER_REAL) got %d returned: %s\n",
retval, strerror (errno));
do
{
x = 0.0;
for (int j = 0; j < 1000000; j++)
x = x + 1.0;
sleep (1); /* relying on the timer to break out */
count++;
}
while (start + testtime * 1e9 > gethrtime ());
/* now disable the itimer */
tval.it_value.tv_sec = 0;
tval.it_value.tv_usec = 0;
tval.it_interval.tv_sec = 0;
tval.it_interval.tv_usec = 0;
retval = setitimer (ITIMER_REAL, &tval, 0);
if (retval != 0)
fprintf (stderr, "setitimer(ITIMER_REAL) got %d returned: %s\n",
retval, strerror (errno));
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "correlate", NULL);
return 0;
}
static void
csig_handler (int sig)
{
return;
}
/* cputime -- loop to use a bunch of user time (f.p.) */
int
cputime (int k)
{
volatile float x; /* temp variable for f.p. calculation */
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of cputime", NULL);
do
{
x = 0.0;
for (int j = 0; j < 1000000; j++)
x = x + 1.0;
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "cputime", NULL);
return 0;
}
/* icputime -- loop to use a bunch of user time (long) */
int
icputime (int k)
{
volatile long x; /* temp variable for long calculation */
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of icputime", NULL);
do
{
x = 0;
for (int j = 0; j < 1000000; j++)
x = x + 1;
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "icputime", NULL);
return 0;
}
/* hrv -- loop to do lots of gethrvtime calls */
int
hrv (int k)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of hrv", NULL);
do
{
for (int j = 0; j < 10000; j++)
(void) gethrvtime ();
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "hrv", NULL);
return 0;
}
/* =============================================================== */
/* ldso -- use up time in ld.so */
int
ldso (int k)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of ldso", NULL);
do
{
for (int j = 0; j < 10000; j++)
(void) dlsym (RTLD_DEFAULT, "nosuchfoo");
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "ldso", NULL);
return 0;
}
/* masksignals -- debug aid -- call routine to mask SIGPROF and SIGEMT */
int
masksignals (int n)
{
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
whrvlog (gethrtime () - start, getmyvtime () - vstart, "masksignals", NULL);
return 0;
}
/* =============================================================== */
/* muldiv -- loop to do a bunch of integer multiply and divide */
volatile int tmp_ival = 0;
int
muldiv (int n)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of muldiv", NULL);
do
{
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 1000; j++)
tmp_ival = j * i / (i + 1.0);
}
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "muldiv", NULL);
return 0;
}
/* =============================================================== */
/* underflow -- loop triggering arithmetic underflow */
volatile float tmp_fval;
int
underflow (int k)
{
float x, y;
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of underflow", NULL);
do
{
x = 1.e-20;
y = 1.e-20;
for (int j = 0; j < 50000; j++)
tmp_fval = x * y;
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "underflow", NULL);
return 0;
}
/* naptime -- spend time in the system sleeping */
int
naptime (int k)
{
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of naptime", NULL);
if (k == 0)
{
k = testtime;
if (k < 1)
k = 1;
}
for (int i = 0; i < k; i++)
sleep (1);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "naptime", NULL);
return 0;
}
/* recurse -- loop to show recursion */
int real_recurse (int, int); /* real routine to do recursion */
int
recurse (int k)
{
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of recurse", NULL);
if (k == 0)
k = 80;
(void) real_recurse (0, k);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "recurse", NULL);
return 0;
}
int
recursedeep (int k)
{
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of recursedeep", NULL);
if (k == 0)
k = 500;
(void) real_recurse (0, k);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "recursedeep", NULL);
return 0;
}
static int rec_count = 0;
int
real_recurse (int i, int imax)
{
if (i == imax)
{
volatile float x;
long long count = 0;
hrtime_t start = gethrtime ();
do
{
x = 0.0;
for (int j = 0; j < 10000000; j++)
x = x + 1.0;
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
return rec_count;
}
else
{
real_recurse (i + 1, imax);
rec_count++;
return rec_count;
}
}
/* gpf -- simple example showing the gprof fallacy */
float gpf_a (void);
float gpf_b (void);
float gpf_work (int);
#define MAX_GPF_WORK_COUNT 1000
int
gpf (int k)
{
long long count = 0;
float x = -1.0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of gpf", NULL);
do
{
x = gpf_a ();
x += gpf_b ();
count++;
if (count == MAX_GPF_WORK_COUNT)
fprintf (stderr, "Execution error -- %lld iterations of gpf_[ab]; possible compiler bug\n",
count);
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
if (x < 0.0)
fprintf (stderr, "Execution error -- x < 0.0; possible compiler bug (x = %f)\n", x);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "gpf - total", NULL);
return 0;
}
float
gpf_a ()
{
float x = -1.0;
for (int i = 0; i < 9; i++)
x += gpf_work (1);
return x;
}
float
gpf_b ()
{
float x = -1.0;
x = gpf_work (10);
return x;
}
float
gpf_work (int amt)
{
volatile float x = 0.0;
int imax = 4 * amt * amt;
for (int i = 0; i < imax; i++)
{
x = 0.0;
for (int j = 0; j < 200000; j++)
x = x + 1.0;
}
return x;
}
/* bounce -- example of indirect recursion */
void bounce_a (int, int);
void bounce_b (int, int);
int
bounce (int k)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of bounce", NULL);
if (k == 0)
k = 20;
do
{
bounce_a (0, k);
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "bounce", NULL);
return 0;
}
void
bounce_a (int i, int imax)
{
if (i == imax)
{
volatile float x = 0.0;
for (int k = 0; k < 8; k++)
{
for (int j = 0; j < 2000000; j++)
x = x + 1.0;
}
return;
}
else
bounce_b (i, imax);
}
void
bounce_b (int i, int imax)
{
bounce_a (i + 1, imax);
return;
}
/* =============================================================== */
/* sched -- spend time calling sched_yield() */
int
sched (int k)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of sched", NULL);
if (k == 0)
{
k = testtime;
if (k < 1)
k = 1;
}
do
{
for (int i = 0; i < 1000000; i++)
sched_yield ();
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "sched", NULL);
return 0;
}
/* synccall -- spend time calling sync() */
int
synccall (int k)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of synccall", NULL);
if (k == 0)
{
k = testtime;
if (k < 1)
k = 1;
}
do
{
sync ();
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld sync() calls\n", count);
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "synccall", NULL);
return 0;
}
/* sigtime -- spend time in a signal handler */
static void sigtime_handler (int);
int
sigtime (int k)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of sigtime", NULL);
/* set up the signal handler */
sigset (SIGHUP, sigtime_handler);
do
{
kill (getpid (), SIGHUP);
count++;
}
while (start + testtime * 1e9 > gethrtime ());
sigset (SIGHUP, SIG_DFL);
fprintf (stderr, " Sent %lld SIGHUP signals\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigtime", NULL);
return 0;
}
static void
sigtime_handler (int sig)
{
volatile int x;
for (int i = 0; i < 50; i++)
{
x = 0;
for (int j = 0; j < 1000000; j++)
x = x + 1;
}
return;
}
/* systime -- spend time in a few system calls */
int
systime (int k)
{
struct timeval ttime;
int j;
long long count = 0;
double t = testtime / 5;
if (t < 1.0)
t = 1.0;
hrtime_t start = gethrtime ();
hrtime_t rstart = start;
hrtime_t vstart = getmyvtime ();
hrtime_t rvstart = vstart;
/* Log the event */
wlog ("start of systime", NULL);
/* do gettimeofday calls */
do
{
for (j = 0; j < 30000; j++)
{
(void) gettimeofday (&ttime, NULL);
}
count++;
}
while (start + t * 1e9 > gethrtime ());
hrtime_t end = gethrtime ();
hrtime_t vend = getmyvtime ();
fprintf (stderr, " Performed %lld while-loop iterations gettimeofday\n", count);
whrvlog (end - start, vend - vstart, "systime -- 10**6 gettimeofday", NULL);
/* do gethrtime calls */
start = gethrtime ();
vstart = getmyvtime ();
count = 0;
do
{
(void) gethrtime ();
count++;
}
while (start + t * 1e9 > gethrtime ());
end = gethrtime ();
vend = getmyvtime ();
fprintf (stderr, " Performed %lld while-loop iterations gethrtime\n", count);
whrvlog ((end - start), (vend - vstart), "systime -- 10**6 gethrtime", NULL);
/* do pairs of gethrtime calls */
start = gethrtime ();
vstart = getmyvtime ();
count = 0;
do
{
for (j = 0; j < 30000; j++)
{
(void) gethrtime ();
(void) gethrtime ();
}
count++;
}
while (start + t * 1e9 > gethrtime ());
end = gethrtime ();
vend = getmyvtime ();
fprintf (stderr, " Performed %lld while-loop iterations pairs of gethrtime\n",
count);
whrvlog (end - start, vend - vstart, "systime -- 10**6 pairs of gethrtime",
NULL);
/* do gethrvtime calls */
start = gethrtime ();
vstart = getmyvtime ();
count = 0;
do
{
for (j = 0; j < 30000; j++)
{
(void) gethrvtime ();
}
count++;
}
while (start + t * 1e9 > gethrtime ());
end = gethrtime ();
vend = getmyvtime ();
fprintf (stderr, " Performed %lld while-loop iterations gethrvtime\n", count);
whrvlog (end - start, vend - vstart, "systime -- 10**6 gethrvtime", NULL);
/* do getrusage calls */
start = gethrtime ();
vstart = getmyvtime ();
count = 0;
do
{
for (j = 0; j < 30000; j++)
{
struct rusage rusage;
(void) getrusage (RUSAGE_SELF, &rusage);
}
count++;
}
while (start + t * 1e9 > gethrtime ());
end = gethrtime ();
vend = getmyvtime ();
fprintf (stderr, " Performed %lld while-loop iterations getrusage\n", count);
whrvlog ((end - start), (vend - vstart), "systime -- 10**6 getrusage", NULL);
whrvlog ((gethrtime () - rstart), (getmyvtime () - rvstart), "systime", NULL);
return 0;
}
/* unwindcases -- test various unwind corner cases */
static void unwindcases_handler (int);
int
unwindcases (int k)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of unwindcases", NULL);
/* set up the signal handler */
sigset (SIGHUP, unwindcases_handler);
/* initialize the new signal mask */
sigset_t new_mask;
sigset_t old_mask;
sigfillset (&new_mask);
sigdelset (&new_mask, SIGHUP);
/* block all signals except SIGHUP*/
sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
do
{
kill (getpid (), SIGHUP);
count++;
}
while (start + testtime * 1e9 > gethrtime ());
sigprocmask (SIG_SETMASK, &old_mask, NULL);
sigset (SIGHUP, SIG_DFL);
fprintf (stderr, " Sent %lld SIGHUP signals\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "unwindcases", NULL);
return 0;
}
#define unwindcases_memcpy memcpy
#define unwindcases_memset memset
#define unwindcases_memnum (4096)
static char unwindcases_array[4097];
static volatile int srcind = 1024;
static void
unwindcases_handler (int sig)
{
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 1000; j++)
{
unwindcases_memset ((void*) unwindcases_array, 0, unwindcases_memnum);
for (int k = 0; k < 10; k++)
{
unwindcases_array[k] = unwindcases_array[srcind];
unwindcases_array[k + srcind / 4] = 0;
unwindcases_array[k] = unwindcases_array[strlen (unwindcases_array + k) + 1];
}
unwindcases_memcpy ((void*) unwindcases_array,
(void*) (unwindcases_array + 4096 / 2),
unwindcases_memnum / 2);
}
}
return;
}
/* tailcallopt -- call routines that would be tail-call optimized when
* compiled with optimization
*/
void tailcall_a (void);
void tailcall_b (void);
void tailcall_c (void);
int
tailcallopt (int n)
{
long long count = 0;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of tailcallopt", NULL);
do
{
tailcall_a ();
count++;
}
while (start + testtime * 1e9 > gethrtime ());
fprintf (stderr, " Performed %lld while-loop iterations\n", count);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "tailcallopt", NULL);
return 0;
}
void
tailcall_a ()
{
volatile float x = 0.0;
for (int j = 0; j < 4000000; j++)
x = x + 1.0;
tailcall_b ();
}
void
tailcall_b ()
{
volatile float x = 0.0;
for (int j = 0; j < 4000000; j++)
x = x + 1.0;
tailcall_c ();
}
void
tailcall_c ()
{
volatile float x = 0.0;
for (int j = 0; j < 4000000; j++)
x = x + 1.0;
}
int
itimer_realprof (int k) /* mess with itimer ITIMER_REALPROF */
{
struct itimerval tval;
int retval;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* set an itimer */
if (k != 0)
{
wlog ("start of itimer_realprof", NULL);
tval.it_interval.tv_sec = 1;
tval.it_interval.tv_usec = 300000;
tval.it_value = tval.it_interval;
}
else
{
wlog ("start of itimer_realprof(0)", NULL);
tval.it_interval.tv_sec = 0;
tval.it_interval.tv_usec = 0;
tval.it_value = tval.it_interval;
}
retval = setitimer (ITIMER_REALPROF, &tval, 0);
if (retval != 0)
fprintf (stderr, "setitimer(ITIMER_REALPROF) got %d returned: %s\n",
retval, strerror (errno));
whrvlog (gethrtime () - start, getmyvtime () - vstart, "itimer_realprof",
NULL);
return 0;
}
static struct sigaction old_sigprof_handler;
static void sigprof_handler (int sig);
static void sigprof_sigaction (int sig, siginfo_t *sip, ucontext_t *uap);
int
sigprof (int k)
{
struct sigaction act;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of sigprof", NULL);
/* query current handler */
if (sigaction (SIGPROF, NULL, &act) == -1)
printf ("\tFailed current sigaction query: %s\n", strerror (errno));
else
printf ("\tCurrently installed sigaction 0x%p\n", act.sa_sigaction);
sigemptyset (&act.sa_mask);
act.sa_flags = SA_RESTART | SA_SIGINFO;
act.sa_sigaction = (void(*)(int, siginfo_t*, void*))sigprof_sigaction;
if (k != 0)
{
/* install with deferral to original handler (if set) */
if (sigaction (SIGPROF, &act, &old_sigprof_handler) == -1)
printf ("\tFailed to install sigprof_sigaction: %s\n", strerror (errno));
if (old_sigprof_handler.sa_sigaction == (void (*)(int, siginfo_t *, void *))SIG_DFL)
{
old_sigprof_handler.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;
printf ("\tReplaced default sigprof handler with 0x%p\n",
act.sa_sigaction);
}
else
printf ("\tReplaced sigprof handler 0x%p with 0x%p\n",
old_sigprof_handler.sa_sigaction, act.sa_sigaction);
}
else
{
/* installed without deferral to any original handler */
old_sigprof_handler.sa_sigaction = (void (*)(int, siginfo_t *, void *))SIG_IGN;
if (sigaction (SIGPROF, &act, NULL) == -1)
printf ("\tFailed to install sigprof_sigaction: %s\n", strerror (errno));
else
printf ("\tInstalled sigprof_sigaction 0x%p\n", act.sa_sigaction);
}
whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigprof", NULL);
return 0;
}
int
sigprofh (int k)
{
struct sigaction act;
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
/* Log the event */
wlog ("start of sigprofh", NULL);
/* query current handler */
if (sigaction (SIGPROF, NULL, &act) == -1)
printf ("\tFailed current sigaction query: %s\n", strerror (errno));
else
printf ("\tCurrently installed handler 0x%p\n", act.sa_handler);
sigemptyset (&act.sa_mask);
act.sa_flags = SA_RESTART;
act.sa_handler = sigprof_handler;
if (k != 0)
{
/* install with deferral to original handler (if set) */
if (sigaction (SIGPROF, &act, &old_sigprof_handler) == -1)
printf ("\tFailed to install sigprof_handler: %s\n", strerror (errno));
if (old_sigprof_handler.sa_handler == SIG_DFL)
{
old_sigprof_handler.sa_handler = SIG_IGN;
printf ("\tReplaced default sigprof handler with 0x%p\n",
act.sa_handler);
}
else
printf ("\tReplaced sigprof handler 0x%p with 0x%p\n",
old_sigprof_handler.sa_handler, act.sa_handler);
}
else
{
/* installed without deferral to any original handler */
old_sigprof_handler.sa_handler = SIG_IGN;
if (sigaction (SIGPROF, &act, NULL) == -1)
printf ("\tFailed to install sigprof_handler: %s\n", strerror (errno));
else
printf ("\tInstalled sigprof_handler 0x%p\n", act.sa_handler);
}
whrvlog (gethrtime () - start, getmyvtime () - vstart, "sigprofh", NULL);
return 0;
}
static void
sigprof_handler (int sig)
{
int j;
volatile int x;
hrtime_t now = gethrtime ();
if (old_sigprof_handler.sa_handler == SIG_IGN)
{
whrvlog (now, 0, "sigprof_handler (ign)", NULL);
for (j = 0, x = 0; j < 1000000; j++)
x = x + 1;
}
else
{
whrvlog (now, 0, "sigprof_handler (fwd)", NULL);
for (j = 0, x = 0; j < 1000000; j++)
x = x + 1;
/* forward signal to original handler */
if (old_sigprof_handler.sa_flags & SA_SIGINFO)
(old_sigprof_handler.sa_sigaction)(sig, NULL, NULL);
else
(old_sigprof_handler.sa_handler)(sig);
printf ("\tReturned from original sigprof handler!\n");
}
return;
}
static void
sigprof_sigaction (int sig, siginfo_t *sip, ucontext_t *uap)
{
int j;
volatile int x;
hrtime_t now = gethrtime ();
if (old_sigprof_handler.sa_sigaction == (void (*)(int, siginfo_t *, void *))SIG_IGN)
{
whrvlog (now, 0, "sigprof_sigaction (ign)", NULL);
for (j = 0, x = 0; j < 1000000; j++)
x = x + 1;
}
else
{
whrvlog (now, 0, "sigprof_sigaction (fwd)", NULL);
for (j = 0, x = 0; j < 1000000; j++)
x = x + 1;
/* forward signal to original handler */
if (old_sigprof_handler.sa_flags & SA_SIGINFO)
(old_sigprof_handler.sa_sigaction)(sig, sip, uap);
else
(old_sigprof_handler.sa_handler)(sig);
printf ("\tReturned from original sigprof sigaction!\n");
}
return;
}
#if 0
Need to consider various signal handler / sigaction scenarios :
1. A handler is already installed, and a new handler is being installed.
(The original handler may be one of the defaults.)
2. A handler is already installed, and a sigaction is being installed.
3. A sigaction is already installed, and a new sigaction is being installed.
4. A sigaction is already installed, and a handler is being installed.
#endif
int
do_chdir (int k) /* switch to a new working directory */
{
char *workdir;
char *workdir0 = "/tmp";
char *workdir1 = "/";
char currworkdir[MAXPATHLEN];
hrtime_t start = gethrtime ();
hrtime_t vstart = getmyvtime ();
if (k != 0)
{
wlog ("start of do_chdir(X)", NULL);
workdir = workdir1;
}
else
{
wlog ("start of do_chdir", NULL);
workdir = workdir0;
}
if (getcwd (currworkdir, sizeof (currworkdir)) == NULL)
fprintf (stderr, "old getcwd failed: %s\n", strerror (errno));
else
printf ("old getcwd returned \"%s\"\n", currworkdir);
if (chdir (workdir) != 0)
fprintf (stderr, "chdir(\"%s\") failed: %s\n", workdir, strerror (errno));
if (getcwd (currworkdir, sizeof (currworkdir)) == NULL)
fprintf (stderr, "new getcwd failed: %s\n", strerror (errno));
else
printf ("new getcwd returned \"%s\"\n", currworkdir);
whrvlog (gethrtime () - start, getmyvtime () - vstart, "do_chdir", NULL);
return 0;
}
int
do_exec (int k) /* do an exec() call */
{
sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
if (putenv (new_name))
fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
if (k >= 0)
{
wlog ("about to exec", NULL);
execl ("./synprog", "synprog", "gpf.cpu.sx", NULL);
wlog ("exec failed!!!", NULL);
}
else
{
wlog ("about to execX", NULL);
execl ("./no-such-file", "no-such-file", "gpf.cpu.sx", NULL);
wlog ("execX failed (as expected)", NULL);
}
return 0;
}
/* preloading libcollector to a setuid executable will fail! */
const char *cmdX = "/random/crash_n_burn";
const char *cmd0 = "/bin/uptime";
const char *cmd1 = "/bin/echo hello world!";
const char *cmd2 = "/usr/bin/sleep 5";
const char *cmd3 = "/usr/bin/sleep 5; /bin/echo hello world!";
const char *cmd4 = "/usr/bin/sleep 2; /bin/echo hello world!; /usr/bin/sleep 2";
const char *cmd5 = "/bin/date; /bin/sleep 2; /bin/date; /bin/sleep 2; /bin/date";
const char *cmd6 = "w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w;w";
const char *cmd7 = "synprog";
const char *cmd8 = "synprog icpu.sx 2>&1";
int
do_popen (int k) /* do a popen() call */
{
int ret;
FILE *fd;
char buf[BUFSIZ];
const char *mode = "r";
/* XXXX popen() will temporarily vfork+exec() a new child */
/* but there will be no accounting for it, unless it's synprog! */
sprintf (new_name, "_SP_NAME=%s_c%d", acct_file, ++syn_combo);
if (putenv (new_name))
fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
/* ignore reapchild to catch child here */
(void) sigset (SIGCHLD, 0);
if (k >= 0)
{
wlog ("about to popen", NULL);
fd = popen (cmd8, mode);
}
else
{
wlog ("about to popenX!", NULL);
fd = popen (cmdX, mode);
}
if (fd == NULL)
printf ("do_popen failed: %s\n", strerror (errno));
else
printf ("do_popen succeeded: fileno=%d\n", fileno (fd));
/* restore pre-popen environment */
sprintf (new_name, "_SP_NAME=%s", acct_file);
if (putenv (new_name))
fprintf (stderr, "Failed to restore name! %s\n", strerror (errno));
if (fd != NULL)
{
while (fgets (buf, BUFSIZ, fd) != NULL)
printf ("& %s", buf);
if ((ret = pclose (fd)) == -1)
printf ("do_popen pclose error: %s\n", strerror (errno));
else
printf ("do_popen pclose returned %d\n", ret);
}
/* set up to reap any children */
(void) sigset (SIGCHLD, reapchild);
return 0;
}
int
do_system (int k) /* do a system() call */
{
int ret;
/* XXXX system() will temporarily vfork+exec() a new child */
/* but there will be no accounting for it, unless it's synprog! */
sprintf (new_name, "_SP_NAME=%s_c%d", acct_file, ++syn_combo);
if (putenv (new_name))
fprintf (stderr, "Failed to name child! %s\n", strerror (errno));
if (k >= 0)
{
wlog ("about to system", NULL);
ret = system (cmd8);
}
else
{
wlog ("about to systemX!", NULL);
ret = system (cmd0);
}
if (ret < 0)
printf ("do_system failed: %s\n", strerror (errno));
else
printf ("do_system succeeded, ret=%d\n", ret);
/* restore pre-system environment */
sprintf (new_name, "_SP_NAME=%s", acct_file);
if (putenv (new_name))
fprintf (stderr, "Failed to restore name! %s\n", strerror (errno));
return 0;
}
int
do_forkexec (int k) /* do a fork()+exec() call combo */
{
int ret, pid;
int status = -1;
char arg0[128], arg1[128];
arg1[0] = (char) 0;
/* ignore reapchild to catch child here */
(void) sigset (SIGCHLD, 0);
sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
if ((pid = fork ()) == 0)
{
syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
strcpy (acct_file, child_name);
acct_init (acct_file);
sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
if (putenv (new_name))
{
fprintf (stderr, "Failed to name fork child! %s\n", strerror (errno));
}
(void) execl (arg0, "fork+exec", arg1[0] ? arg1 : NULL, NULL);
fprintf (stderr, "fork execl failed! %s\n", strerror (errno));
_exit (127);
}
else if (pid == -1)
fprintf (stderr, "fork failed! %s\n", strerror (errno));
else
{
do
{
ret = waitpid (pid, &status, WNOHANG | WUNTRACED);
}
while ((ret == -1) && (errno == EINTR));
if (ret == -1)
fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
#if 0
else
{
if (WIFEXITED (status))
printf ("WEXITSTATUS=%d\n", WEXITSTATUS (status));
if (WIFSTOPPED (status))
printf ("WSTOPSIG=%d\n", WSTOPSIG (status));
if (WIFSIGNALED (status))
printf ("WTERMSIG=%d\n", WTERMSIG (status));
if (WIFCONTINUED (status))
printf ("WIFCONTINUED=%d\n", WIFCONTINUED (status));
}
#endif
if (WIFEXITED (status))
printf ("do_forkexec succeeded: child exit status=%d\n",
WEXITSTATUS (status));
else
printf ("do_forkexec failed! status=%d\n", status);
}
/* set up to reap any children */
(void) sigset (SIGCHLD, reapchild);
return 0;
}
int
do_vforkexec (int k) /* do a vfork()+exec() call combo */
{
int ret, pid;
int status = 1;
char arg0[128], arg1[128];
arg1[0] = (char) 0;
/* ignore reapchild to catch child here */
(void) sigset (SIGCHLD, 0);
sprintf (child_name, "%s_f%d", acct_file, ++syn_fork);
if ((pid = vfork ()) == 0)
{
syn_fork = syn_exec = syn_combo = 0; /* reset for new child line */
strcpy (acct_file, child_name);
acct_init (acct_file);
sprintf (new_name, "_SP_NAME=%s_x%d", acct_file, ++syn_exec);
if (putenv (new_name))
fprintf (stderr, "Failed to name vfork child! %s\n", strerror (errno));
(void) execl (arg0, "vfork+exec", arg1[0] ? arg1 : NULL, NULL);
printf ("vfork execl failed! %s\n", strerror (errno));
_exit (127);
}
else if (pid == -1)
fprintf (stderr, "vfork failed! %s\n", strerror (errno));
else
{
do
{
ret = waitpid (pid, &status, WNOHANG | WUNTRACED);
}
while (ret == -1 && errno == EINTR);
if (ret == -1)
fprintf (stderr, "waitpid failed: %s\n", strerror (errno));
#if 0
else
{
if (WIFEXITED (status))
printf ("WEXITSTATUS=%d\n", WEXITSTATUS (status));
if (WIFSTOPPED (status))
printf ("WSTOPSIG=%d\n", WSTOPSIG (status));
if (WIFSIGNALED (status))
printf ("WTERMSIG=%d\n", WTERMSIG (status));
if (WIFCONTINUED (status))
printf ("WIFCONTINUED=%d\n", WIFCONTINUED (status));
}
#endif
if (WIFEXITED (status))
printf ("do_vforkexec succeeded: child exit status=%d\n",
WEXITSTATUS (status));
else
printf ("do_vforkexec failed! status=%d\n", status);
}
/* set up to reap any children */
(void) sigset (SIGCHLD, reapchild);
return 0;
}