sigaction01.c revision d6d11d08678aac1ed2c370ea8e42e5f45aea07be
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 73void setup(); 74void cleanup(); 75 76char *TCID = "sigaction01"; 77int TST_TOTAL = 4; 78 79volatile sig_atomic_t testcase_no; 80volatile 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 */ 89void 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 */ 192int 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 */ 213void 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 */ 223void cleanup(void) 224{ 225 226} 227 228int 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