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