summaryrefslogtreecommitdiff
path: root/test/wait_must_be_interruptible.c
blob: 931ec4ce20ea0b9c0a124859587434c412cb604f (plain)
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
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>

/* Expected order is:
 * Child signals parent
 * Parent got signal
 * Child will exit now
 *
 * The bug we test for: under strace -f, last two lines are swapped
 * because wait syscall is suspended by strace and thus can't be interrupted.
 */

static const char msg1[] = "Child signals parent\n";
static const char msg2[] = "Parent got signal\n";
static const char msg3[] = "Child will exit now\n";

static void handler(int s)
{
	write(1, msg2, sizeof(msg2)-1);
}

static void test()
{
	/* Note: in Linux, signal() installs handler with SA_RESTART flag,
	 * therefore wait will be restarted.
	 */
	signal(SIGALRM, handler);

	if (fork() == 0) {
		/* child */
		sleep(1);
		write(1, msg1, sizeof(msg1)-1);
		kill(getppid(), SIGALRM);
		sleep(1);
		write(1, msg3, sizeof(msg3)-1);
		_exit(0);
	}

	/* parent */
	wait(NULL);
	_exit(0);
}

int main()
{
	char buf1[80];
	char buf2[80];
	char buf3[80];
	int pipefd[2];

	printf("Please run me under 'strace -f'\n");

	pipe(pipefd);

	if (fork() == 0) {
		if (pipefd[1] != 1) {
			dup2(pipefd[1], 1);
			close(pipefd[1]);
		}
		test();
	}

	if (pipefd[0] != 0) {
		dup2(pipefd[0], 0);
		close(pipefd[0]);
	}
	fgets(buf1, 80, stdin);	printf("%s", buf1);
	fgets(buf2, 80, stdin);	printf("%s", buf2);
	fgets(buf3, 80, stdin);	printf("%s", buf3);

	if (strcmp(buf1, msg1) != 0
	 || strcmp(buf2, msg2) != 0
	 || strcmp(buf3, msg3) != 0
	) {
		printf("ERROR! Expected order:\n%s%s%s", msg1, msg2, msg3);
		return 1;
	}
	printf("Good: wait seems to be correctly interrupted by signals\n");
	return 0;
}