[libc-commits] [libc] [libc] Implement ppoll in poll (PR #225767)

Aman Maurya via libc-commits libc-commits at lists.llvm.org
Wed Sep 23 07:26:14 PDT 2026


https://github.com/amanmaurya92 updated https://github.com/llvm/llvm-project/pull/225767

>From e2d847bbcbd37c45d55aa459705688004c5d2689 Mon Sep 17 00:00:00 2001
From: amanmaurya92 <amanmaurya9209 at gmail.com>
Date: Wed, 23 Sep 2026 18:38:40 +0530
Subject: [PATCH] [libc] Implement ppoll in poll

Assisted by Antigravity and Gemini.
---
 libc/config/linux/aarch64/entrypoints.txt |  1 +
 libc/config/linux/riscv/entrypoints.txt   |  1 +
 libc/config/linux/x86_64/entrypoints.txt  |  1 +
 libc/hdr/CMakeLists.txt                   |  8 +++
 libc/hdr/poll_macros.h                    | 22 ++++++
 libc/include/CMakeLists.txt               |  2 +
 libc/include/poll.yaml                    | 11 +++
 libc/src/poll/CMakeLists.txt              |  7 ++
 libc/src/poll/linux/CMakeLists.txt        | 17 +++++
 libc/src/poll/linux/ppoll.cpp             | 57 +++++++++++++++
 libc/src/poll/ppoll.h                     | 25 +++++++
 libc/test/src/poll/CMakeLists.txt         | 22 ++++++
 libc/test/src/poll/ppoll_test.cpp         | 86 +++++++++++++++++++++++
 13 files changed, 260 insertions(+)
 create mode 100644 libc/hdr/poll_macros.h
 create mode 100644 libc/src/poll/linux/ppoll.cpp
 create mode 100644 libc/src/poll/ppoll.h
 create mode 100644 libc/test/src/poll/ppoll_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 479a70846714f0..e4cfff496d59a6 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -57,6 +57,7 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # poll.h entrypoints
     libc.src.poll.poll
+    libc.src.poll.ppoll
 
     # pwd.h entrypoints
     libc.src.pwd.endpwent
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index c841b28d9e544e..7f1a82b77b395e 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -76,6 +76,7 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # poll.h entrypoints
     libc.src.poll.poll
+    libc.src.poll.ppoll
 
     # pwd.h entrypoints
     libc.src.pwd.endpwent
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 786a1ea0743055..7733a4fb1de48d 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -76,6 +76,7 @@ set(TARGET_LIBC_ENTRYPOINTS
 
     # poll.h entrypoints
     libc.src.poll.poll
+    libc.src.poll.ppoll
 
     # pwd.h entrypoints
     libc.src.pwd.endpwent
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index fa01bc55785daa..64efe4968b51ac 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -120,6 +120,14 @@ add_proxy_header_library(
     libc.include.llvm-libc-macros.netinet_in_macros
 )
 
+add_proxy_header_library(
+  poll_macros
+  HDRS
+    poll_macros.h
+  FULL_BUILD_DEPENDS
+    libc.include.llvm-libc-macros.poll-macros
+)
+
 add_proxy_header_library(
   pthread_macros
   HDRS
diff --git a/libc/hdr/poll_macros.h b/libc/hdr/poll_macros.h
new file mode 100644
index 00000000000000..f24d93956ca231
--- /dev/null
+++ b/libc/hdr/poll_macros.h
@@ -0,0 +1,22 @@
+//===-- Definition of macros from poll.h ----------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_HDR_POLL_MACROS_H
+#define LLVM_LIBC_HDR_POLL_MACROS_H
+
+#ifdef LIBC_FULL_BUILD
+
+#include "include/llvm-libc-macros/poll-macros.h"
+
+#else // Overlay mode
+
+#include <poll.h>
+
+#endif // LIBC_FULL_BUILD
+
+#endif // LLVM_LIBC_HDR_POLL_MACROS_H
diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt
index f63e7e3dc6a734..e46f8c163ef2d2 100644
--- a/libc/include/CMakeLists.txt
+++ b/libc/include/CMakeLists.txt
@@ -1257,6 +1257,8 @@ add_header_macro(
   DEPENDS
     .llvm-libc-types.struct_pollfd
     .llvm-libc-types.nfds_t
+    .llvm-libc-types.struct_timespec
+    .llvm-libc-types.sigset_t
     .llvm-libc-macros.poll-macros
 )
 
diff --git a/libc/include/poll.yaml b/libc/include/poll.yaml
index bb7d99e87aa078..085445da1304f0 100644
--- a/libc/include/poll.yaml
+++ b/libc/include/poll.yaml
@@ -25,6 +25,8 @@ macros:
 types:
   - type_name: struct_pollfd
   - type_name: nfds_t
+  - type_name: struct_timespec
+  - type_name: sigset_t
 enums: []
 functions:
   - name: poll
@@ -35,3 +37,12 @@ functions:
       - type: struct pollfd *
       - type: nfds_t
       - type: int
+  - name: ppoll
+    standards:
+      - posix
+    return_type: int
+    arguments:
+      - type: struct pollfd *
+      - type: nfds_t
+      - type: const struct timespec *
+      - type: const sigset_t *
diff --git a/libc/src/poll/CMakeLists.txt b/libc/src/poll/CMakeLists.txt
index 65fbe46bb46128..c5bd970bb9a74e 100644
--- a/libc/src/poll/CMakeLists.txt
+++ b/libc/src/poll/CMakeLists.txt
@@ -8,3 +8,10 @@ add_entrypoint_object(
   DEPENDS
     .${LIBC_TARGET_OS}.poll
 )
+
+add_entrypoint_object(
+  ppoll
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.ppoll
+)
diff --git a/libc/src/poll/linux/CMakeLists.txt b/libc/src/poll/linux/CMakeLists.txt
index a9ef596c36c893..12871edf630ec4 100644
--- a/libc/src/poll/linux/CMakeLists.txt
+++ b/libc/src/poll/linux/CMakeLists.txt
@@ -12,3 +12,20 @@ add_entrypoint_object(
     libc.src.__support.OSUtil.osutil
     libc.src.errno.errno
 )
+
+add_entrypoint_object(
+  ppoll
+  SRCS
+    ppoll.cpp
+  HDRS
+    ../ppoll.h
+  DEPENDS
+    libc.hdr.signal_macros
+    libc.hdr.types.nfds_t
+    libc.hdr.types.sigset_t
+    libc.hdr.types.struct_pollfd
+    libc.hdr.types.struct_timespec
+    libc.include.sys_syscall
+    libc.src.__support.OSUtil.osutil
+    libc.src.errno.errno
+)
diff --git a/libc/src/poll/linux/ppoll.cpp b/libc/src/poll/linux/ppoll.cpp
new file mode 100644
index 00000000000000..245ba4acd41e51
--- /dev/null
+++ b/libc/src/poll/linux/ppoll.cpp
@@ -0,0 +1,57 @@
+//===-- Linux implementation of ppoll ------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "src/poll/ppoll.h"
+
+#include "hdr/signal_macros.h"
+#include "hdr/types/nfds_t.h"
+#include "hdr/types/sigset_t.h"
+#include "hdr/types/struct_pollfd.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/OSUtil/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+#include <sys/syscall.h> // SYS_ppoll, SYS_ppoll_time64
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(int, ppoll,
+                   (struct pollfd * fds, nfds_t nfds,
+                    const struct timespec *tmo_p, const sigset_t *sigmask)) {
+  timespec ts;
+  timespec *tsp = nullptr;
+  if (tmo_p != nullptr) {
+    ts = *tmo_p;
+    tsp = &ts;
+  }
+
+#if defined(SYS_ppoll_time64)
+  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_ppoll_time64, fds, nfds, tsp,
+                                              sigmask, NSIG / 8);
+#elif defined(SYS_ppoll)
+  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_ppoll, fds, nfds, tsp,
+                                              sigmask, NSIG / 8);
+#else
+#error "ppoll and ppoll_time64 syscalls not available."
+#endif
+
+  if (ret < 0) {
+    libc_errno = -ret;
+    return -1;
+  }
+  return ret;
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/poll/ppoll.h b/libc/src/poll/ppoll.h
new file mode 100644
index 00000000000000..71b90e4ac69c64
--- /dev/null
+++ b/libc/src/poll/ppoll.h
@@ -0,0 +1,25 @@
+//===-- Implementation header for ppoll -------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_POLL_PPOLL_H
+#define LLVM_LIBC_SRC_POLL_PPOLL_H
+
+#include "hdr/types/nfds_t.h"
+#include "hdr/types/sigset_t.h"
+#include "hdr/types/struct_pollfd.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *tmo_p,
+          const sigset_t *sigmask);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_POLL_PPOLL_H
diff --git a/libc/test/src/poll/CMakeLists.txt b/libc/test/src/poll/CMakeLists.txt
index b6f18c5dbf4bfb..5097f05bbddb90 100644
--- a/libc/test/src/poll/CMakeLists.txt
+++ b/libc/test/src/poll/CMakeLists.txt
@@ -12,3 +12,25 @@ add_libc_test(
     libc.src.poll.poll
     libc.test.UnitTest.ErrnoCheckingTest
 )
+
+add_libc_test(
+  ppoll_test
+  SUITE
+    libc_poll_unittests
+  SRCS
+    ppoll_test.cpp
+  DEPENDS
+    libc.hdr.limits_macros
+    libc.hdr.poll_macros
+    libc.hdr.types.sigset_t
+    libc.hdr.types.struct_pollfd
+    libc.hdr.types.struct_timespec
+    libc.src.__support.CPP.scope
+    libc.src.errno.errno
+    libc.src.poll.ppoll
+    libc.src.unistd.close
+    libc.src.unistd.pipe
+    libc.src.unistd.read
+    libc.src.unistd.write
+    libc.test.UnitTest.ErrnoCheckingTest
+)
diff --git a/libc/test/src/poll/ppoll_test.cpp b/libc/test/src/poll/ppoll_test.cpp
new file mode 100644
index 00000000000000..f6fe9941645866
--- /dev/null
+++ b/libc/test/src/poll/ppoll_test.cpp
@@ -0,0 +1,86 @@
+//===-- Unittests for ppoll -----------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "hdr/limits_macros.h"
+#include "hdr/poll_macros.h"
+#include "hdr/types/sigset_t.h"
+#include "hdr/types/struct_pollfd.h"
+#include "hdr/types/struct_timespec.h"
+#include "src/__support/CPP/scope.h"
+#include "src/poll/ppoll.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 LlvmLibcPPollTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
+
+TEST_F(LlvmLibcPPollTest, SmokeTest) {
+  timespec ts{0, 0};
+  int ret = LIBC_NAMESPACE::ppoll(nullptr, 0, &ts, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(0, ret);
+}
+
+TEST_F(LlvmLibcPPollTest, SmokeFailureTest) {
+  int ret = LIBC_NAMESPACE::ppoll(nullptr, UINT_MAX, nullptr, nullptr);
+  ASSERT_ERRNO_EQ(EINVAL);
+  ASSERT_EQ(-1, ret);
+}
+
+TEST_F(LlvmLibcPPollTest, TimeoutNotMutated) {
+  const timespec orig_ts{0, 0};
+  timespec ts = orig_ts;
+  int ret = LIBC_NAMESPACE::ppoll(nullptr, 0, &ts, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(0, ret);
+  ASSERT_EQ(ts.tv_sec, orig_ts.tv_sec);
+  ASSERT_EQ(ts.tv_nsec, orig_ts.tv_nsec);
+}
+
+TEST_F(LlvmLibcPPollTest, WithSigmask) {
+  timespec ts{0, 0};
+  sigset_t mask{};
+  int ret = LIBC_NAMESPACE::ppoll(nullptr, 0, &ts, &mask);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(0, ret);
+}
+
+TEST_F(LlvmLibcPPollTest, PipeReadiness) {
+  int pipefd[2];
+  ASSERT_EQ(LIBC_NAMESPACE::pipe(pipefd), 0);
+  ASSERT_ERRNO_SUCCESS();
+
+  LIBC_NAMESPACE::cpp::scope_exit cleanup([&] {
+    LIBC_NAMESPACE::close(pipefd[0]);
+    LIBC_NAMESPACE::close(pipefd[1]);
+  });
+
+  pollfd pfd{pipefd[0], POLLIN, 0};
+  timespec ts{0, 0};
+  int ret = LIBC_NAMESPACE::ppoll(&pfd, 1, &ts, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(0, ret);
+  ASSERT_EQ(0, static_cast<int>(pfd.revents));
+
+  char c = 'x';
+  ASSERT_EQ(LIBC_NAMESPACE::write(pipefd[1], &c, 1), static_cast<ssize_t>(1));
+  ASSERT_ERRNO_SUCCESS();
+
+  ret = LIBC_NAMESPACE::ppoll(&pfd, 1, &ts, nullptr);
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ(1, ret);
+  ASSERT_EQ(POLLIN, pfd.revents & POLLIN);
+
+  char buf = 0;
+  ASSERT_EQ(LIBC_NAMESPACE::read(pipefd[0], &buf, 1), static_cast<ssize_t>(1));
+  ASSERT_ERRNO_SUCCESS();
+  ASSERT_EQ('x', buf);
+}



More information about the libc-commits mailing list