1#include <unistd.h>
2#include <sys/types.h>
3#include <signal.h>
4#include <sys/wait.h>
5#include <stdio.h>
6#include <string.h>
7
8/* Expected order is:
9 * Child signals parent
10 * Parent got signal
11 * Child will exit now
12 *
13 * The bug we test for: under strace -f, last two lines are swapped
14 * because wait syscall is suspended by strace and thus can't be interrupted.
15 */
16
17static const char msg1[] = "Child signals parent\n";
18static const char msg2[] = "Parent got signal\n";
19static const char msg3[] = "Child will exit now\n";
20
21static void handler(int s)
22{
23	write(1, msg2, sizeof(msg2)-1);
24}
25
26static void test()
27{
28	/* Note: in Linux, signal() installs handler with SA_RESTART flag,
29	 * therefore wait will be restarted.
30	 */
31	signal(SIGALRM, handler);
32
33	if (fork() == 0) {
34		/* child */
35		sleep(1);
36		write(1, msg1, sizeof(msg1)-1);
37		kill(getppid(), SIGALRM);
38		sleep(1);
39		write(1, msg3, sizeof(msg3)-1);
40		_exit(0);
41	}
42
43	/* parent */
44	wait(NULL);
45	_exit(0);
46}
47
48int main()
49{
50	char buf1[80];
51	char buf2[80];
52	char buf3[80];
53	int pipefd[2];
54
55	printf("Please run me under 'strace -f'\n");
56
57	pipe(pipefd);
58
59	if (fork() == 0) {
60		if (pipefd[1] != 1) {
61			dup2(pipefd[1], 1);
62			close(pipefd[1]);
63		}
64		test();
65	}
66
67	if (pipefd[0] != 0) {
68		dup2(pipefd[0], 0);
69		close(pipefd[0]);
70	}
71	fgets(buf1, 80, stdin);	printf("%s", buf1);
72	fgets(buf2, 80, stdin);	printf("%s", buf2);
73	fgets(buf3, 80, stdin);	printf("%s", buf3);
74
75	if (strcmp(buf1, msg1) != 0
76	 || strcmp(buf2, msg2) != 0
77	 || strcmp(buf3, msg3) != 0
78	) {
79		printf("ERROR! Expected order:\n%s%s%s", msg1, msg2, msg3);
80		return 1;
81	}
82	printf("Good: wait seems to be correctly interrupted by signals\n");
83	return 0;
84}
85