From 178bd263afddd9f1ebe326540395105b267e189c Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 1 May 2009 05:00:34 +0000 Subject: [PATCH] Refactor and recomment async-sigs so it's easier to understand. Send all its output to stderr as well. git-svn-id: svn://svn.valgrind.org/valgrind/trunk@9706 --- none/tests/Makefile.am | 2 +- none/tests/async-sigs.c | 203 +++++++++++++++++-------------- none/tests/async-sigs.stderr.exp | 18 ++- none/tests/async-sigs.stdout.exp | 8 -- none/tests/async-sigs.vgtest | 1 + 5 files changed, 121 insertions(+), 111 deletions(-) delete mode 100644 none/tests/async-sigs.stdout.exp diff --git a/none/tests/Makefile.am b/none/tests/Makefile.am index 4f71ffbe1f..f1bbff6cad 100644 --- a/none/tests/Makefile.am +++ b/none/tests/Makefile.am @@ -38,7 +38,7 @@ noinst_HEADERS = fdleak.h EXTRA_DIST = $(noinst_SCRIPTS) \ ansi.stderr.exp ansi.vgtest \ args.stderr.exp args.stdout.exp args.vgtest \ - async-sigs.stderr.exp async-sigs.stdout.exp async-sigs.vgtest \ + async-sigs.stderr.exp async-sigs.vgtest \ bitfield1.stderr.exp bitfield1.vgtest \ bug129866.vgtest bug129866.stderr.exp bug129866.stdout.exp \ closeall.stderr.exp closeall.vgtest \ diff --git a/none/tests/async-sigs.c b/none/tests/async-sigs.c index 3e403f6d00..25b730bef0 100644 --- a/none/tests/async-sigs.c +++ b/none/tests/async-sigs.c @@ -1,3 +1,12 @@ +// This tests handling of signals sent from outside the process in the +// following combinations: sync and async signals, caught and uncaught +// signals, and while blocking or not blocking in a syscall. This exercises +// various different paths in Valgrind's signal handling. +// +// It does this by installing signal handlers for one signal S, spawning +// another process P, sending S from P multiple times (all caught), then +// sending another signal from P (not caught). + #include #include #include @@ -7,7 +16,7 @@ #include #include -static const struct timespec bip = { 0, 1000000000 / 5 }; +static const struct timespec bip = { 0, 1000000000 / 5 }; // 0.2 seconds. static void handler(int sig) { @@ -18,103 +27,113 @@ static void handler(int sig) respect to thread scheduling. */ static void do_kill(int pid, int sig) { - int status; - int killer; - int ret; - - killer = vfork(); - - if (killer == -1) { - perror("killer/vfork"); - exit(1); - } - - if (killer == 0) { - char sigbuf[20]; - char pidbuf[20]; - sprintf(sigbuf, "-%d", sig); - sprintf(pidbuf, "%d", pid); - execl("/bin/kill", "kill", sigbuf, pidbuf, NULL); - perror("exec failed"); - exit(1); - } - - do - ret = waitpid(killer, &status, 0); - while(ret == -1 && errno == EINTR); - - if (ret != killer) { - perror("kill/waitpid"); - exit(1); - } - - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { - printf("kill %d failed status=%s %d\n", killer, - WIFEXITED(status) ? "exit" : "signal", - WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)); - exit(1); - } + int status; + int killer; + int ret; + + killer = vfork(); + if (killer == -1) { + perror("killer/vfork"); + exit(1); + } + + // In the child, exec 'kill' in order to send the signal. + if (killer == 0) { + char sigbuf[20]; + char pidbuf[20]; + sprintf(sigbuf, "-%d", sig); + sprintf(pidbuf, "%d", pid); + execl("/bin/kill", "kill", sigbuf, pidbuf, NULL); + perror("exec failed"); + exit(1); + } + + // In the parent, just wait for the child and then check it ran ok. + do + ret = waitpid(killer, &status, 0); + while (ret == -1 && errno == EINTR); + + if (ret != killer) { + perror("kill/waitpid"); + exit(1); + } + + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { + fprintf(stderr, "kill %d failed status=%s %d\n", killer, + WIFEXITED(status) ? "exit" : "signal", + WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)); + exit(1); + } } static void test(int block, int caughtsig, int fatalsig) { - int pid; - int status; - int i; - - printf("testing: blocking=%d caught=%d fatal=%d... ", block, caughtsig, fatalsig); - fflush(stdout); - - pid = fork(); - if (pid == -1) { - perror("fork"); - exit(1); - } - - if (pid == 0) { - alarm(10); /* if something breaks, don't spin forever */ - signal(caughtsig, handler); - - for(;;) - if (block) - pause(); - - } - - nanosleep(&bip, 0); /* wait for child to get going */ - - for(i = 0; i < 5; i++) { - do_kill(pid, caughtsig); /* should be caught */ - nanosleep(&bip, 0); - do_kill(pid, caughtsig); - do_kill(pid, caughtsig); - } - - nanosleep(&bip, 0); - - do_kill(pid, fatalsig); /* should kill it */ - - if (waitpid(pid, &status, 0) != pid) - printf("FAILED: waitpid failed: %s\n", strerror(errno)); - else if (!WIFSIGNALED(status) || WTERMSIG(status) != fatalsig) - printf("FAILED: child exited with unexpected status %s %d\n", - WIFEXITED(status) ? "exit" : "signal", - WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)); - else - printf("PASSED\n"); + int pid; + int status; + int i; + + fprintf(stderr, "testing: blocking=%d caught=%d fatal=%d... ", + block, caughtsig, fatalsig); + + pid = fork(); + if (pid == -1) { + perror("fork"); + exit(1); + } + + // In the child, install the signal handler, then wait for the signal to + // arrive: + // - if 'block' is set, wait on a system call; + // - otherwise, wait in client code (by spinning). + // The alarm() calls is so that if something breaks, we don't get stuck. + if (pid == 0) { + signal(caughtsig, handler); + alarm(10); + + for (;;) + if (block) { + pause(); + } + } + + // In the parent, send the signals. + nanosleep(&bip, 0); // Wait for child to get going. + + for (i = 0; i < 5; i++) { + do_kill(pid, caughtsig); // Should be caught. + nanosleep(&bip, 0); + do_kill(pid, caughtsig); // Ditto. + do_kill(pid, caughtsig); // Ditto. + } + + nanosleep(&bip, 0); + + do_kill(pid, fatalsig); // Should kill it. + + // Check that the child behaved as expected when it received the signals. + if (waitpid(pid, &status, 0) != pid) { + fprintf(stderr, "FAILED: waitpid failed: %s\n", strerror(errno)); + + } else if (!WIFSIGNALED(status) || WTERMSIG(status) != fatalsig) { + fprintf(stderr, "FAILED: child exited with unexpected status %s %d\n", + WIFEXITED(status) ? "exit" : "signal", + WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)); + + } else { + fprintf(stderr, "PASSED\n"); + } } int main() { - static const int catch[] = { SIGSEGV, SIGUSR1 }; - static const int fatal[] = { SIGBUS, SIGUSR2 }; - int block, catchidx, fatalidx; - - setvbuf(stdout, NULL, _IOLBF, 0); - - for(block = 0; block < 2; block++) - for(catchidx = 0; catchidx < sizeof(catch)/sizeof(*catch); catchidx++) - for(fatalidx = 0; fatalidx < sizeof(fatal)/sizeof(*fatal); fatalidx++) - test(block, catch[catchidx], fatal[fatalidx]); - return 0; + test(/*non-blocked*/0, /* sync*/SIGSEGV, /* sync*/SIGBUS); + test(/*non-blocked*/0, /* sync*/SIGSEGV, /*async*/SIGHUP); + test(/*non-blocked*/0, /*async*/SIGUSR1, /* sync*/SIGBUS); + test(/*non-blocked*/0, /*async*/SIGUSR1, /*async*/SIGHUP); + test(/* blocked*/1, /* sync*/SIGSEGV, /* sync*/SIGBUS); + test(/* blocked*/1, /* sync*/SIGSEGV, /*async*/SIGHUP); + test(/* blocked*/1, /*async*/SIGUSR1, /* sync*/SIGBUS); + test(/* blocked*/1, /*async*/SIGUSR1, /*async*/SIGHUP); + + return 0; } diff --git a/none/tests/async-sigs.stderr.exp b/none/tests/async-sigs.stderr.exp index 584ba8795f..6e784a2ef7 100644 --- a/none/tests/async-sigs.stderr.exp +++ b/none/tests/async-sigs.stderr.exp @@ -1,10 +1,8 @@ - - - - - - - - - - +testing: blocking=0 caught=11 fatal=7... PASSED +testing: blocking=0 caught=11 fatal=1... PASSED +testing: blocking=0 caught=10 fatal=7... PASSED +testing: blocking=0 caught=10 fatal=1... PASSED +testing: blocking=1 caught=11 fatal=7... PASSED +testing: blocking=1 caught=11 fatal=1... PASSED +testing: blocking=1 caught=10 fatal=7... PASSED +testing: blocking=1 caught=10 fatal=1... PASSED diff --git a/none/tests/async-sigs.stdout.exp b/none/tests/async-sigs.stdout.exp deleted file mode 100644 index 397f4991c1..0000000000 --- a/none/tests/async-sigs.stdout.exp +++ /dev/null @@ -1,8 +0,0 @@ -testing: blocking=0 caught=11 fatal=7... PASSED -testing: blocking=0 caught=11 fatal=12... PASSED -testing: blocking=0 caught=10 fatal=7... PASSED -testing: blocking=0 caught=10 fatal=12... PASSED -testing: blocking=1 caught=11 fatal=7... PASSED -testing: blocking=1 caught=11 fatal=12... PASSED -testing: blocking=1 caught=10 fatal=7... PASSED -testing: blocking=1 caught=10 fatal=12... PASSED diff --git a/none/tests/async-sigs.vgtest b/none/tests/async-sigs.vgtest index 6a6a77dae9..ec51f036fd 100644 --- a/none/tests/async-sigs.vgtest +++ b/none/tests/async-sigs.vgtest @@ -1 +1,2 @@ prog: async-sigs +vgopts: -q -- 2.47.3