File: async-sigs.c

package info (click to toggle)
valgrind 1%3A3.3.1-3
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 34,452 kB
  • ctags: 27,778
  • sloc: ansic: 234,398; sh: 14,186; xml: 11,662; perl: 4,410; asm: 3,135; makefile: 3,011; exp: 625; cpp: 255; haskell: 195
file content (120 lines) | stat: -rw-r--r-- 2,673 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>

static const struct timespec bip = { 0, 1000000000 / 5 };

static void handler(int sig)
{
}

/* Kill our child, but use a separate kill command.  This is so that
   it's running independently of Valgrind, and so is async with
   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);
	}
}

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 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;
}