[libc-commits] [libc] 6bfa1c5 - [libc] Implement pselect in sys/select (#226237)

via libc-commits libc-commits at lists.llvm.org
Fri Sep 25 01:33:51 PDT 2026


Author: Aman Maurya
Date: 2026-09-25T10:33:44+02:00
New Revision: 6bfa1c552ea19edad20a76c773f480175ef58797

URL: https://github.com/llvm/llvm-project/commit/6bfa1c552ea19edad20a76c773f480175ef58797
DIFF: https://github.com/llvm/llvm-project/commit/6bfa1c552ea19edad20a76c773f480175ef58797.diff

LOG: [libc] Implement pselect in sys/select (#226237)

Implement the standard POSIX.1-2008 / POSIX.1-2024 function `pselect` in
`<sys/select.h>`, bringing `<sys/select.h>` to 100% POSIX completion.

Fixes #226195.

Added: 
    libc/src/__support/OSUtil/linux/syscall_wrappers/pselect6.h
    libc/src/sys/select/linux/pselect.cpp
    libc/src/sys/select/pselect.h
    libc/test/src/sys/select/pselect_test.cpp

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/sys/select.yaml
    libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
    libc/src/sys/select/CMakeLists.txt
    libc/src/sys/select/linux/CMakeLists.txt
    libc/src/sys/select/linux/select.cpp
    libc/test/src/sys/select/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index b1e4a2b9fb87d9..fbc1f34dca0dec 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1434,6 +1434,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.unistd.sysconf
 
     # sys/select.h entrypoints
+    libc.src.sys.select.pselect
     libc.src.sys.select.select
 
     # link.h entrypoints

diff  --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index dd3fa4268ac437..c045833ad1d145 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1633,6 +1633,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.unistd.sysconf
 
     # sys/select.h entrypoints
+    libc.src.sys.select.pselect
     libc.src.sys.select.select
 
     # wchar.h entrypoints

diff  --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 558310a1765293..672dd1ad96833f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1659,6 +1659,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.unistd.sysconf
 
     # sys/select.h entrypoints
+    libc.src.sys.select.pselect
     libc.src.sys.select.select
 
     # wchar.h entrypoints

diff  --git a/libc/include/sys/select.yaml b/libc/include/sys/select.yaml
index 3c0a026c13edf5..017ce0b4ca4a0c 100644
--- a/libc/include/sys/select.yaml
+++ b/libc/include/sys/select.yaml
@@ -24,3 +24,14 @@ functions:
       - type: fd_set *__restrict
       - type: fd_set *__restrict
       - type: struct timeval *__restrict
+  - name: pselect
+    standards:
+      - posix
+    return_type: int
+    arguments:
+      - type: int
+      - type: fd_set *__restrict
+      - type: fd_set *__restrict
+      - type: fd_set *__restrict
+      - type: const struct timespec *__restrict
+      - type: const sigset_t *__restrict

diff  --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 0b41afa13758e0..1af11116862c75 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -1513,3 +1513,20 @@ add_header_library(
     libc.src.__support.OSUtil.osutil
 )
 
+add_header_library(
+  pselect6
+  HDRS
+    pselect6.h
+  DEPENDS
+    libc.hdr.signal_macros
+    libc.hdr.types.fd_set
+    libc.hdr.types.sigset_t
+    libc.hdr.types.size_t
+    libc.hdr.types.struct_timespec
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.common
+    libc.src.__support.error_or
+    libc.src.__support.macros.config
+)
+

diff  --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/pselect6.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/pselect6.h
new file mode 100644
index 00000000000000..41ef28e024cc91
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/pselect6.h
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Syscall wrapper for pselect6.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PSELECT6_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PSELECT6_H
+
+#include "hdr/signal_macros.h"
+#include "hdr/types/fd_set.h"
+#include "hdr/types/sigset_t.h"
+#include "hdr/types/size_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h>
+
+namespace LIBC_NAMESPACE_DECL {
+namespace linux_syscalls {
+
+// Note: On Linux, the raw pselect6 syscall modifies its timeout argument to
+// return the remaining time if interrupted. Therefore, this wrapper accepts
+// a mutable timespec pointer. The POSIX pselect entrypoint is responsible for
+// making a copy to prevent mutating the user's const timeout argument.
+LIBC_INLINE ErrorOr<int> pselect6(int nfds, fd_set *__restrict readfds,
+                                  fd_set *__restrict writefds,
+                                  fd_set *__restrict exceptfds,
+                                  struct timespec *__restrict timeout,
+                                  const sigset_t *__restrict sigmask) {
+  // The kernel expects the signal mask size in bytes, not the number of
+  // signals. NSIG is the signal count, so NSIG / 8 gives the byte size.
+  const size_t SIGSETSIZE = NSIG / 8;
+  struct pselect6_sigset_t {
+    const sigset_t *ss;
+    size_t ss_len;
+  };
+  pselect6_sigset_t pss{sigmask, SIGSETSIZE};
+
+#if defined(SYS_pselect6_time64)
+  static_assert(
+      sizeof(time_t) == sizeof(int64_t),
+      "SYS_pselect6_time64 requires struct timespec with 64-bit members.");
+  return syscall_checked<int>(SYS_pselect6_time64, nfds, readfds, writefds,
+                              exceptfds, timeout, &pss);
+#elif defined(SYS_pselect6)
+  static_assert(
+      sizeof(timespec::tv_nsec) == sizeof(long),
+      "This legacy syscall fallback is only safe on platforms where tv_nsec "
+      "matches the register size (long). It is unsafe on 32-bit platforms "
+      "with 64-bit tv_nsec.");
+  return syscall_checked<int>(SYS_pselect6, nfds, readfds, writefds, exceptfds,
+                              timeout, &pss);
+#else
+#error "pselect6 and pselect6_time64 syscalls not available."
+#endif
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_PSELECT6_H

diff  --git a/libc/src/sys/select/CMakeLists.txt b/libc/src/sys/select/CMakeLists.txt
index ce36c66b255b06..ad7413f5fa3f23 100644
--- a/libc/src/sys/select/CMakeLists.txt
+++ b/libc/src/sys/select/CMakeLists.txt
@@ -8,3 +8,10 @@ add_entrypoint_object(
   DEPENDS
     .${LIBC_TARGET_OS}.select
 )
+
+add_entrypoint_object(
+  pselect
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.pselect
+)

diff  --git a/libc/src/sys/select/linux/CMakeLists.txt b/libc/src/sys/select/linux/CMakeLists.txt
index a239b2d0c94281..63e9bd22581e16 100644
--- a/libc/src/sys/select/linux/CMakeLists.txt
+++ b/libc/src/sys/select/linux/CMakeLists.txt
@@ -6,12 +6,27 @@ add_entrypoint_object(
     ../select.h
   DEPENDS
     libc.hdr.types.fd_set
-    libc.hdr.types.sigset_t
-    libc.hdr.types.size_t
     libc.hdr.types.struct_timespec
     libc.hdr.types.struct_timeval
-    libc.include.sys_syscall
     libc.src.__support.CPP.limits
-    libc.src.__support.OSUtil.osutil
-    libc.src.errno.errno
+    libc.src.__support.OSUtil.linux.syscall_wrappers.pselect6
+    libc.src.__support.common
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.config
+)
+
+add_entrypoint_object(
+  pselect
+  SRCS
+    pselect.cpp
+  HDRS
+    ../pselect.h
+  DEPENDS
+    libc.hdr.types.fd_set
+    libc.hdr.types.sigset_t
+    libc.hdr.types.struct_timespec
+    libc.src.__support.OSUtil.linux.syscall_wrappers.pselect6
+    libc.src.__support.common
+    libc.src.__support.libc_errno
+    libc.src.__support.macros.config
 )

diff  --git a/libc/src/sys/select/linux/pselect.cpp b/libc/src/sys/select/linux/pselect.cpp
new file mode 100644
index 00000000000000..dc12ebec4b0e97
--- /dev/null
+++ b/libc/src/sys/select/linux/pselect.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 pselect.
+///
+//===----------------------------------------------------------------------===//
+
+#include "src/sys/select/pselect.h"
+
+#include "hdr/types/fd_set.h"
+#include "hdr/types/sigset_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/pselect6.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, pselect,
+                   (int nfds, fd_set *__restrict readfds,
+                    fd_set *__restrict writefds, fd_set *__restrict exceptfds,
+                    const struct timespec *__restrict timeout,
+                    const sigset_t *__restrict sigmask)) {
+  // The Linux raw pselect6 syscall modifies its timeout argument. To conform to
+  // POSIX (which declares timeout as const), we pass a copy.
+  timespec ts;
+  timespec *tsp = nullptr;
+  if (timeout != nullptr) {
+    ts = *timeout;
+    tsp = &ts;
+  }
+  auto result = linux_syscalls::pselect6(nfds, readfds, writefds, exceptfds,
+                                         tsp, sigmask);
+  if (!result.has_value()) {
+    libc_errno = result.error();
+    return -1;
+  }
+  return result.value();
+}
+
+} // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/sys/select/linux/select.cpp b/libc/src/sys/select/linux/select.cpp
index fbb0e4a4cf07fb..1407bf74fb9663 100644
--- a/libc/src/sys/select/linux/select.cpp
+++ b/libc/src/sys/select/linux/select.cpp
@@ -8,23 +8,17 @@
 
 #include "src/sys/select/select.h"
 
-#include "hdr/types/sigset_t.h"
-#include "hdr/types/size_t.h"
+#include "hdr/types/fd_set.h"
 #include "hdr/types/struct_timespec.h"
+#include "hdr/types/struct_timeval.h"
 #include "src/__support/CPP/limits.h"
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/OSUtil/linux/syscall_wrappers/pselect6.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
-#include <sys/syscall.h> // For syscall numbers.
 
 namespace LIBC_NAMESPACE_DECL {
 
-struct pselect6_sigset_t {
-  sigset_t *ss;
-  size_t ss_len;
-};
-
 LLVM_LIBC_FUNCTION(int, select,
                    (int nfds, fd_set *__restrict read_set,
                     fd_set *__restrict write_set, fd_set *__restrict error_set,
@@ -32,12 +26,9 @@ LLVM_LIBC_FUNCTION(int, select,
   // Linux has a SYS_select syscall but it is not available on all
   // architectures. So, we use the SYS_pselect6 syscall which is more
   // widely available. However, SYS_pselect6 takes a struct timespec argument
-  // instead of a struct timeval argument. Also, it takes an additional
-  // argument which is a pointer to an object of a type defined above as
-  // "pselect6_sigset_t".
-  struct timespec ts {
-    0, 0
-  };
+  // instead of a struct timeval argument.
+  struct timespec ts;
+  struct timespec *tsp = nullptr;
   if (timeout != nullptr) {
     // In general, if the tv_sec and tv_usec in |timeout| are correctly set,
     // then converting tv_usec to nanoseconds will not be a problem. However,
@@ -49,29 +40,18 @@ LLVM_LIBC_FUNCTION(int, select,
       ts.tv_nsec = 999999999;
     } else {
       ts.tv_sec = timeout->tv_sec + timeout->tv_usec / 1000000;
-      ts.tv_nsec = timeout->tv_usec * 1000;
+      ts.tv_nsec = (timeout->tv_usec % 1000000) * 1000;
     }
+    tsp = &ts;
   }
-  pselect6_sigset_t pss{nullptr, sizeof(sigset_t)};
-#if defined(SYS_pselect6_time64)
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(
-      SYS_pselect6_time64, nfds, read_set, write_set, error_set, &ts, &pss);
-#elif defined(SYS_pselect6)
-  static_assert(
-      sizeof(timespec::tv_nsec) == sizeof(long),
-      "This legacy syscall fallback is only safe on platforms where tv_nsec "
-      "matches the register size (long). It is unsafe on 32-bit platforms "
-      "with 64-bit tv_nsec.");
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_pselect6, nfds, read_set,
-                                              write_set, error_set, &ts, &pss);
-#else
-#error "SYS_pselect6 and SYS_pselect6_time64 syscalls not available."
-#endif
-  if (ret < 0) {
-    libc_errno = -ret;
+
+  auto result = linux_syscalls::pselect6(nfds, read_set, write_set, error_set,
+                                         tsp, nullptr);
+  if (!result.has_value()) {
+    libc_errno = result.error();
     return -1;
   }
-  return ret;
+  return result.value();
 }
 
 } // namespace LIBC_NAMESPACE_DECL

diff  --git a/libc/src/sys/select/pselect.h b/libc/src/sys/select/pselect.h
new file mode 100644
index 00000000000000..62436778b3a0ff
--- /dev/null
+++ b/libc/src/sys/select/pselect.h
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 pselect.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SYS_SELECT_PSELECT_H
+#define LLVM_LIBC_SRC_SYS_SELECT_PSELECT_H
+
+#include "hdr/types/fd_set.h"
+#include "hdr/types/sigset_t.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pselect(int nfds, fd_set *__restrict readfds, fd_set *__restrict writefds,
+            fd_set *__restrict exceptfds,
+            const struct timespec *__restrict timeout,
+            const sigset_t *__restrict sigmask);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SYS_SELECT_PSELECT_H

diff  --git a/libc/test/src/sys/select/CMakeLists.txt b/libc/test/src/sys/select/CMakeLists.txt
index 316201cb30835a..7d9fa2e28628fc 100644
--- a/libc/test/src/sys/select/CMakeLists.txt
+++ b/libc/test/src/sys/select/CMakeLists.txt
@@ -31,4 +31,36 @@ add_libc_test(
     libc.test.UnitTest.ErrnoSetterMatcher
 )
 
+add_libc_test(
+  pselect_test
+  SUITE
+    libc_sys_select_unittests
+  SRCS
+    pselect_test.cpp
+  DEPENDS
+    libc.hdr.signal_macros
+    libc.hdr.sys_select_macros
+    libc.hdr.sys_time_macros
+    libc.hdr.types.fd_set
+    libc.hdr.types.sigset_t
+    libc.hdr.types.ssize_t
+    libc.hdr.types.struct_itimerval
+    libc.hdr.types.struct_sigaction
+    libc.hdr.types.struct_timespec
+    libc.src.__support.CPP.scope
+    libc.src.errno.errno
+    libc.src.signal.raise
+    libc.src.signal.sigaction
+    libc.src.signal.sigaddset
+    libc.src.signal.sigemptyset
+    libc.src.signal.sigprocmask
+    libc.src.sys.select.pselect
+    libc.src.sys.time.setitimer
+    libc.src.unistd.close
+    libc.src.unistd.pipe
+    libc.src.unistd.read
+    libc.src.unistd.write
+    libc.test.UnitTest.ErrnoCheckingTest
+)
+
 add_subdirectory(testdata)

diff  --git a/libc/test/src/sys/select/pselect_test.cpp b/libc/test/src/sys/select/pselect_test.cpp
new file mode 100644
index 00000000000000..b0bb545b3a995f
--- /dev/null
+++ b/libc/test/src/sys/select/pselect_test.cpp
@@ -0,0 +1,165 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Unit tests for pselect.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/signal_macros.h"
+#include "hdr/sys_select_macros.h"
+#include "hdr/sys_time_macros.h"
+#include "hdr/types/fd_set.h"
+#include "hdr/types/sigset_t.h"
+#include "hdr/types/ssize_t.h"
+#include "hdr/types/struct_itimerval.h"
+#include "hdr/types/struct_sigaction.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/CPP/scope.h"
+#include "src/signal/raise.h"
+#include "src/signal/sigaction.h"
+#include "src/signal/sigaddset.h"
+#include "src/signal/sigemptyset.h"
+#include "src/signal/sigprocmask.h"
+#include "src/sys/select/pselect.h"
+#include "src/sys/time/setitimer.h"
+#include "src/unistd/close.h"
+#include "src/unistd/pipe.h"
+#include "src/unistd/read.h"
+#include "src/unistd/write.h"
+#include "test/UnitTest/ErrnoCheckingTest.h"
+#include "test/UnitTest/Test.h"
+
+using LlvmLibcPSelectTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+static bool sigalrm_handler_called = false;
+extern "C" void handle_sigalrm(int) { sigalrm_handler_called = true; }
+
+static bool sigusr1_handler_called = false;
+extern "C" void handle_sigusr1(int) { sigusr1_handler_called = true; }
+
+TEST_F(LlvmLibcPSelectTest, SmokeTest) {
+  timespec ts{0, 0};
+  int ret = LIBC_NAMESPACE::pselect(0, nullptr, nullptr, nullptr, &ts, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(0, ret);
+}
+
+TEST_F(LlvmLibcPSelectTest, SmokeFailureTest) {
+  timespec ts{0, 0};
+  int ret =
+      LIBC_NAMESPACE::pselect(-1, nullptr, nullptr, nullptr, &ts, nullptr);
+  ASSERT_EQ(-1, ret);
+  ASSERT_ERRNO_EQ(EINVAL);
+}
+
+TEST_F(LlvmLibcPSelectTest, TimeoutNotMutated) {
+  sigalrm_handler_called = false;
+  struct sigaction sa{};
+  sa.sa_handler = handle_sigalrm;
+  LIBC_NAMESPACE::sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  struct sigaction old_sa{};
+  ASSERT_EQ(LIBC_NAMESPACE::sigaction(SIGALRM, &sa, &old_sa), 0);
+
+  LIBC_NAMESPACE::cpp::scope_exit restore_sa([&] {
+    LIBC_NAMESPACE::sigaction(SIGALRM, &old_sa, nullptr);
+    struct itimerval disable_timer{};
+    LIBC_NAMESPACE::setitimer(ITIMER_REAL, &disable_timer, nullptr);
+  });
+
+  struct itimerval timer{};
+  timer.it_value.tv_sec = 0;
+  timer.it_value.tv_usec = 100000; // 100ms
+  ASSERT_EQ(LIBC_NAMESPACE::setitimer(ITIMER_REAL, &timer, nullptr), 0);
+
+  const timespec ORIG_TS{1, 0}; // 1 second
+  timespec ts = ORIG_TS;
+  int ret = LIBC_NAMESPACE::pselect(0, nullptr, nullptr, nullptr, &ts, nullptr);
+  ASSERT_EQ(-1, ret);
+  ASSERT_ERRNO_EQ(EINTR);
+  ASSERT_TRUE(sigalrm_handler_called);
+
+  // The Linux raw syscall modifies its timeout argument when interrupted by a
+  // signal, but POSIX requires that pselect does not modify it. Verify that the
+  // timeout argument was not modified.
+  ASSERT_EQ(ts.tv_sec, ORIG_TS.tv_sec);
+  ASSERT_EQ(ts.tv_nsec, ORIG_TS.tv_nsec);
+}
+
+TEST_F(LlvmLibcPSelectTest, WithSigmask) {
+  sigusr1_handler_called = false;
+  struct sigaction sa{};
+  sa.sa_handler = handle_sigusr1;
+  LIBC_NAMESPACE::sigemptyset(&sa.sa_mask);
+  sa.sa_flags = 0;
+  struct sigaction old_sa{};
+  ASSERT_EQ(LIBC_NAMESPACE::sigaction(SIGUSR1, &sa, &old_sa), 0);
+
+  sigset_t block_mask{};
+  LIBC_NAMESPACE::sigemptyset(&block_mask);
+  LIBC_NAMESPACE::sigaddset(&block_mask, SIGUSR1);
+  sigset_t orig_mask{};
+  ASSERT_EQ(LIBC_NAMESPACE::sigprocmask(SIG_BLOCK, &block_mask, &orig_mask), 0);
+
+  LIBC_NAMESPACE::cpp::scope_exit cleanup([&] {
+    LIBC_NAMESPACE::sigprocmask(SIG_SETMASK, &orig_mask, nullptr);
+    LIBC_NAMESPACE::sigaction(SIGUSR1, &old_sa, nullptr);
+  });
+
+  // Raise SIGUSR1 while it is blocked.
+  ASSERT_EQ(LIBC_NAMESPACE::raise(SIGUSR1), 0);
+  ASSERT_FALSE(sigusr1_handler_called);
+
+  // Call pselect with a mask that unblocks SIGUSR1.
+  sigset_t unblock_mask{};
+  LIBC_NAMESPACE::sigemptyset(&unblock_mask);
+  timespec ts{1, 0};
+  int ret =
+      LIBC_NAMESPACE::pselect(0, nullptr, nullptr, nullptr, &ts, &unblock_mask);
+  ASSERT_EQ(-1, ret);
+  ASSERT_ERRNO_EQ(EINTR);
+  ASSERT_TRUE(sigusr1_handler_called);
+}
+
+TEST_F(LlvmLibcPSelectTest, PipeReadiness) {
+  int pipefd[2];
+  ASSERT_EQ(LIBC_NAMESPACE::pipe(pipefd), 0);
+
+  LIBC_NAMESPACE::cpp::scope_exit close_pipe([&] {
+    LIBC_NAMESPACE::close(pipefd[0]);
+    LIBC_NAMESPACE::close(pipefd[1]);
+  });
+
+  fd_set read_set;
+  FD_ZERO(&read_set);
+  FD_SET(pipefd[0], &read_set);
+
+  timespec zero{0, 0};
+  int ret = LIBC_NAMESPACE::pselect(pipefd[0] + 1, &read_set, nullptr, nullptr,
+                                    &zero, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(0, ret);
+  ASSERT_EQ(0, FD_ISSET(pipefd[0], &read_set));
+
+  constexpr char MSG = 'x';
+  ASSERT_EQ(LIBC_NAMESPACE::write(pipefd[1], &MSG, 1), ssize_t(1));
+
+  FD_ZERO(&read_set);
+  FD_SET(pipefd[0], &read_set);
+
+  ret = LIBC_NAMESPACE::pselect(pipefd[0] + 1, &read_set, nullptr, nullptr,
+                                &zero, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(1, ret);
+  ASSERT_NE(0, FD_ISSET(pipefd[0], &read_set));
+
+  char buf = 0;
+  ASSERT_EQ(LIBC_NAMESPACE::read(pipefd[0], &buf, 1), ssize_t(1));
+  ASSERT_EQ(buf, MSG);
+}


        


More information about the libc-commits mailing list