C++程序  |  149行  |  3.99 KB

// 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
};