[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