Add `sigset64_t` and accompanying functions.
This doesn't address `struct sigaction` and `sigaction`. That will
come later.
Bug: http://b/72493232
Test: ran tests
Change-Id: I4134346757ce3a4dac6feae413361cec16223386
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index 5cbec88..ebc079e 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -20,57 +20,45 @@
#include <sys/types.h>
#include <unistd.h>
+#include <thread>
+
#include <gtest/gtest.h>
#include "ScopedSignalHandler.h"
-static size_t SIGNAL_MIN() {
+static int SIGNAL_MIN() {
return 1; // Signals start at 1 (SIGHUP), not 0.
}
-static size_t SIGNAL_MAX() {
- size_t result = SIGRTMAX;
-
-#if defined(__BIONIC__) && !defined(__mips__) && !defined(__LP64__)
- // 32-bit bionic's sigset_t is too small for ARM and x86: 32 bits instead of 64.
- // This means you can't refer to any of the real-time signals.
- // See http://b/3038348 and http://b/5828899.
- result = 32;
-#else
- // Otherwise, C libraries should be perfectly capable of using their largest signal.
- if (sizeof(sigset_t) * 8 < static_cast<size_t>(SIGRTMAX)) {
- abort();
- }
-#endif
-
- return result;
+template <typename SigSetT>
+static int SIGNAL_MAX(SigSetT* set) {
+ return sizeof(*set) * 8;
}
-template <typename Fn>
-static void TestSigSet1(Fn fn) {
- // NULL sigset_t*.
- sigset_t* set_ptr = NULL;
+template <typename SigSetT>
+static void TestSigSet1(int (fn)(SigSetT*)) {
+ // NULL sigset_t*/sigset64_t*.
+ SigSetT* set_ptr = NULL;
errno = 0;
ASSERT_EQ(-1, fn(set_ptr));
ASSERT_EQ(EINVAL, errno);
// Non-NULL.
- sigset_t set;
+ SigSetT set = {};
errno = 0;
ASSERT_EQ(0, fn(&set));
ASSERT_EQ(0, errno);
}
-template <typename Fn>
-static void TestSigSet2(Fn fn) {
- // NULL sigset_t*.
- sigset_t* set_ptr = NULL;
+template <typename SigSetT>
+static void TestSigSet2(int (fn)(SigSetT*, int)) {
+ // NULL sigset_t*/sigset64_t*.
+ SigSetT* set_ptr = NULL;
errno = 0;
ASSERT_EQ(-1, fn(set_ptr, SIGSEGV));
ASSERT_EQ(EINVAL, errno);
- sigset_t set;
- sigemptyset(&set);
+ SigSetT set = {};
// Bad signal number: too small.
errno = 0;
@@ -79,37 +67,67 @@
// Bad signal number: too high.
errno = 0;
- ASSERT_EQ(-1, fn(&set, SIGNAL_MAX() + 1));
+ ASSERT_EQ(-1, fn(&set, SIGNAL_MAX(&set) + 1));
ASSERT_EQ(EINVAL, errno);
// Good signal numbers, low and high ends of range.
errno = 0;
ASSERT_EQ(0, fn(&set, SIGNAL_MIN()));
ASSERT_EQ(0, errno);
- ASSERT_EQ(0, fn(&set, SIGNAL_MAX()));
+ ASSERT_EQ(0, fn(&set, SIGNAL_MAX(&set)));
ASSERT_EQ(0, errno);
}
-TEST(signal, sigismember_invalid) {
- TestSigSet2(sigismember);
-}
-
TEST(signal, sigaddset_invalid) {
TestSigSet2(sigaddset);
}
+TEST(signal, sigaddset64_invalid) {
+#if defined(__BIONIC__)
+ TestSigSet2(sigaddset64);
+#endif
+}
+
TEST(signal, sigdelset_invalid) {
TestSigSet2(sigdelset);
}
+TEST(signal, sigdelset64_invalid) {
+#if defined(__BIONIC__)
+ TestSigSet2(sigdelset64);
+#endif
+}
+
TEST(signal, sigemptyset_invalid) {
TestSigSet1(sigemptyset);
}
+TEST(signal, sigemptyset64_invalid) {
+#if defined(__BIONIC__)
+ TestSigSet1(sigemptyset64);
+#endif
+}
+
TEST(signal, sigfillset_invalid) {
TestSigSet1(sigfillset);
}
+TEST(signal, sigfillset64_invalid) {
+#if defined(__BIONIC__)
+ TestSigSet1(sigfillset64);
+#endif
+}
+
+TEST(signal, sigismember_invalid) {
+ TestSigSet2(sigismember);
+}
+
+TEST(signal, sigismember64_invalid) {
+#if defined(__BIONIC__)
+ TestSigSet2(sigismember64);
+#endif
+}
+
TEST(signal, raise_invalid) {
errno = 0;
ASSERT_EQ(-1, raise(-1));
@@ -129,12 +147,8 @@
raise(SIGALRM);
}
-static void HandleSIGALRM(int signal_number) {
- ASSERT_EQ(SIGALRM, signal_number);
-}
-
-TEST(signal, sigwait) {
- ScopedSignalHandler ssh(SIGALRM, HandleSIGALRM);
+TEST(signal, sigwait_SIGALRM) {
+ ScopedSignalHandler ssh(SIGALRM, [](int sig) { ASSERT_EQ(SIGALRM, sig); });
sigset_t wait_set;
sigemptyset(&wait_set);
@@ -149,38 +163,57 @@
ASSERT_EQ(SIGALRM, received_signal);
}
-static int g_sigsuspend_test_helper_call_count = 0;
+TEST(signal, sigwait64_SIGRTMIN) {
+ ScopedSignalHandler ssh(SIGRTMIN, [](int sig) { ASSERT_EQ(SIGRTMIN, sig); });
-static void SigSuspendTestHelper(int) {
- ++g_sigsuspend_test_helper_call_count;
+ sigset64_t wait_set;
+ sigemptyset64(&wait_set);
+ sigaddset64(&wait_set, SIGRTMIN);
+
+ pid_t pid = getpid();
+ std::thread thread([&pid]() {
+ usleep(5000);
+ kill(pid, SIGRTMIN);
+ });
+
+ int received_signal;
+ errno = 0;
+ ASSERT_EQ(0, sigwait64(&wait_set, &received_signal));
+ ASSERT_EQ(0, errno);
+ ASSERT_EQ(SIGRTMIN, received_signal);
+
+ thread.join();
}
+static int g_sigsuspend_signal_handler_call_count = 0;
+
TEST(signal, sigsuspend_sigpending) {
+ SignalMaskRestorer smr;
+
// Block SIGALRM.
sigset_t just_SIGALRM;
sigemptyset(&just_SIGALRM);
sigaddset(&just_SIGALRM, SIGALRM);
- sigset_t original_set;
- ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, &original_set));
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, nullptr));
- ScopedSignalHandler ssh(SIGALRM, SigSuspendTestHelper);
+ ScopedSignalHandler ssh(SIGALRM, [](int) { ++g_sigsuspend_signal_handler_call_count; });
// There should be no pending signals.
sigset_t pending;
sigemptyset(&pending);
ASSERT_EQ(0, sigpending(&pending));
- for (size_t i = SIGNAL_MIN(); i <= SIGNAL_MAX(); ++i) {
+ for (int i = SIGNAL_MIN(); i <= SIGNAL_MAX(&pending); ++i) {
EXPECT_FALSE(sigismember(&pending, i)) << i;
}
// Raise SIGALRM and check our signal handler wasn't called.
raise(SIGALRM);
- ASSERT_EQ(0, g_sigsuspend_test_helper_call_count);
+ ASSERT_EQ(0, g_sigsuspend_signal_handler_call_count);
// We should now have a pending SIGALRM but nothing else.
sigemptyset(&pending);
ASSERT_EQ(0, sigpending(&pending));
- for (size_t i = SIGNAL_MIN(); i <= SIGNAL_MAX(); ++i) {
+ for (int i = SIGNAL_MIN(); i <= SIGNAL_MAX(&pending); ++i) {
EXPECT_EQ((i == SIGALRM), sigismember(&pending, i));
}
@@ -191,10 +224,49 @@
ASSERT_EQ(-1, sigsuspend(¬_SIGALRM));
ASSERT_EQ(EINTR, errno);
// ...and check that we now receive our pending SIGALRM.
- ASSERT_EQ(1, g_sigsuspend_test_helper_call_count);
+ ASSERT_EQ(1, g_sigsuspend_signal_handler_call_count);
+}
- // Restore the original set.
- ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_set, NULL));
+static int g_sigsuspend64_signal_handler_call_count = 0;
+
+TEST(signal, sigsuspend64_sigpending64) {
+ SignalMaskRestorer smr;
+
+ // Block SIGRTMIN.
+ sigset64_t just_SIGRTMIN;
+ sigemptyset64(&just_SIGRTMIN);
+ sigaddset64(&just_SIGRTMIN, SIGRTMIN);
+ ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &just_SIGRTMIN, nullptr));
+
+ ScopedSignalHandler ssh(SIGRTMIN, [](int) { ++g_sigsuspend64_signal_handler_call_count; });
+
+ // There should be no pending signals.
+ sigset64_t pending;
+ sigemptyset64(&pending);
+ ASSERT_EQ(0, sigpending64(&pending));
+ for (int i = SIGNAL_MIN(); i <= SIGNAL_MAX(&pending); ++i) {
+ EXPECT_FALSE(sigismember64(&pending, i)) << i;
+ }
+
+ // Raise SIGRTMIN and check our signal handler wasn't called.
+ raise(SIGRTMIN);
+ ASSERT_EQ(0, g_sigsuspend64_signal_handler_call_count);
+
+ // We should now have a pending SIGRTMIN but nothing else.
+ sigemptyset64(&pending);
+ ASSERT_EQ(0, sigpending64(&pending));
+ for (int i = SIGNAL_MIN(); i <= SIGNAL_MAX(&pending); ++i) {
+ EXPECT_EQ((i == SIGRTMIN), sigismember64(&pending, i));
+ }
+
+ // Use sigsuspend64 to block everything except SIGRTMIN...
+ sigset64_t not_SIGRTMIN;
+ sigfillset64(¬_SIGRTMIN);
+ sigdelset64(¬_SIGRTMIN, SIGRTMIN);
+ ASSERT_EQ(-1, sigsuspend64(¬_SIGRTMIN));
+ ASSERT_EQ(EINTR, errno);
+ // ...and check that we now receive our pending SIGRTMIN.
+ ASSERT_EQ(1, g_sigsuspend64_signal_handler_call_count);
}
static void EmptySignalHandler(int) {}
@@ -301,12 +373,13 @@
}
TEST(signal, sigwaitinfo) {
+ SignalMaskRestorer smr;
+
// Block SIGALRM.
sigset_t just_SIGALRM;
sigemptyset(&just_SIGALRM);
sigaddset(&just_SIGALRM, SIGALRM);
- sigset_t original_set;
- ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, &original_set));
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, nullptr));
// Raise SIGALRM.
sigval_t sigval;
@@ -320,38 +393,75 @@
ASSERT_EQ(0, errno);
ASSERT_EQ(SIGALRM, info.si_signo);
ASSERT_EQ(1, info.si_value.sival_int);
+}
- ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_set, NULL));
+TEST(signal, sigwaitinfo64_SIGRTMIN) {
+ SignalMaskRestorer smr;
+
+ // Block SIGRTMIN.
+ sigset64_t just_SIGRTMIN;
+ sigemptyset64(&just_SIGRTMIN);
+ sigaddset64(&just_SIGRTMIN, SIGRTMIN);
+ ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &just_SIGRTMIN, nullptr));
+
+ // Raise SIGRTMIN.
+ sigval_t sigval;
+ sigval.sival_int = 1;
+ ASSERT_EQ(0, sigqueue(getpid(), SIGRTMIN, sigval));
+
+ // Get pending SIGRTMIN.
+ siginfo_t info;
+ errno = 0;
+ ASSERT_EQ(SIGRTMIN, sigwaitinfo64(&just_SIGRTMIN, &info));
+ ASSERT_EQ(0, errno);
+ ASSERT_EQ(SIGRTMIN, info.si_signo);
+ ASSERT_EQ(1, info.si_value.sival_int);
}
TEST(signal, sigtimedwait) {
+ SignalMaskRestorer smr;
+
// Block SIGALRM.
sigset_t just_SIGALRM;
sigemptyset(&just_SIGALRM);
sigaddset(&just_SIGALRM, SIGALRM);
- sigset_t original_set;
- ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, &original_set));
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &just_SIGALRM, nullptr));
// Raise SIGALRM.
- sigval_t sigval;
- sigval.sival_int = 1;
+ sigval_t sigval = { .sival_int = 1 };
ASSERT_EQ(0, sigqueue(getpid(), SIGALRM, sigval));
// Get pending SIGALRM.
siginfo_t info;
- struct timespec timeout;
- timeout.tv_sec = 2;
- timeout.tv_nsec = 0;
+ timespec timeout = { .tv_sec = 2, .tv_nsec = 0 };
errno = 0;
ASSERT_EQ(SIGALRM, sigtimedwait(&just_SIGALRM, &info, &timeout));
ASSERT_EQ(0, errno);
+}
- ASSERT_EQ(0, sigprocmask(SIG_SETMASK, &original_set, NULL));
+TEST(signal, sigtimedwait64_SIGRTMIN) {
+ SignalMaskRestorer smr;
+
+ // Block SIGRTMIN.
+ sigset64_t just_SIGRTMIN;
+ sigemptyset64(&just_SIGRTMIN);
+ sigaddset64(&just_SIGRTMIN, SIGRTMIN);
+ ASSERT_EQ(0, sigprocmask64(SIG_BLOCK, &just_SIGRTMIN, nullptr));
+
+ // Raise SIGALRM.
+ sigval_t sigval = { .sival_int = 1 };
+ ASSERT_EQ(0, sigqueue(getpid(), SIGRTMIN, sigval));
+
+ // Get pending SIGALRM.
+ siginfo_t info;
+ timespec timeout = { .tv_sec = 2, .tv_nsec = 0 };
+ errno = 0;
+ ASSERT_EQ(SIGRTMIN, sigtimedwait64(&just_SIGRTMIN, &info, &timeout));
+ ASSERT_EQ(0, errno);
}
static int64_t NanoTime() {
- struct timespec t;
- t.tv_sec = t.tv_nsec = 0;
+ timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
return static_cast<int64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
}
@@ -367,9 +477,7 @@
// Wait timeout.
int64_t start_time = NanoTime();
siginfo_t info;
- struct timespec timeout;
- timeout.tv_sec = 0;
- timeout.tv_nsec = 1000000;
+ timespec timeout = { .tv_sec = 0, .tv_nsec = 1000000 };
errno = 0;
ASSERT_EQ(-1, sigtimedwait(&just_SIGALRM, &info, &timeout));
ASSERT_EQ(EAGAIN, errno);
@@ -411,18 +519,20 @@
<< sent.si_code << ", received " << received.si_code
<< error_msg;
}
+#endif
-#if defined(__arm__) || defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
TEST(signal, sigset_size) {
// The setjmp implementations for ARM, AArch64, x86, and x86_64 assume that sigset_t can fit in a
// long. This is true because ARM and x86 have broken rt signal support, and AArch64 and x86_64
// both have a SIGRTMAX defined as 64.
+#if defined(__arm__) || defined(__aarch64__) || defined(__i386__) || defined(__x86_64__)
+#if defined(__BIONIC__)
static_assert(sizeof(sigset_t) <= sizeof(long), "sigset_t doesn't fit in a long");
+#endif
+ static_assert(sizeof(sigset64_t)*8 >= 64, "sigset64_t too small for real-time signals");
+#endif
}
-#endif
-#endif
-
TEST(signal, sigignore_EINVAL) {
errno = 0;
ASSERT_EQ(-1, sigignore(99999));