mc_translate.c: enable further uses of DLexpensive for scalar EQ/NE comparisons
[valgrind.git] / none / tests / async-sigs.c
blobf05eb6e4ebda2c2dee867950a424732c63e72f73
1 // This tests handling of signals sent from outside the process in the
2 // following combinations: sync and async signals, caught and uncaught
3 // signals, and while blocking or not blocking in a syscall. This exercises
4 // various different paths in Valgrind's signal handling.
5 //
6 // It does this by installing signal handlers for one signal S, spawning
7 // another process P, sending S from P multiple times (all caught), then
8 // sending another signal from P (not caught).
10 #include <signal.h>
11 #include <unistd.h>
12 #include <sys/wait.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <time.h>
19 static const struct timespec bip = { 0, 1000000000 / 5 }; // 0.2 seconds.
21 static void handler(int sig)
25 static void install_handler(int sig, void (*sig_handler)(int))
27 struct sigaction sa;
28 sa.sa_handler = sig_handler;
29 sigemptyset(&sa.sa_mask);
30 sa.sa_flags = 0;
31 sigaction(sig, &sa, 0);
34 /* Kill our child, but use a separate kill command. This is so that
35 it's running independently of Valgrind, and so is async with
36 respect to thread scheduling. */
37 static void do_kill(int pid, int sig)
39 int status;
40 int killer;
41 int ret;
43 killer = vfork();
44 if (killer == -1) {
45 perror("killer/vfork");
46 exit(1);
49 // In the child, exec 'kill' in order to send the signal.
50 if (killer == 0) {
51 char sigbuf[20];
52 char pidbuf[20];
53 sprintf(sigbuf, "-%d", sig);
54 sprintf(pidbuf, "%d", pid);
55 execl("/bin/kill", "kill", sigbuf, pidbuf, (char *) NULL);
56 perror("exec failed");
57 exit(1);
60 // In the parent, just wait for the child and then check it ran ok.
61 do
62 ret = waitpid(killer, &status, 0);
63 while (ret == -1 && errno == EINTR);
65 if (ret != killer) {
66 perror("kill/waitpid");
67 exit(1);
70 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
71 fprintf(stderr, "kill %d failed status=%s %d\n", killer,
72 WIFEXITED(status) ? "exit" : "signal",
73 WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status));
74 exit(1);
78 static void test(int block, int caughtsig, int fatalsig)
80 int pid;
81 int status;
82 int i;
84 fprintf(stderr, "testing: blocking=%d caught=%d fatal=%d... ",
85 block, caughtsig, fatalsig);
87 pid = fork();
88 if (pid == -1) {
89 perror("fork");
90 exit(1);
93 // In the child, install the signal handler, then wait for the signal to
94 // arrive:
95 // - if 'block' is set, wait on a system call;
96 // - otherwise, wait in client code (by spinning).
97 // The alarm() calls is so that if something breaks, we don't get stuck.
98 if (pid == 0) {
99 install_handler(caughtsig, handler);
100 alarm(10);
102 for (;;)
103 if (block) {
104 pause();
108 // In the parent, send the signals.
109 nanosleep(&bip, 0); // Wait for child to get going.
111 for (i = 0; i < 5; i++) {
112 do_kill(pid, caughtsig); // Should be caught.
113 nanosleep(&bip, 0);
114 do_kill(pid, caughtsig); // Ditto.
115 do_kill(pid, caughtsig); // Ditto.
118 nanosleep(&bip, 0);
120 do_kill(pid, fatalsig); // Should kill it.
122 // Check that the child behaved as expected when it received the signals.
123 if (waitpid(pid, &status, 0) != pid) {
124 fprintf(stderr, "FAILED: waitpid failed: %s\n", strerror(errno));
126 } else if (!WIFSIGNALED(status) || WTERMSIG(status) != fatalsig) {
127 fprintf(stderr, "FAILED: child exited with unexpected status %s %d\n",
128 WIFEXITED(status) ? "exit" : "signal",
129 WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status));
131 } else {
132 fprintf(stderr, "PASSED\n");
136 int main()
138 /* Restore default behaviour of SIGHUP when forked from cron. */
139 install_handler(SIGHUP, SIG_DFL);
141 test(/*non-blocked*/0, /* sync*/SIGSEGV, /* sync*/SIGBUS);
142 test(/*non-blocked*/0, /* sync*/SIGSEGV, /*async*/SIGHUP);
143 test(/*non-blocked*/0, /*async*/SIGUSR1, /* sync*/SIGBUS);
144 test(/*non-blocked*/0, /*async*/SIGUSR1, /*async*/SIGHUP);
145 test(/* blocked*/1, /* sync*/SIGSEGV, /* sync*/SIGBUS);
146 test(/* blocked*/1, /* sync*/SIGSEGV, /*async*/SIGHUP);
147 test(/* blocked*/1, /*async*/SIGUSR1, /* sync*/SIGBUS);
148 test(/* blocked*/1, /*async*/SIGUSR1, /*async*/SIGHUP);
150 return 0;