[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(&current, SIGUSR1));
-  ASSERT_FALSE(is_signal_set(&current, SIGUSR2));
+  ASSERT_EQ(sigismember(&current, SIGUSR1), 1);
+  ASSERT_EQ(sigismember(&current, 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