1/*
2 * Copyright (c) 2003, Intel Corporation. All rights reserved.
3 * Created by:  salwan.searty REMOVE-THIS AT intel DOT com
4 * This file is licensed under the GPL license.  For the full content
5 * of this license, see the COPYING file at the top level of this
6 * source tree.
7
8 Assumption: The test assumes that this program is run under normal conditions,
9 and not when the processor and other resources are too stressed.
10
11 This program tries to verify two things:
12
13 1. sigsuspend() replaces the original signal mask (containing SIGUSR1)
14    with the new signal mask (containing SIGUSR2.) This can be accomplished
15    by having the child call sigsuspend, and then have the parent send the
16    child a SIGUSR2 signal. The signal should remain pending while as long
17    as the child is suspended. How do we verify that a signal is pending?
18    Well, if it wasn't for the fact that the child is suspended, we could
19    have easily called the sigpending() from the child process. Because
20    the child is suspended, we have to somehow verify that the signal is
21    pending using only the parent process. This is acheived by having the
22    parent send the child another signal, one that will cause the child to
23    resume execution. If the SIGUSR2 is only delivered after sigsuspend
24    returns, then that means that SIGUSR2 has in fact been pending while
25    the child was suspended, and therefore that proves that sigsuspend()
26    did successfully temporarily replace the original signal mask with one
27    containing only SIGUSR2.
28
29 2. The child process is suspended until the parent process delivers
30    SIGUSR1. We verify this using the following rationale: Via the 3 seconds of
31    sleep at the very start of the parent section of the code, the parent
32    process allowed for enough time for the child process to complete execution
33    and get to the "return 2" line at the very end of the child's code, but the
34    parent didn't allow for any time in which the child may have been suspended.
35    Because the child did recieve the signal that the parent later sent before
36    the child finished executing, that had to have meant that the child was
37    suspended for a while during it's execution.
38
39*/
40
41#include <signal.h>
42#include <sys/types.h>
43#include <sys/wait.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <unistd.h>
47#include "posixtest.h"
48
49int SIGUSR1_called = 0;
50int SIGUSR2_called = 0;
51
52void handler(int signo)
53{
54	if (signo == SIGUSR1) {
55		printf("SIGUSR1 called. Inside handler\n");
56		SIGUSR1_called = 1;
57		if (SIGUSR2_called == 1) {
58			exit(1);
59		}
60	}
61	else if (signo == SIGUSR2) {
62		printf("SIGUSR2 called. Inside handler\n");
63		SIGUSR2_called = 1;
64		if (SIGUSR1_called == 1)
65			exit(0);
66		else
67			exit(1);
68	}
69}
70
71int main()
72{
73	pid_t pid;
74	pid = fork();
75
76	if (pid == 0) {
77		/* child */
78
79	        sigset_t tempmask, originalmask;
80
81	        struct sigaction act;
82
83	        act.sa_handler = handler;
84	        act.sa_flags=0;
85	        sigemptyset(&act.sa_mask);
86
87	        sigemptyset(&tempmask);
88		sigaddset(&tempmask, SIGUSR2);
89
90	        if (sigaction(SIGUSR1,  &act, 0) == -1) {
91	                perror("Unexpected error while attempting to pre-conditions");
92                	return PTS_UNRESOLVED;
93	        }
94
95	        if (sigaction(SIGUSR2,  &act, 0) == -1) {
96	                perror("Unexpected error while attempting to pre-conditions");
97                	return PTS_UNRESOLVED;
98	        }
99
100	        sigemptyset(&originalmask);
101		sigaddset(&originalmask, SIGUSR1);
102		sigprocmask(SIG_SETMASK, &originalmask, NULL);
103
104		printf("suspending child\n");
105	        if (sigsuspend(&tempmask) != -1)
106	                perror("sigsuspend error");
107
108	        printf("returned from suspend\n");
109		sleep(1);
110		return 2;
111
112	} else {
113		int s;
114		int exit_status;
115
116		/* parent */
117		sleep(3);
118
119		printf("parent sending child a SIGUSR2 signal\n");
120		kill (pid, SIGUSR2);
121
122		if (SIGUSR2_called == 1) {
123                        printf("Test FAILED: sigsuspend did not add SIGUSR2 to the temporary mask\n");
124                        return PTS_FAIL;
125		}
126		printf("parent sending child a SIGUSR1 signal\n");
127		kill (pid, SIGUSR1);
128
129		if (wait(&s) == -1) {
130			perror("Unexpected error while setting up test "
131			       "pre-conditions");
132			return PTS_UNRESOLVED;
133		}
134
135		if (!WIFEXITED(s)) {
136			printf("Test FAILED: Did not exit normally\n");
137			return PTS_FAIL;
138		}
139
140		exit_status = WEXITSTATUS(s);
141
142		printf("Exit status from child is %d\n", exit_status);
143
144                if (exit_status == 1) {
145                        printf("Test UNRESOLVED: Either sigsuspend did not successfully block SIGUSR2, OR sigsuspend returned before handling the signal SIGUSR1\n");
146                        return PTS_UNRESOLVED;
147                }
148
149                if (exit_status == 2) {
150                        printf("Test FAILED: sigsuspend did not suspend the child\n");
151                        return PTS_FAIL;
152                }
153
154		printf("Test PASSED\n");
155		return PTS_PASS;
156	}
157}
158