signal_test_02.c revision 1be1c0c2f28892ffed0d2fcd34e551204060e22d
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 * Copyright (C) Bull S.A. 1996 22 * Level 1,5 Years Bull Confidential and Proprietary Information 23 */ 24 25/*---------------------------------------------------------------------+ 26| signal_test_02 | 27| ==================================================================== | 28| | 29| Description: Simplistic test to verify the signal system function | 30| calls: | 31| | 32| o Setup a signal-catching function for every possible | 33| signal. | 34| o Send signals to the process and verify that they | 35| were received by the signal-catching function. | 36| o Block a few signals by changing the process signal | 37| mask. Send signals to the process and verify that | 38| they indeed were blocked. | 39| o Add additional signals to the process signal mask. | 40| Verify that they were blocked too. | 41| o Change the process signal mask to unblock one | 42| signal and suspend execution of the process until | 43| the signal is received. Verify that the unblocked | 44| signal is received. | 45| | 46| System calls: The following system calls are tested: | 47| | 48| sigprocmask () - Sets the current signal mask | 49| sigemptyset () - Creates and manipulates signal masks | 50| sigfillset () - Creates and manipulates signal masks | 51| sigaddset () - Creates and manipulates signal masks | 52| sigdelset () - Creates and manipulates signal masks | 53| sigsuspend () - Atomically changes the set of blocked | 54| signals and waits for a signal | 55| sigaction () - Specifies the action to take upon | 56| delivery of a signal | 57| kill () - Sends a signal to a process | 58| | 59| Usage: signal_test_03 | 60| | 61| To compile: cc -o signal_test_03 signal_test_03 | 62| | 63| Last update: Ver. 1.2, 2/7/94 23:17:48 | 64| | 65| Change Activity | 66| | 67| Version Date Name Reason | 68| 0.1 050689 CTU Initial version | 69| 0.2 112293 DJK Rewrite for AIX version 4.1 | 70| 1.2 020794 DJK Move to "prod" directory | 71| 1.3 060501 VHM Port to work in linux | 72| | 73+---------------------------------------------------------------------*/ 74 75#define SIGMAX 64 /* What should this number really be? _NSIG from bits/signum.h maybe? */ 76 77#include <stdio.h> 78#include <stdlib.h> 79#include <errno.h> 80#include <signal.h> 81#include <string.h> 82#include <unistd.h> 83#include <sys/types.h> 84 85 86/* Macro for specifying signal masks */ 87#define MASK(sig) (1 << ((sig) - 1)) 88 89#include "signals.h" 90 91/* Function prototypes */ 92void init_sig (); 93void handler (int sig);//, int code, struct sigcontext *); 94void reset_valid_sig (); 95void sys_error (const char *, int); 96void error (const char *, int); 97 98 99/* Define an array for verifying received signals */ 100int valid_sig [ SIGMAX + 1 ]; 101 102 103/*---------------------------------------------------------------------+ 104| main () | 105| ==================================================================== | 106| | 107| Function: Main program (see prolog for more details) | 108| | 109+---------------------------------------------------------------------*/ 110int main (int argc, char **argv) 111{ 112 sigset_t setsig, /* Initial signal mask */ 113 newsetsig; /* Second signal mask */ 114 pid_t pid = getpid (); /* Process ID (of this process) */ 115 116 /* Print out program header */ 117 printf ("%s: IPC TestSuite program\n\n", *argv); 118 119 /* 120 * Establish signal handler for each signal & reset "valid signals" 121 * array 122 */ 123 init_sig (); 124 reset_valid_sig (); 125 126 sigemptyset(&setsig); 127 if (sigprocmask (SIG_SETMASK, &setsig, (sigset_t *) NULL) < 0) 128 sys_error ("sigprocmask failed", __LINE__); 129 130 /* 131 * Send SIGILL, SIGALRM & SIGIOT signals to this process: 132 * 133 * First indicate which signals the signal handler should expect 134 * by setting the corresponding valid_sig[] array fields. 135 * 136 * Then send the signals to this process. 137 * 138 * And finally verify that the signals were caught by the signal 139 * handler by checking to see if the corresponding valid_sig[] array 140 * fields were reset. 141 */ 142 printf ("\tSend SIGILL, SIGALRM, SIGIOT signals to process\n"); 143 valid_sig [SIGILL] = 1; 144 valid_sig [SIGALRM] = 1; 145 valid_sig [SIGIOT] = 1; 146 147 kill (pid, SIGILL); 148 kill (pid, SIGALRM); 149 kill (pid, SIGIOT); 150 151 if (valid_sig [SIGILL]) 152 error ("failed to receive SIGILL signal!", __LINE__); 153 if (valid_sig [SIGALRM]) 154 error ("failed to receive SIGALRM signal!", __LINE__); 155 if (valid_sig [SIGIOT]) 156 error ("failed to receive SIGIOT signal!", __LINE__); 157 158 /* 159 * Block SIGILL, SIGALRM & SIGIOT signals: 160 * 161 * First initialize the signal set so that all signals are excluded, 162 * then individually add the signals to block to the signal set. 163 * 164 * Then change the process signal mask with sigprocmask (SIG_SETMASK). 165 * 166 * Verify that the desired signals are blocked from interrupting the 167 * process, by sending both blocked and unblocked signals to the 168 * process. Only the unblocked signals should interrupt the process. 169 */ 170 printf ("\n\tBlock SIGILL, SIGALRM, SIGIOT signals, " \ 171 "and resend signals + others\n"); 172 sigemptyset(&setsig); 173 174 if (sigaddset (&setsig, SIGIOT) < 0) 175 sys_error ("sigaddset (SIGIOT) failed", __LINE__); 176 if (sigaddset (&setsig, SIGILL) < 0) 177 sys_error ("sigaddset (SIGILL) failed", __LINE__); 178 if (sigaddset (&setsig, SIGALRM) < 0) 179 sys_error ("sigaddset (SIGALRM) failed", __LINE__); 180 181 if (sigprocmask (SIG_SETMASK, &setsig, (sigset_t *) NULL) < 0) 182 sys_error ("sigaddset (SIGALRM) failed", __LINE__); 183 184 valid_sig [SIGFPE] = 1; 185 valid_sig [SIGTERM] = 1; 186 valid_sig [SIGINT] = 1; 187 188 kill (pid, SIGILL); 189 kill (pid, SIGALRM); 190 kill (pid, SIGIOT); 191 kill (pid, SIGFPE); 192 kill (pid, SIGTERM); 193 kill (pid, SIGINT); 194 195 if (valid_sig [SIGFPE]) 196 sys_error ("failed to receive SIGFPE signal!", __LINE__); 197 if (valid_sig [SIGTERM]) 198 sys_error ("failed to receive SIGTERM signal!", __LINE__); 199 if (valid_sig [SIGINT]) 200 sys_error ("failed to receive SIGINT signal!", __LINE__); 201 202 /* 203 * Block additional SIGFPE, SIGTERM & SIGINT signals: 204 * 205 * Create an other signal set to contain the additional signals to block 206 * and add the signals to block to the signal set. 207 * 208 * Change the process signal mask to block the additional signals 209 * with the sigprocmask (SIG_BLOCK) function. 210 * 211 * Verify that all of the desired signals are now blocked from 212 * interrupting the process. None of the specified signals should 213 * interrupt the process until the process signal mask is changed. 214 */ 215 printf ("\n\tBlock rest of signals\n"); 216 sigemptyset (&newsetsig); 217 218 sigaddset (&newsetsig, SIGFPE); 219 sigaddset (&newsetsig, SIGTERM); 220 sigaddset (&newsetsig, SIGINT); 221 222 if (sigprocmask (SIG_BLOCK, &newsetsig, &setsig) < 0) 223 sys_error ("sigprocmask failed", __LINE__); 224 225 kill (pid, SIGILL); 226 kill (pid, SIGALRM); 227 kill (pid, SIGIOT); 228 kill (pid, SIGFPE); 229 kill (pid, SIGTERM); 230 kill (pid, SIGINT); 231 232 /* 233 * Wait two seconds just to make sure that none of the specified 234 * signals interrupt the process (They should all be blocked). 235 */ 236 sleep (2); 237 238 /* 239 * Change the process signal mask: 240 * 241 * Now specifiy a new process signal set to allow the SIGINT signal 242 * to interrupt the process. Create the signal set by initializing 243 * the signal set with sigfillset () so that all signals are included 244 * in the signal set, then remove the SIGINT signal from the set with 245 * sigdelset (). 246 * 247 * Force the process to suspend execution until delivery of an 248 * unblocked signal (SIGINT in this case) with sigsuspend (). 249 * 250 * Additionally, verify that the SIGINT signal was received. 251 */ 252 valid_sig [SIGINT] = 1; 253 254 printf ("\n\tChange signal mask & wait until signal interrupts process\n"); 255 if (sigfillset (&setsig) < 0) 256 sys_error ("sigfillset failed", __LINE__); 257 if (sigdelset (&setsig, SIGINT) < 0) 258 sys_error ("sigdelset failed", __LINE__); 259 if (sigsuspend(&setsig) != -1 || errno != 4) 260 sys_error ("sigsuspend failed", __LINE__); 261 262 if (valid_sig [SIGINT]) 263 error ("failed to receive SIGIOT signal!", __LINE__); 264 265 /* Program completed successfully -- exit */ 266 printf ("\nsuccessful!\n"); 267 268 return (0); 269} 270 271 272/*---------------------------------------------------------------------+ 273| init_sig () | 274| ==================================================================== | 275| | 276| Function: Initialize the signal vector for ALL possible signals | 277| (as defined in /usr/include/sys/signal.h) except for | 278| the following signals which cannot be caught or ignored: | 279| | 280| o SIGKILL (9) | 281| o SIGSTOP (17) | 282| o SIGCONT (19) | 283| | 284| Returns: n/a | 285| | 286+---------------------------------------------------------------------*/ 287void init_sig () 288{ 289 struct sigaction invec; 290 char msg [256]; /* Buffer for error message */ 291 int i; 292 293 for (i=1; i<=SIGMAX; i++) { 294 295 /* Cannot catch or ignore the following signals */ 296#ifdef _IA64 /* SIGWAITING not supported, RESERVED */ 297 if ((i == SIGKILL) || (i == SIGSTOP) || 298 (i == SIGCONT) || (i == SIGWAITING)) continue; 299#else 300# ifdef _LINUX_ 301 if ((i == SIGKILL) || (i == SIGSTOP) || ((i>=32)&&(i<=34))) continue; 302# else 303 if (i == SIGKILL || i == SIGSTOP || i == SIGCONT) continue; 304# endif 305#endif 306 307 invec.sa_handler = (void (*)(int)) handler; 308 sigemptyset (&invec.sa_mask); 309 invec.sa_flags = 0; 310 311 if (sigaction (i, &invec, (struct sigaction *) NULL) < 0) { 312 sprintf (msg, "sigaction failed on signal %d", i); 313 error (msg, __LINE__); 314 } 315 } 316} 317 318/*---------------------------------------------------------------------+ 319| handler () | 320| ==================================================================== | 321| | 322| Function: Signal catching function. As specified in init_sig_vec() | 323| this function is automatically called each time a signal | 324| is received by the process. | 325| | 326| Once receiving the signal, verify that the corresponding | 327| signal was expected. | 328| | 329| Returns: Aborts program if an unexpected signal was received. | 330| | 331+---------------------------------------------------------------------*/ 332void handler (int sig)//, int code, struct sigcontext *scp) 333{ 334 char msg [256]; 335 336 /* Check to insure that expected signal was received */ 337 if (valid_sig [sig]) { 338 valid_sig [sig] = 0; 339 printf ("\treceived signal: (%s)\n", signames[sig]); 340 } else { 341 sprintf (msg, "unexpected signal (%d,%s)", sig, (sig<32)?signames[sig]:"unknown signal"); 342 error (msg, __LINE__); 343 } 344} 345 346 347/*---------------------------------------------------------------------+ 348| reset_valid_sig () | 349| ==================================================================== | 350| | 351| Function: Reset the valid "signal" array | 352| | 353| Returns: n/a | 354| | 355+---------------------------------------------------------------------*/ 356void reset_valid_sig () 357{ 358 int i; 359 360 for (i=0; i< (SIGMAX + 1); i++) 361 valid_sig [i] = 0; 362} 363 364 365/*---------------------------------------------------------------------+ 366| sys_error () | 367| ==================================================================== | 368| | 369| Function: Creates system error message and calls error () | 370| | 371+---------------------------------------------------------------------*/ 372void sys_error (const char *msg, int line) 373{ 374 char syserr_msg [256]; 375 376 sprintf (syserr_msg, "%s: %s\n", msg, strerror (errno)); 377 error (syserr_msg, line); 378} 379 380 381/*---------------------------------------------------------------------+ 382| error () | 383| ==================================================================== | 384| | 385| Function: Prints out message and exits... | 386| | 387+---------------------------------------------------------------------*/ 388void error (const char *msg, int line) 389{ 390 fprintf (stderr, "ERROR [line: %d] %s\n", line, msg); 391 exit (-1); 392} 393