sigaction01.c revision 7d0a4a57fbcd47f72b67c08df532e8ef47f6fdae
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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#include "usctest.h" 73 74void setup(); 75void cleanup(); 76 77char *TCID = "sigaction01"; 78int TST_TOTAL = 4; 79extern int Tst_count; 80 81volatile sig_atomic_t testcase_no; 82volatile sig_atomic_t pass; 83 84/* 85 * handler() 86 * 87 * A signal handler that understands which test case is currently 88 * being executed and compares the current conditions to the ones it 89 * expects (based on the test case number). 90 */ 91void handler(int sig, siginfo_t * sip, void *ucp) 92{ 93 struct sigaction oact; 94 int err; 95 sigset_t nmask, omask; 96 97 /* 98 * Get sigaction setting 99 */ 100 err = sigaction(SIGUSR1, NULL, &oact); 101 102 if (err == -1) { 103 perror("sigaction"); 104 return; 105 } 106 107 /* 108 * Get current signal mask 109 */ 110 sigemptyset(&nmask); 111 sigemptyset(&omask); 112 err = sigprocmask(SIG_BLOCK, &nmask, &omask); 113 if (err == -1) { 114 perror("sigprocmask"); 115 tst_resm(TWARN, "sigprocmask() failed"); 116 return; 117 } 118 119 switch (testcase_no) { 120 case 1: 121 /* 122 * SA_RESETHAND and SA_SIGINFO were set. SA_SIGINFO should 123 * be clear in Linux. In Linux kernel, SA_SIGINFO is not 124 * cleared in psig(). 125 */ 126 if (!(oact.sa_flags & SA_SIGINFO)) { 127 tst_resm(TFAIL, "SA_RESETHAND should not " 128 "cause SA_SIGINFO to be cleared, but it was."); 129 return; 130 } 131 if (sip == NULL) { 132 tst_resm(TFAIL, "siginfo should not be NULL"); 133 return; 134 } 135 tst_resm(TPASS, "SA_RESETHAND did not " 136 "cause SA_SIGINFO to be cleared"); 137 break; 138 139 case 2: 140 /* 141 * In Linux, SA_RESETHAND doesn't imply SA_NODEFER; sig 142 * should not be masked. The testcase should pass if 143 * SA_NODEFER is not masked, ie. if SA_NODEFER is a member 144 * of the signal list 145 */ 146 if (sigismember(&omask, sig) == 0) { 147 tst_resm(TFAIL, "SA_RESETHAND should cause sig to" 148 "be masked when the handler executes."); 149 return; 150 } 151 tst_resm(TPASS, "SA_RESETHAND was masked when handler " 152 "executed"); 153 break; 154 155 case 3: 156 /* 157 * SA_RESETHAND implies SA_NODEFER unless sa_mask already 158 * included sig. 159 */ 160 if (!sigismember(&omask, sig)) { 161 tst_resm(TFAIL, "sig should continue to be masked" 162 "because sa_mask originally contained sig."); 163 return; 164 } 165 tst_resm(TPASS, "sig has been masked " 166 "because sa_mask originally contained sig"); 167 break; 168 169 case 4: 170 /* 171 * A signal generated from a mechanism that does not provide 172 * siginfo should invoke the handler with a non-NULL siginfo 173 * pointer. 174 */ 175 if (sip == NULL) { 176 tst_resm(TFAIL, "siginfo pointer should not be NULL"); 177 return; 178 } 179 tst_resm(TPASS, "siginfo pointer non NULL"); 180 break; 181 182 default: 183 tst_resm(TFAIL, "invalid test case number: %d", testcase_no); 184 exit(1); 185 } 186} 187 188/* 189 * set_handler() 190 * 191 * Establish a signal handler for SIGUSR1 with the specified flags and 192 * signal to mask while the handler executes. 193 */ 194int set_handler(int flags, int sig_to_mask) 195{ 196 struct sigaction sa; 197 198 sa.sa_sigaction = handler; 199 sa.sa_flags = flags; 200 sigemptyset(&sa.sa_mask); 201 sigaddset(&sa.sa_mask, sig_to_mask); 202 203 TEST(sigaction(SIGUSR1, &sa, NULL)); 204 if (TEST_RETURN != 0) { 205 perror("sigaction"); 206 tst_resm(TFAIL, "call failed unexpectedly"); 207 return 1; 208 } 209 return 0; 210} 211 212/* 213 * setup() - performs all ONE TIME setup for this test. 214 */ 215void setup() 216{ 217 218 TEST_PAUSE; 219} 220 221/* 222 * cleanup() - performs all ONE TIME cleanup for this test at 223 * completion or premature exit. 224 */ 225void cleanup() 226{ 227 /* 228 * print timing stats if that option was specified. 229 * print errno log if that option was specified. 230 */ 231 TEST_CLEANUP; 232 233} 234int main(int ac, char **av) 235{ 236 int lc; /* loop counter */ 237 char *msg; /* message got from parse_opts */ 238 int i; 239 int test_flags[] = { SA_RESETHAND | SA_SIGINFO, SA_RESETHAND, 240 SA_RESETHAND | SA_SIGINFO, SA_RESETHAND | SA_SIGINFO 241 }; 242 243 if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) { 244 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); 245 } 246 247 setup(); 248 249 for (lc = 0; TEST_LOOPING(lc); lc++) { 250 251 /* reset Tst_count in case we are looping */ 252 Tst_count = 0; 253 254 testcase_no = 0; 255 256 for (i = 0; i < TST_TOTAL; i++) { 257 if (set_handler(test_flags[i], 0) == 0) { 258 if (STD_FUNCTIONAL_TEST) { 259 testcase_no++; 260 switch (i) { 261 case 0: 262 /*FALLTHROUGH*/ case 1: 263 (void)kill(getpid(), SIGUSR1); 264 break; 265 case 2: 266 /*FALLTHROUGH*/ case 3: 267 (void) 268 pthread_kill(pthread_self(), 269 SIGUSR1); 270 break; 271 default: 272 tst_brkm(TBROK, cleanup, 273 "illegal case number"); 274 break; 275 } 276 } else { 277 tst_resm(TPASS, "call succeeded"); 278 } 279 } 280 } 281 } 282 cleanup(); 283 284 tst_exit(); 285}