• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *
5  *   This program is free software;  you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  *   the GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program;  if not, write to the Free Software
17  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * NAME
22  * 	sigaction01.c
23  *
24  * DESCRIPTION
25  * 	Test some features of sigaction (see below for more details)
26  *
27  * ALGORITHM
28  * 	Use sigaction(2) to set a signal handler for SIGUSR1 with a certain
29  * 	set of flags, set a global variable indicating the test case, and
30  * 	finally send the signal to ourselves, causing the signal handler to
31  * 	run. The signal handler then checks the signal handler to run. The
32  * 	signal handler then checks certain conditions based on the test case
33  * 	number.
34  * 	There are 4 test cases:
35  *
36  * 	1) Set SA_RESETHAND and SA_SIGINFO. When the handler runs,
37  * 	SA_SIGINFO should be set.
38  *
39  * 	2) Set SA_RESETHAND. When the handler runs, SIGUSR1 should be
40  * 	masked (SA_RESETHAND makes sigaction behave as if SA_NODEFER was
41  * 	not set).
42  *
43  * 	3) Same as case #2, but when the handler is established, sa_mask is
44  * 	set to include SIGUSR1. Ensure that SIGUSR1 is indeed masked even if
45  * 	SA_RESETHAND is set.
46  *
47  * 	4) A signal generated from an interface or condition that does not
48  * 	provide siginfo (such as pthread_kill(3)) should invoke the handler
49  * 	with a non-NULL siginfo pointer.
50  *
51  * USAGE:  <for command-line>
52  * sigaction01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
53  *     where,  -c n : Run n copies concurrently.
54  *             -f   : Turn off functionality Testing.
55  *             -i n : Execute test n times.
56  *             -I x : Execute test for x seconds.
57  *             -P x : Pause for x seconds between iterations.
58  *             -t   : Turn on syscall timing.
59  *
60  * HISTORY
61  *	07/2001 Ported by Wayne Boyer
62  *
63  * RESTRICTIONS
64  *	NONE
65  */
66 #include <pthread.h>
67 #include <signal.h>
68 #include <errno.h>
69 #include <stdlib.h>
70 #include <unistd.h>
71 #include "test.h"
72 
73 void setup();
74 void cleanup();
75 
76 char *TCID = "sigaction01";
77 int TST_TOTAL = 4;
78 
79 volatile sig_atomic_t testcase_no;
80 volatile sig_atomic_t pass;
81 
82 /*
83  * handler()
84  *
85  * 	A signal handler that understands which test case is currently
86  * 	being executed and compares the current conditions to the ones it
87  * 	expects (based on the test case number).
88  */
handler(int sig,siginfo_t * sip,void * ucp)89 void handler(int sig, siginfo_t * sip, void *ucp)
90 {
91 	struct sigaction oact;
92 	int err;
93 	sigset_t nmask, omask;
94 
95 	/*
96 	 * Get sigaction setting
97 	 */
98 	err = sigaction(SIGUSR1, NULL, &oact);
99 
100 	if (err == -1) {
101 		perror("sigaction");
102 		return;
103 	}
104 
105 	/*
106 	 * Get current signal mask
107 	 */
108 	sigemptyset(&nmask);
109 	sigemptyset(&omask);
110 	err = sigprocmask(SIG_BLOCK, &nmask, &omask);
111 	if (err == -1) {
112 		perror("sigprocmask");
113 		tst_resm(TWARN, "sigprocmask() failed");
114 		return;
115 	}
116 
117 	switch (testcase_no) {
118 	case 1:
119 		/*
120 		 * SA_RESETHAND and SA_SIGINFO were set. SA_SIGINFO should
121 		 * be clear in Linux. In Linux kernel, SA_SIGINFO is not
122 		 * cleared in psig().
123 		 */
124 		if (!(oact.sa_flags & SA_SIGINFO)) {
125 			tst_resm(TFAIL, "SA_RESETHAND should not "
126 				 "cause SA_SIGINFO to be cleared, but it was.");
127 			return;
128 		}
129 		if (sip == NULL) {
130 			tst_resm(TFAIL, "siginfo should not be NULL");
131 			return;
132 		}
133 		tst_resm(TPASS, "SA_RESETHAND did not "
134 			 "cause SA_SIGINFO to be cleared");
135 		break;
136 
137 	case 2:
138 		/*
139 		 * In Linux, SA_RESETHAND doesn't imply SA_NODEFER; sig
140 		 * should not be masked.  The testcase should pass if
141 		 * SA_NODEFER is not masked, ie. if SA_NODEFER is a member
142 		 * of the signal list
143 		 */
144 		if (sigismember(&omask, sig) == 0) {
145 			tst_resm(TFAIL, "SA_RESETHAND should cause sig to"
146 				 "be masked when the handler executes.");
147 			return;
148 		}
149 		tst_resm(TPASS, "SA_RESETHAND was masked when handler "
150 			 "executed");
151 		break;
152 
153 	case 3:
154 		/*
155 		 * SA_RESETHAND implies SA_NODEFER unless sa_mask already
156 		 * included sig.
157 		 */
158 		if (!sigismember(&omask, sig)) {
159 			tst_resm(TFAIL, "sig should continue to be masked"
160 				 "because sa_mask originally contained sig.");
161 			return;
162 		}
163 		tst_resm(TPASS, "sig has been masked "
164 			 "because sa_mask originally contained sig");
165 		break;
166 
167 	case 4:
168 		/*
169 		 * A signal generated from a mechanism that does not provide
170 		 * siginfo should invoke the handler with a non-NULL siginfo
171 		 * pointer.
172 		 */
173 		if (sip == NULL) {
174 			tst_resm(TFAIL, "siginfo pointer should not be NULL");
175 			return;
176 		}
177 		tst_resm(TPASS, "siginfo pointer non NULL");
178 		break;
179 
180 	default:
181 		tst_resm(TFAIL, "invalid test case number: %d", testcase_no);
182 		exit(1);
183 	}
184 }
185 
186 /*
187  * set_handler()
188  *
189  * 	Establish a signal handler for SIGUSR1 with the specified flags and
190  * 	signal to mask while the handler executes.
191  */
set_handler(int flags,int sig_to_mask)192 int set_handler(int flags, int sig_to_mask)
193 {
194 	struct sigaction sa;
195 
196 	sa.sa_sigaction = handler;
197 	sa.sa_flags = flags;
198 	sigemptyset(&sa.sa_mask);
199 	sigaddset(&sa.sa_mask, sig_to_mask);
200 
201 	TEST(sigaction(SIGUSR1, &sa, NULL));
202 	if (TEST_RETURN != 0) {
203 		perror("sigaction");
204 		tst_resm(TFAIL, "call failed unexpectedly");
205 		return 1;
206 	}
207 	return 0;
208 }
209 
210 /*
211  * setup() - performs all ONE TIME setup for this test.
212  */
setup(void)213 void setup(void)
214 {
215 
216 	TEST_PAUSE;
217 }
218 
219 /*
220  * cleanup() - performs all ONE TIME cleanup for this test at
221  *	       completion or premature exit.
222  */
cleanup(void)223 void cleanup(void)
224 {
225 
226 }
227 
main(int ac,char ** av)228 int main(int ac, char **av)
229 {
230 	int lc;
231 	int i;
232 	int test_flags[] = { SA_RESETHAND | SA_SIGINFO, SA_RESETHAND,
233 		SA_RESETHAND | SA_SIGINFO, SA_RESETHAND | SA_SIGINFO
234 	};
235 
236 	tst_parse_opts(ac, av, NULL, NULL);
237 
238 	setup();
239 
240 	for (lc = 0; TEST_LOOPING(lc); lc++) {
241 
242 		/* reset tst_count in case we are looping */
243 		tst_count = 0;
244 
245 		testcase_no = 0;
246 
247 		for (i = 0; i < TST_TOTAL; i++) {
248 			if (set_handler(test_flags[i], 0) == 0) {
249 				testcase_no++;
250 				switch (i) {
251 				case 0:
252 				 /*FALLTHROUGH*/ case 1:
253 					(void)kill(getpid(), SIGUSR1);
254 					break;
255 				case 2:
256 				 /*FALLTHROUGH*/ case 3:
257 					(void)
258 					    pthread_kill(pthread_self(),
259 							 SIGUSR1);
260 					break;
261 				default:
262 					tst_brkm(TBROK, cleanup,
263 						 "illegal case number");
264 					break;
265 				}
266 			}
267 		}
268 	}
269 
270 	cleanup();
271 	tst_exit();
272 }
273