#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.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(void)
{
	/* 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(void)
{
	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;
}
