/* $OpenBSD: signal-stress.c,v 1.2 2004/08/05 15:06:59 art Exp $ */ /* * Written by Artur Grabowski 2004 Public Domain. */ #include #include #include #include #include #include #include int nprocs, nsigs; pid_t *pids; pid_t next, prev; sig_atomic_t usr1, usr2; void sighand(int sig) { if (sig == SIGUSR1 && ++usr1 <= nsigs) { if (kill(next, sig)) _exit(1); } if (sig == SIGUSR2 && ++usr2 <= nsigs) { if (kill(prev, sig)) _exit(1); } } void do_child(void) { int i; /* * Step 1 - suspend and wait for SIGCONT so that all siblings have * been started before the next step. */ raise(SIGSTOP); /* Find our neighbours. */ for (i = 0; i < nprocs; i++) { if (pids[i] != getpid()) continue; if (i + 1 == nprocs) next = pids[0]; else next = pids[i + 1]; if (i == 0) prev = pids[nprocs - 1]; else prev = pids[i - 1]; } signal(SIGUSR1, sighand); signal(SIGUSR2, sighand); /* Step 2 - wait again until everyone is ready. */ raise(SIGSTOP); while (usr1 < nsigs || usr2 < nsigs) pause(); /* Step 3 - wait again until everyone is ready. */ raise(SIGSTOP); } void wait_stopped(pid_t pid) { int status; if (waitpid(pid, &status, WUNTRACED) != pid) err(1, "waitpid"); if (!WIFSTOPPED(status)) errx(1, "child %d not stopped", pid); } void cleanup(void) { int i; for (i = 0; i < nprocs; i++) kill(pids[i], 9); } void alrmhand(int sig) { cleanup(); _exit(1); } int main() { int i; pid_t pid; nprocs = 35; nsigs = 1000; if ((pids = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0)) == MAP_FAILED) err(1, "mmap"); for (i = 0; i < nprocs; i++) { switch((pid = fork())) { case 0: do_child(); _exit(0); case -1: err(1, "fork"); } pids[i] = pid; } atexit(cleanup); signal(SIGALRM, alrmhand); alarm(120); /* Die after two minutes. */ /* Step 1. Wait until all children have went to sleep */ for (i = 0; i < nprocs; i++) wait_stopped(pids[i]); /* And wake them */ for (i = 0; i < nprocs; i++) kill(pids[i], SIGCONT); /* Step 2. Repeat. */ for (i = 0; i < nprocs; i++) wait_stopped(pids[i]); for (i = 0; i < nprocs; i++) kill(pids[i], SIGCONT); /* * Now all children are ready for action. * Send the first signals and wait until they all exit. */ kill(pids[arc4random() % nprocs], SIGUSR1); kill(pids[arc4random() % nprocs], SIGUSR2); /* * The signal game is running, now insert noise in the process. */ for (i = 0; i < nprocs; i++) { pid_t pid = pids[arc4random() % nprocs]; kill(pid, SIGSTOP); wait_stopped(pid); kill(pid, SIGCONT); } /* Step 3. Repeat. */ for (i = 0; i < nprocs; i++) wait_stopped(pids[i]); for (i = 0; i < nprocs; i++) kill(pids[i], SIGCONT); /* Wait for everyone to finish. */ for (i = 0; i < nprocs; i++) { int status; if (waitpid(pids[i], &status, WUNTRACED) != pids[i]) err(1, "waitpid"); if (!WIFEXITED(status)) errx(1, "child %d not stopped (%d)", pids[i], status); if (WEXITSTATUS(status) != 0) warnx("child %d status: %d", i, status); } return (0); }