Merge "Add SysV signal handling"
diff --git a/libc/Android.mk b/libc/Android.mk
index e9ee7fc..4cef97a 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -174,12 +174,17 @@
bionic/sigdelset.cpp \
bionic/sigemptyset.cpp \
bionic/sigfillset.cpp \
+ bionic/sighold.cpp \
+ bionic/sigignore.cpp \
bionic/sigismember.cpp \
bionic/signal.cpp \
bionic/signalfd.cpp \
+ bionic/sigpause.cpp \
bionic/sigpending.cpp \
bionic/sigprocmask.cpp \
bionic/sigqueue.cpp \
+ bionic/sigrelse.cpp \
+ bionic/sigset.cpp \
bionic/sigsuspend.cpp \
bionic/sigtimedwait.cpp \
bionic/sigwait.cpp \
diff --git a/libc/bionic/sighold.cpp b/libc/bionic/sighold.cpp
new file mode 100644
index 0000000..e9c8ca1
--- /dev/null
+++ b/libc/bionic/sighold.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+
+int sighold(int sig) {
+ sigset_t set;
+ if (sigemptyset(&set) == -1) return -1;
+ if (sigaddset(&set, sig) == -1) return -1;
+ return sigprocmask(SIG_BLOCK, &set, nullptr);
+}
diff --git a/libc/bionic/sigignore.cpp b/libc/bionic/sigignore.cpp
new file mode 100644
index 0000000..06f458e
--- /dev/null
+++ b/libc/bionic/sigignore.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+#include <string.h>
+
+int sigignore(int sig) {
+ struct sigaction sa;
+ memset(&sa, 0, sizeof(sa));
+ if (sigemptyset(&sa.sa_mask) == -1) return -1;
+ sa.sa_handler = SIG_IGN;
+ return sigaction(sig, &sa, nullptr);
+}
diff --git a/libc/bionic/sigpause.cpp b/libc/bionic/sigpause.cpp
new file mode 100644
index 0000000..8ba42d4
--- /dev/null
+++ b/libc/bionic/sigpause.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+
+int sigpause(int sig) {
+ sigset_t set;
+ if (sigprocmask(SIG_SETMASK, nullptr, &set) == -1) return -1;
+ if (sigdelset(&set, sig) == -1) return -1;
+ return sigsuspend(&set);
+}
diff --git a/libc/bionic/sigrelse.cpp b/libc/bionic/sigrelse.cpp
new file mode 100644
index 0000000..ab5554e
--- /dev/null
+++ b/libc/bionic/sigrelse.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+
+int sigrelse(int sig) {
+ sigset_t set;
+ if (sigemptyset(&set) == -1) return -1;
+ if (sigaddset(&set, sig) == -1) return -1;
+ return sigprocmask(SIG_UNBLOCK, &set, nullptr);
+}
diff --git a/libc/bionic/sigset.cpp b/libc/bionic/sigset.cpp
new file mode 100644
index 0000000..e3f3e72
--- /dev/null
+++ b/libc/bionic/sigset.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <signal.h>
+#include <string.h>
+
+sighandler_t sigset(int sig, sighandler_t disp) {
+ struct sigaction new_sa;
+ if (disp != SIG_HOLD) {
+ memset(&new_sa, 0, sizeof(new_sa));
+ new_sa.sa_handler = disp;
+ sigemptyset(&new_sa.sa_mask);
+ }
+
+ struct sigaction old_sa;
+ if (sigaction(sig, disp == SIG_HOLD ? nullptr : &new_sa, &old_sa) == -1) {
+ return SIG_ERR;
+ }
+
+ sigset_t new_proc_mask;
+ sigemptyset(&new_proc_mask);
+ sigaddset(&new_proc_mask, sig);
+
+ sigset_t old_proc_mask;
+ if (sigprocmask(disp == SIG_HOLD ? SIG_BLOCK : SIG_UNBLOCK,
+ &new_proc_mask, &old_proc_mask) == -1) {
+ return SIG_ERR;
+ }
+
+ return sigismember(&old_proc_mask, sig) ? SIG_HOLD : old_sa.sa_handler;
+}
diff --git a/libc/include/signal.h b/libc/include/signal.h
index 85c46c0..763bae9 100644
--- a/libc/include/signal.h
+++ b/libc/include/signal.h
@@ -64,6 +64,11 @@
#define _NSIG (_KERNEL__NSIG + 1)
#define NSIG _NSIG
+/* The kernel headers define SIG_DFL (0) and SIG_IGN (1) but not SIG_HOLD, since
+ * SIG_HOLD is only used by the deprecated SysV signal API.
+ */
+#define SIG_HOLD ((sighandler_t)(uintptr_t)2)
+
/* We take a few real-time signals for ourselves. May as well use the same names as glibc. */
#define SIGRTMIN (__libc_current_sigrtmin())
#define SIGRTMAX (__libc_current_sigrtmax())
@@ -120,6 +125,12 @@
extern int sigsuspend(const sigset_t*) __nonnull((1));
extern int sigwait(const sigset_t*, int*) __nonnull((1, 2));
+extern int sighold(int) __attribute__((deprecated("use sigprocmask() or pthread_sigmask() instead")));
+extern int sigignore(int) __attribute__((deprecated("use sigaction() instead")));
+extern int sigpause(int) __attribute__((deprecated("use sigsuspend() instead")));
+extern int sigrelse(int) __attribute__((deprecated("use sigprocmask() or pthread_sigmask() instead")));
+extern sighandler_t sigset(int, sighandler_t) __attribute__((deprecated("use sigaction() instead")));
+
extern int raise(int);
extern int kill(pid_t, int);
extern int killpg(int, int);
diff --git a/libc/libc.arm.brillo.map b/libc/libc.arm.brillo.map
index b8cdd3c..054b9be 100644
--- a/libc/libc.arm.brillo.map
+++ b/libc/libc.arm.brillo.map
@@ -1277,6 +1277,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.arm.map b/libc/libc.arm.map
index 57060ae..6177627 100644
--- a/libc/libc.arm.map
+++ b/libc/libc.arm.map
@@ -1277,6 +1277,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.arm64.map b/libc/libc.arm64.map
index ac9d009..15d6764 100644
--- a/libc/libc.arm64.map
+++ b/libc/libc.arm64.map
@@ -1199,6 +1199,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.map.txt b/libc/libc.map.txt
index 9d51b8d..7332c08 100644
--- a/libc/libc.map.txt
+++ b/libc/libc.map.txt
@@ -1303,6 +1303,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.mips.brillo.map b/libc/libc.mips.brillo.map
index 7133f4b..5af070e 100644
--- a/libc/libc.mips.brillo.map
+++ b/libc/libc.mips.brillo.map
@@ -1261,6 +1261,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.mips.map b/libc/libc.mips.map
index e9b15c3..98f1a29 100644
--- a/libc/libc.mips.map
+++ b/libc/libc.mips.map
@@ -1261,6 +1261,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.mips64.map b/libc/libc.mips64.map
index ac9d009..15d6764 100644
--- a/libc/libc.mips64.map
+++ b/libc/libc.mips64.map
@@ -1199,6 +1199,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.x86.brillo.map b/libc/libc.x86.brillo.map
index c67f533..5459b0b 100644
--- a/libc/libc.x86.brillo.map
+++ b/libc/libc.x86.brillo.map
@@ -1260,6 +1260,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.x86.map b/libc/libc.x86.map
index 6838184..050f047 100644
--- a/libc/libc.x86.map
+++ b/libc/libc.x86.map
@@ -1260,6 +1260,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/libc/libc.x86_64.map b/libc/libc.x86_64.map
index ac9d009..15d6764 100644
--- a/libc/libc.x86_64.map
+++ b/libc/libc.x86_64.map
@@ -1199,6 +1199,11 @@
hasmntopt;
pthread_getname_np;
setdomainname;
+ sighold;
+ sigignore;
+ sigpause;
+ sigrelse;
+ sigset;
} LIBC_N;
LIBC_PRIVATE {
diff --git a/tests/Android.mk b/tests/Android.mk
index aeb10ea..7fdf2f4 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -38,6 +38,10 @@
-Werror \
-fno-builtin \
+# We want to test deprecated API too.
+test_cflags += \
+ -Wno-deprecated-declarations \
+
test_cflags += -D__STDC_LIMIT_MACROS # For glibc.
test_cppflags := \
diff --git a/tests/ScopedSignalHandler.h b/tests/ScopedSignalHandler.h
index 3fb60a1..8998d0d 100644
--- a/tests/ScopedSignalHandler.h
+++ b/tests/ScopedSignalHandler.h
@@ -39,6 +39,10 @@
sigaction(signal_number_, &action_, &old_action_);
}
+ ScopedSignalHandler(int signal_number) : signal_number_(signal_number) {
+ sigaction(signal_number, nullptr, &old_action_);
+ }
+
~ScopedSignalHandler() {
sigaction(signal_number_, &old_action_, NULL);
}
@@ -49,4 +53,18 @@
const int signal_number_;
};
+class ScopedSignalMask {
+ public:
+ ScopedSignalMask() {
+ sigprocmask(SIG_SETMASK, nullptr, &old_mask_);
+ }
+
+ ~ScopedSignalMask() {
+ sigprocmask(SIG_SETMASK, &old_mask_, nullptr);
+ }
+
+ private:
+ sigset_t old_mask_;
+};
+
#endif // _BIONIC_TESTS_SCOPED_SIGNAL_HANDLER_H
diff --git a/tests/signal_test.cpp b/tests/signal_test.cpp
index c5128ea..36ac690 100644
--- a/tests/signal_test.cpp
+++ b/tests/signal_test.cpp
@@ -422,3 +422,108 @@
#endif
#endif
+
+TEST(signal, sigignore_EINVAL) {
+ errno = 0;
+ ASSERT_EQ(-1, sigignore(99999));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(signal, sigignore) {
+ errno = 0;
+ EXPECT_EQ(-1, sigignore(SIGKILL));
+ EXPECT_EQ(errno, EINVAL);
+
+ errno = 0;
+ EXPECT_EQ(-1, sigignore(SIGSTOP));
+ EXPECT_EQ(errno, EINVAL);
+
+ ScopedSignalHandler sigalrm{SIGALRM};
+ ASSERT_EQ(0, sigignore(SIGALRM));
+
+ struct sigaction sa;
+ ASSERT_EQ(0, sigaction(SIGALRM, nullptr, &sa));
+ EXPECT_EQ(SIG_IGN, sa.sa_handler);
+}
+
+TEST(signal, sighold_EINVAL) {
+ errno = 0;
+ ASSERT_EQ(-1, sighold(99999));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(signal, sigpause_EINVAL) {
+ errno = 0;
+ ASSERT_EQ(-1, sigpause(99999));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(signal, sigrelse_EINVAL) {
+ errno = 0;
+ ASSERT_EQ(-1, sigpause(99999));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(signal, sighold_sigpause_sigrelse) {
+ static int sigalrm_handler_call_count;
+ auto sigalrm_handler = [](int) { sigalrm_handler_call_count++; };
+ ScopedSignalHandler sigalrm{SIGALRM, sigalrm_handler};
+ ScopedSignalMask mask;
+ sigset_t set;
+
+ // sighold(SIGALRM) should add SIGALRM to the signal mask ...
+ ASSERT_EQ(0, sighold(SIGALRM));
+ ASSERT_EQ(0, sigprocmask(SIG_SETMASK, 0, &set));
+ EXPECT_TRUE(sigismember(&set, SIGALRM));
+
+ // ... preventing our SIGALRM handler from running ...
+ raise(SIGALRM);
+ ASSERT_EQ(0, sigalrm_handler_call_count);
+ // ... until sigpause(SIGALRM) temporarily unblocks it.
+ ASSERT_EQ(-1, sigpause(SIGALRM));
+ ASSERT_EQ(EINTR, errno);
+ ASSERT_EQ(1, sigalrm_handler_call_count);
+
+ // But sigpause(SIGALRM) shouldn't permanently unblock SIGALRM.
+ ASSERT_EQ(0, sigprocmask(SIG_SETMASK, 0, &set));
+ EXPECT_TRUE(sigismember(&set, SIGALRM));
+
+ ASSERT_EQ(0, sigrelse(SIGALRM));
+ ASSERT_EQ(0, sigprocmask(SIG_SETMASK, 0, &set));
+ EXPECT_FALSE(sigismember(&set, SIGALRM));
+}
+
+TEST(signal, sigset_EINVAL) {
+ errno = 0;
+ ASSERT_EQ(SIG_ERR, sigset(99999, SIG_DFL));
+ ASSERT_EQ(EINVAL, errno);
+}
+
+TEST(signal, sigset) {
+ auto sigalrm_handler = [](int) { };
+ ScopedSignalHandler sigalrm{SIGALRM, sigalrm_handler};
+ ScopedSignalMask mask;
+
+ // block SIGALRM so the next sigset(SIGARLM) call will return SIG_HOLD
+ sigset_t sigalrm_set;
+ sigemptyset(&sigalrm_set);
+ sigaddset(&sigalrm_set, SIGALRM);
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, &sigalrm_set, nullptr));
+
+ sigset_t set;
+ ASSERT_EQ(SIG_HOLD, sigset(SIGALRM, sigalrm_handler));
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, nullptr, &set));
+ EXPECT_FALSE(sigismember(&set, SIGALRM));
+
+ ASSERT_EQ(sigalrm_handler, sigset(SIGALRM, SIG_IGN));
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, nullptr, &set));
+ EXPECT_FALSE(sigismember(&set, SIGALRM));
+
+ ASSERT_EQ(SIG_IGN, sigset(SIGALRM, SIG_DFL));
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, nullptr, &set));
+ EXPECT_FALSE(sigismember(&set, SIGALRM));
+
+ ASSERT_EQ(SIG_DFL, sigset(SIGALRM, SIG_HOLD));
+ ASSERT_EQ(0, sigprocmask(SIG_BLOCK, nullptr, &set));
+ EXPECT_TRUE(sigismember(&set, SIGALRM));
+}