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