[libc-commits] [libc] c70dfc1 - [libc] Implement sigismember in signal (#234838)
via libc-commits
libc-commits at lists.llvm.org
Fri Oct 23 02:24:32 PDT 2026
Author: Aman Maurya
Date: 2026-10-23T14:54:26+05:30
New Revision: c70dfc1711bddd0aa7e3acff4224bc2a363092b9
URL: https://github.com/llvm/llvm-project/commit/c70dfc1711bddd0aa7e3acff4224bc2a363092b9
DIFF: https://github.com/llvm/llvm-project/commit/c70dfc1711bddd0aa7e3acff4224bc2a363092b9.diff
LOG: [libc] Implement sigismember in signal (#234838)
### Summary
Implement the standard POSIX function `sigismember` in `<signal.h>`.
- Adds internal helper `signals::is_member` returning `ErrorOr<int>` in
`libc/src/__support/OSUtil/linux/sigmask.h`.
- Implements the `sigismember` public entrypoint in
`libc/src/signal/linux/sigismember.cpp`.
- Declares `sigismember` in `libc/include/signal.yaml` and
`libc/utils/docgen/signal.yaml`.
- Registers entrypoints for Linux (`x86_64`, `aarch64`, `riscv`).
- Adds unit tests in `libc/test/src/signal/sigismember_test.cpp`.
- Resolves existing TODO in `libc/test/src/ucontext/ucontext_test.cpp`
by using `sigismember`.
Fixes #234066.
Added:
libc/src/signal/linux/sigismember.cpp
libc/src/signal/sigismember.h
libc/test/src/signal/sigismember_test.cpp
Modified:
libc/config/linux/aarch64/entrypoints.txt
libc/config/linux/riscv/entrypoints.txt
libc/config/linux/x86_64/entrypoints.txt
libc/include/signal.yaml
libc/src/__support/OSUtil/linux/sigmask.h
libc/src/signal/CMakeLists.txt
libc/src/signal/linux/CMakeLists.txt
libc/test/src/signal/CMakeLists.txt
libc/test/src/ucontext/CMakeLists.txt
libc/test/src/ucontext/ucontext_test.cpp
libc/utils/docgen/signal.yaml
Removed:
################################################################################
diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index be4d80db3afb37..cae6bcab572ab9 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1376,6 +1376,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.signal.sigdelset
libc.src.signal.sigemptyset
libc.src.signal.sigfillset
+ libc.src.signal.sigismember
libc.src.signal.signal
libc.src.signal.sigprocmask
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 20e33295bfb206..e3d6b174d951a1 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1562,6 +1562,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.signal.sigdelset
libc.src.signal.sigemptyset
libc.src.signal.sigfillset
+ libc.src.signal.sigismember
libc.src.signal.signal
libc.src.signal.sigprocmask
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 7d7c3ad1e1768d..fd6ba983e52e8a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1588,6 +1588,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.signal.sigdelset
libc.src.signal.sigemptyset
libc.src.signal.sigfillset
+ libc.src.signal.sigismember
libc.src.signal.signal
libc.src.signal.sigprocmask
diff --git a/libc/include/signal.yaml b/libc/include/signal.yaml
index 5c73f6dd7994eb..b763da7eeb6025 100644
--- a/libc/include/signal.yaml
+++ b/libc/include/signal.yaml
@@ -104,6 +104,14 @@ functions:
return_type: int
arguments:
- type: sigset_t *
+ - name: sigismember
+ standards:
+ - posix
+ return_type: int
+ arguments:
+ - type: const sigset_t *
+ - type: int
+
- name: signal
standards:
- stdc
diff --git a/libc/src/__support/OSUtil/linux/sigmask.h b/libc/src/__support/OSUtil/linux/sigmask.h
index 25ade4a1f3aea4..8c06199233ef48 100644
--- a/libc/src/__support/OSUtil/linux/sigmask.h
+++ b/libc/src/__support/OSUtil/linux/sigmask.h
@@ -66,6 +66,17 @@ LIBC_INLINE constexpr bool remove(sigset_t &set, int signal) {
return set_bit(set, signal, false);
}
+/// Test if the bit corresponding to |signal| in |set| is set.
+/// Returns 1 if set, 0 if not set, or Error(EINVAL) if |signal| is invalid.
+LIBC_INLINE constexpr ErrorOr<int> is_member(const sigset_t &set, int signal) {
+ if (signal >= NSIG || signal <= 0)
+ return Error(EINVAL);
+ size_t n = static_cast<size_t>(signal) - 1;
+ size_t word = n / BITS_PER_SIGWORD;
+ size_t bit = n % BITS_PER_SIGWORD;
+ return (set.__signals[word] & (1UL << bit)) ? 1 : 0;
+}
+
/// Block the signals in |set|. If |old_set| is non-null, store the previous
/// signal mask in |*old_set|.
LIBC_INLINE ErrorOr<int> block(const sigset_t &set,
diff --git a/libc/src/signal/CMakeLists.txt b/libc/src/signal/CMakeLists.txt
index 5611a5da853b9c..8da94d1eea85fd 100644
--- a/libc/src/signal/CMakeLists.txt
+++ b/libc/src/signal/CMakeLists.txt
@@ -85,3 +85,10 @@ add_entrypoint_object(
DEPENDS
.${LIBC_TARGET_OS}.sigdelset
)
+
+add_entrypoint_object(
+ sigismember
+ ALIAS
+ DEPENDS
+ .${LIBC_TARGET_OS}.sigismember
+)
diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt
index c035a4915e132f..77898cf9aab636 100644
--- a/libc/src/signal/linux/CMakeLists.txt
+++ b/libc/src/signal/linux/CMakeLists.txt
@@ -182,3 +182,16 @@ add_entrypoint_object(
libc.src.__support.OSUtil.linux.sigmask
libc.src.errno.errno
)
+
+add_entrypoint_object(
+ sigismember
+ SRCS
+ sigismember.cpp
+ HDRS
+ ../sigismember.h
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.types.sigset_t
+ libc.src.__support.OSUtil.linux.sigmask
+ libc.src.errno.errno
+)
diff --git a/libc/src/signal/linux/sigismember.cpp b/libc/src/signal/linux/sigismember.cpp
new file mode 100644
index 00000000000000..7bbbd22672ed55
--- /dev/null
+++ b/libc/src/signal/linux/sigismember.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux implementation of sigismember function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/signal/sigismember.h"
+
+#include "hdr/errno_macros.h"
+#include "hdr/types/sigset_t.h"
+#include "src/__support/OSUtil/linux/sigmask.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, sigismember, (const sigset_t *set, int signum)) {
+ if (set == nullptr) {
+ libc_errno = EINVAL;
+ return -1;
+ }
+ auto res = signals::is_member(*set, signum);
+ if (!res) {
+ libc_errno = res.error();
+ return -1;
+ }
+ return res.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/signal/sigismember.h b/libc/src/signal/sigismember.h
new file mode 100644
index 00000000000000..9650721bee731e
--- /dev/null
+++ b/libc/src/signal/sigismember.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for sigismember function.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SIGNAL_SIGISMEMBER_H
+#define LLVM_LIBC_SRC_SIGNAL_SIGISMEMBER_H
+
+#include "hdr/types/sigset_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int sigismember(const sigset_t *set, int signum);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SIGNAL_SIGISMEMBER_H
diff --git a/libc/test/src/signal/CMakeLists.txt b/libc/test/src/signal/CMakeLists.txt
index 9e7c55b75885d0..dc1769c963b228 100644
--- a/libc/test/src/signal/CMakeLists.txt
+++ b/libc/test/src/signal/CMakeLists.txt
@@ -128,6 +128,25 @@ add_libc_test(
libc.test.UnitTest.ErrnoSetterMatcher
)
+add_libc_test(
+ sigismember_test
+ SUITE
+ libc-signal-tests
+ SRCS
+ sigismember_test.cpp
+ DEPENDS
+ libc.hdr.errno_macros
+ libc.hdr.signal_macros
+ libc.hdr.types.sigset_t
+ libc.src.errno.errno
+ libc.src.signal.sigaddset
+ libc.src.signal.sigdelset
+ libc.src.signal.sigemptyset
+ libc.src.signal.sigfillset
+ libc.src.signal.sigismember
+ libc.test.UnitTest.ErrnoSetterMatcher
+)
+
add_libc_test(
sigaltstack_test
SUITE
diff --git a/libc/test/src/signal/sigismember_test.cpp b/libc/test/src/signal/sigismember_test.cpp
new file mode 100644
index 00000000000000..d78e2f442c04ac
--- /dev/null
+++ b/libc/test/src/signal/sigismember_test.cpp
@@ -0,0 +1,72 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unittests for sigismember.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/signal/sigismember.h"
+
+#include "hdr/signal_macros.h"
+#include "hdr/types/sigset_t.h"
+#include "src/signal/sigaddset.h"
+#include "src/signal/sigdelset.h"
+#include "src/signal/sigemptyset.h"
+#include "src/signal/sigfillset.h"
+#include "test/UnitTest/ErrnoSetterMatcher.h"
+#include "test/UnitTest/Test.h"
+
+TEST(LlvmLibcSigismember, Invalid) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Fails;
+ EXPECT_THAT(LIBC_NAMESPACE::sigismember(nullptr, SIGSEGV), Fails(EINVAL));
+
+ sigset_t sigset;
+ EXPECT_THAT(LIBC_NAMESPACE::sigismember(&sigset, -1), Fails(EINVAL));
+ EXPECT_THAT(LIBC_NAMESPACE::sigismember(&sigset, 0), Fails(EINVAL));
+
+#if defined(__APPLE__)
+ EXPECT_THAT(LIBC_NAMESPACE::sigismember(&sigset, NSIG), Fails(EINVAL));
+#else
+ constexpr int bitsInSigsetT = 8 * sizeof(sigset_t);
+ EXPECT_THAT(LIBC_NAMESPACE::sigismember(&sigset, bitsInSigsetT + 1),
+ Fails(EINVAL));
+#endif
+}
+
+TEST(LlvmLibcSigismember, BasicOperations) {
+ using LIBC_NAMESPACE::testing::ErrnoSetterMatcher::Succeeds;
+ sigset_t sigset;
+
+ EXPECT_THAT(LIBC_NAMESPACE::sigemptyset(&sigset), Succeeds());
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR1), 0);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR2), 0);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGINT), 0);
+
+ EXPECT_THAT(LIBC_NAMESPACE::sigaddset(&sigset, SIGUSR1), Succeeds());
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR1), 1);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR2), 0);
+
+ EXPECT_THAT(LIBC_NAMESPACE::sigaddset(&sigset, SIGINT), Succeeds());
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR1), 1);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGINT), 1);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR2), 0);
+
+ EXPECT_THAT(LIBC_NAMESPACE::sigdelset(&sigset, SIGUSR1), Succeeds());
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR1), 0);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGINT), 1);
+
+ EXPECT_THAT(LIBC_NAMESPACE::sigfillset(&sigset), Succeeds());
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR1), 1);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR2), 1);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGINT), 1);
+
+ EXPECT_THAT(LIBC_NAMESPACE::sigdelset(&sigset, SIGUSR2), Succeeds());
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR1), 1);
+ EXPECT_EQ(LIBC_NAMESPACE::sigismember(&sigset, SIGUSR2), 0);
+}
diff --git a/libc/test/src/ucontext/CMakeLists.txt b/libc/test/src/ucontext/CMakeLists.txt
index c773a151f37e5e..d05ed32774dc8f 100644
--- a/libc/test/src/ucontext/CMakeLists.txt
+++ b/libc/test/src/ucontext/CMakeLists.txt
@@ -12,6 +12,7 @@ if(TARGET libc.src.ucontext.getcontext)
libc.src.ucontext.setcontext
libc.src.signal.sigemptyset
libc.src.signal.sigaddset
+ libc.src.signal.sigismember
libc.src.signal.sigprocmask
)
endif()
diff --git a/libc/test/src/ucontext/ucontext_test.cpp b/libc/test/src/ucontext/ucontext_test.cpp
index f7ef972cca2060..c9167b4b87dc2a 100644
--- a/libc/test/src/ucontext/ucontext_test.cpp
+++ b/libc/test/src/ucontext/ucontext_test.cpp
@@ -11,6 +11,7 @@
#include "src/signal/sigaddset.h"
#include "src/signal/sigemptyset.h"
+#include "src/signal/sigismember.h"
#include "src/signal/sigprocmask.h"
#include "test/UnitTest/Test.h"
@@ -19,14 +20,6 @@
namespace LIBC_NAMESPACE {
-static bool is_signal_set(const sigset_t *set, int signum) {
- // TODO: Replace this with sigismember once it is implemented.
- // sigset_t is an array of unsigned long, signum is 1-indexed.
- int word = (signum - 1) / (sizeof(unsigned long) * 8);
- int bit = (signum - 1) % (sizeof(unsigned long) * 8);
- return (set->__signals[word] & (1UL << bit)) != 0;
-}
-
TEST(LlvmLibcUcontextTest, BasicStubTest) {
static volatile int jumped = 0;
ucontext_t ctx;
@@ -50,8 +43,8 @@ TEST(LlvmLibcUcontextTest, SignalMaskTest) {
getcontext(&ctx);
// Verify that getcontext captured the mask
- ASSERT_TRUE(is_signal_set(&ctx.uc_sigmask, SIGUSR1));
- ASSERT_FALSE(is_signal_set(&ctx.uc_sigmask, SIGUSR2));
+ ASSERT_EQ(sigismember(&ctx.uc_sigmask, SIGUSR1), 1);
+ ASSERT_EQ(sigismember(&ctx.uc_sigmask, SIGUSR2), 0);
sigset_t new_set;
static volatile int mask_jumped = 0;
@@ -71,8 +64,8 @@ TEST(LlvmLibcUcontextTest, SignalMaskTest) {
// Restore original mask for clean state
sigprocmask(SIG_SETMASK, &old_set, nullptr);
- ASSERT_TRUE(is_signal_set(¤t, SIGUSR1));
- ASSERT_FALSE(is_signal_set(¤t, SIGUSR2));
+ ASSERT_EQ(sigismember(¤t, SIGUSR1), 1);
+ ASSERT_EQ(sigismember(¤t, SIGUSR2), 0);
}
} // namespace LIBC_NAMESPACE
diff --git a/libc/utils/docgen/signal.yaml b/libc/utils/docgen/signal.yaml
index da31a86b00eb06..1023d6b60cf9a4 100644
--- a/libc/utils/docgen/signal.yaml
+++ b/libc/utils/docgen/signal.yaml
@@ -16,6 +16,8 @@ functions:
in-latest-posix: ''
sigfillset:
in-latest-posix: ''
+ sigismember:
+ in-latest-posix: ''
signal:
c-definition: 7.14.1.1
in-latest-posix: ''
More information about the libc-commits
mailing list