blob: e47d6b0432c3c0f7e2593141c99a820905547d33 [file] [log] [blame]
/*
*
* Copyright (c) International Business Machines Corp., 2001
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
* the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* NAME
* sigaction01.c
*
* DESCRIPTION
* Test some features of sigaction (see below for more details)
*
* ALGORITHM
* Use sigaction(2) to set a signal handler for SIGUSR1 with a certain
* set of flags, set a global variable indicating the test case, and
* finally send the signal to ourselves, causing the signal handler to
* run. The signal handler then checks the signal handler to run. The
* signal handler then checks certain conditions based on the test case
* number.
* There are 4 test cases:
*
* 1) Set SA_RESETHAND and SA_SIGINFO. When the handler runs,
* SA_SIGINFO should be set.
*
* 2) Set SA_RESETHAND. When the handler runs, SIGUSR1 should be
* masked (SA_RESETHAND makes sigaction behave as if SA_NODEFER was
* not set).
*
* 3) Same as case #2, but when the handler is established, sa_mask is
* set to include SIGUSR1. Ensure that SIGUSR1 is indeed masked even if
* SA_RESETHAND is set.
*
* 4) A signal generated from an interface or condition that does not
* provide siginfo (such as pthread_kill(3)) should invoke the handler
* with a non-NULL siginfo pointer.
*
* USAGE: <for command-line>
* sigaction01 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
* where, -c n : Run n copies concurrently.
* -f : Turn off functionality Testing.
* -i n : Execute test n times.
* -I x : Execute test for x seconds.
* -P x : Pause for x seconds between iterations.
* -t : Turn on syscall timing.
*
* HISTORY
* 07/2001 Ported by Wayne Boyer
*
* RESTRICTIONS
* NONE
*/
#include <pthread.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include "test.h"
void setup();
void cleanup();
char *TCID = "sigaction01";
int TST_TOTAL = 4;
volatile sig_atomic_t testcase_no;
volatile sig_atomic_t pass;
/*
* handler()
*
* A signal handler that understands which test case is currently
* being executed and compares the current conditions to the ones it
* expects (based on the test case number).
*/
void handler(int sig, siginfo_t * sip, void *ucp)
{
struct sigaction oact;
int err;
sigset_t nmask, omask;
/*
* Get sigaction setting
*/
err = sigaction(SIGUSR1, NULL, &oact);
if (err == -1) {
perror("sigaction");
return;
}
/*
* Get current signal mask
*/
sigemptyset(&nmask);
sigemptyset(&omask);
err = sigprocmask(SIG_BLOCK, &nmask, &omask);
if (err == -1) {
perror("sigprocmask");
tst_resm(TWARN, "sigprocmask() failed");
return;
}
switch (testcase_no) {
case 1:
/*
* SA_RESETHAND and SA_SIGINFO were set. SA_SIGINFO should
* be clear in Linux. In Linux kernel, SA_SIGINFO is not
* cleared in psig().
*/
if (!(oact.sa_flags & SA_SIGINFO)) {
tst_resm(TFAIL, "SA_RESETHAND should not "
"cause SA_SIGINFO to be cleared, but it was.");
return;
}
if (sip == NULL) {
tst_resm(TFAIL, "siginfo should not be NULL");
return;
}
tst_resm(TPASS, "SA_RESETHAND did not "
"cause SA_SIGINFO to be cleared");
break;
case 2:
/*
* In Linux, SA_RESETHAND doesn't imply SA_NODEFER; sig
* should not be masked. The testcase should pass if
* SA_NODEFER is not masked, ie. if SA_NODEFER is a member
* of the signal list
*/
if (sigismember(&omask, sig) == 0) {
tst_resm(TFAIL, "SA_RESETHAND should cause sig to"
"be masked when the handler executes.");
return;
}
tst_resm(TPASS, "SA_RESETHAND was masked when handler "
"executed");
break;
case 3:
/*
* SA_RESETHAND implies SA_NODEFER unless sa_mask already
* included sig.
*/
if (!sigismember(&omask, sig)) {
tst_resm(TFAIL, "sig should continue to be masked"
"because sa_mask originally contained sig.");
return;
}
tst_resm(TPASS, "sig has been masked "
"because sa_mask originally contained sig");
break;
case 4:
/*
* A signal generated from a mechanism that does not provide
* siginfo should invoke the handler with a non-NULL siginfo
* pointer.
*/
if (sip == NULL) {
tst_resm(TFAIL, "siginfo pointer should not be NULL");
return;
}
tst_resm(TPASS, "siginfo pointer non NULL");
break;
default:
tst_resm(TFAIL, "invalid test case number: %d", testcase_no);
exit(1);
}
}
/*
* set_handler()
*
* Establish a signal handler for SIGUSR1 with the specified flags and
* signal to mask while the handler executes.
*/
int set_handler(int flags, int sig_to_mask)
{
struct sigaction sa;
sa.sa_sigaction = handler;
sa.sa_flags = flags;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, sig_to_mask);
TEST(sigaction(SIGUSR1, &sa, NULL));
if (TEST_RETURN != 0) {
perror("sigaction");
tst_resm(TFAIL, "call failed unexpectedly");
return 1;
}
return 0;
}
/*
* setup() - performs all ONE TIME setup for this test.
*/
void setup(void)
{
TEST_PAUSE;
}
/*
* cleanup() - performs all ONE TIME cleanup for this test at
* completion or premature exit.
*/
void cleanup(void)
{
}
int main(int ac, char **av)
{
int lc;
const char *msg; /* message got from parse_opts */
int i;
int test_flags[] = { SA_RESETHAND | SA_SIGINFO, SA_RESETHAND,
SA_RESETHAND | SA_SIGINFO, SA_RESETHAND | SA_SIGINFO
};
if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) {
tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
}
setup();
for (lc = 0; TEST_LOOPING(lc); lc++) {
/* reset tst_count in case we are looping */
tst_count = 0;
testcase_no = 0;
for (i = 0; i < TST_TOTAL; i++) {
if (set_handler(test_flags[i], 0) == 0) {
testcase_no++;
switch (i) {
case 0:
/*FALLTHROUGH*/ case 1:
(void)kill(getpid(), SIGUSR1);
break;
case 2:
/*FALLTHROUGH*/ case 3:
(void)
pthread_kill(pthread_self(),
SIGUSR1);
break;
default:
tst_brkm(TBROK, cleanup,
"illegal case number");
break;
}
}
}
}
cleanup();
tst_exit();
}