// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) International Business Machines Corp., 2002
*
* AUTHORS
* Paul Larson
* Matthias Maennich
*
* DESCRIPTION
* Test to assert basic functionality of sigpending. All the tests can also be
* compiled to use the rt_sigpending syscall instead. To simplify the
* documentation, only sigpending() is usually mentioned below.
*
* Test 1:
* Suppress handling SIGUSR1 and SIGUSR1, raise them and assert their
* signal pending.
*
* Test 2:
* Call sigpending(sigset_t*=-1), it should return -1 with errno EFAULT
*/
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include "tst_test.h"
#include "ltp_signal.h"
#include "lapi/syscalls.h"
#if defined(TEST_SIGPENDING)
#define tested_sigpending(sigset) TEST(tst_syscall(__NR_sigpending, sigset))
#elif defined(TEST_RT_SIGPENDING)
#define tested_sigpending(sigset) \
TEST(tst_syscall(__NR_rt_sigpending, sigset, SIGSETSIZE))
#else
#error Neither TEST_SIGPENDING nor TEST_RT_SIGPENDING is defined!
#endif
static int sighandler_counter;
static void sighandler(int signum LTP_ATTRIBUTE_UNUSED)
{
++sighandler_counter;
}
static void test_sigpending(void)
{
int SIGMAX = MIN(sizeof(sigset_t) * 8, (size_t)_NSIG);
int i; /* loop index */
/* set up signal mask and handler */
sigset_t only_SIGUSR, old_mask;
sighandler_t old_sighandler1, old_sighandler2;
sigemptyset(&only_SIGUSR);
sigaddset(&only_SIGUSR, SIGUSR1);
sigaddset(&only_SIGUSR, SIGUSR2);
if (sigprocmask(SIG_SETMASK, &only_SIGUSR, &old_mask))
tst_brk(TBROK, "sigprocmask failed");
old_sighandler1 = SAFE_SIGNAL(SIGUSR1, sighandler);
old_sighandler2 = SAFE_SIGNAL(SIGUSR2, sighandler);
/* Initially no signal should be pending */
sigset_t pending;
sigemptyset(&pending);
tested_sigpending(&pending);
for (i = 1; i < SIGMAX; ++i)
if (sigismember(&pending, i))
tst_brk(TFAIL,
"initialization failed: no signal should be pending by now");
/* raise a signal */
if (raise(SIGUSR1))
tst_brk(TBROK, "raising SIGUSR1 failed");
if (sighandler_counter > 0)
tst_brk(TFAIL,
"signal handler is not (yet) supposed to be called");
/* now we should have exactly one pending signal (SIGUSR1) */
sigemptyset(&pending);
tested_sigpending(&pending);
for (i = 1; i < SIGMAX; ++i)
if ((i == SIGUSR1) != sigismember(&pending, i))
tst_brk(TFAIL, "only SIGUSR1 should be pending by now");
/* raise another signal */
if (raise(SIGUSR2))
tst_brk(TBROK, "raising SIGUSR2 failed");
if (sighandler_counter > 0)
tst_brk(TFAIL,
"signal handler is not (yet) supposed to be called");
/* now we should have exactly two pending signals (SIGUSR1, SIGUSR2) */
sigemptyset(&pending);
tested_sigpending(&pending);
for (i = 1; i < SIGMAX; ++i)
if ((i == SIGUSR1 || i == SIGUSR2) != sigismember(&pending, i))
tst_brk(TFAIL,
"only SIGUSR1, SIGUSR2 should be pending by now");
tst_res(TPASS, "basic sigpending test successful");
/* reinstate old mask */
if (sigprocmask(SIG_SETMASK, &old_mask, NULL))
tst_brk(TBROK, "sigprocmask failed");
/* at this time the signal handler has been called, once for each signal */
if (sighandler_counter != 2)
tst_brk(TFAIL,
"signal handler has not been called for each signal");
/* reinstate the original signal handlers */
SAFE_SIGNAL(SIGUSR1, old_sighandler1);
SAFE_SIGNAL(SIGUSR2, old_sighandler2);
}
static void test_efault_on_invalid_sigset(void)
{
/* set sigset to point to an invalid location */
sigset_t *sigset = tst_get_bad_addr(NULL);
tested_sigpending(sigset);
/* check return code */
if (TST_RET == -1) {
if (TST_ERR != EFAULT) {
tst_res(TFAIL | TTERRNO,
"syscall failed with wrong errno, expected errno=%d, got %d",
EFAULT, TST_ERR);
} else {
tst_res(TPASS | TTERRNO, "expected failure");
}
} else {
tst_res(TFAIL,
"syscall failed, expected return value=-1, got %ld",
TST_RET);
}
}
static void run(void)
{
test_sigpending();
test_efault_on_invalid_sigset();
}
static struct tst_test test = {
.test_all = run
};