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