[libc-commits] [libc] [libc] Port wait4 to the syscall_wrappers ladder (PR #218699)

Mikhail R. Gadelha via libc-commits libc-commits at lists.llvm.org
Tue Aug 25 07:43:16 PDT 2026


https://github.com/mikhailramalho created https://github.com/llvm/llvm-project/pull/218699

wait4Impl.h carried its own SYS_wait4/SYS_waitid fallback while syscall_wrappers/wait4.h assumed SYS_wait4 exists, so the wrapper failed to build on architectures that only provide waitid, such as rv32.

It should fix the rv32 bot.

>From 96ea97b2bebe02e7910341d87b400de63dcf59ac Mon Sep 17 00:00:00 2001
From: "Mikhail R. Gadelha" <mikhail at igalia.com>
Date: Tue, 25 Aug 2026 11:41:12 -0300
Subject: [PATCH] [libc] Port wait4 to the syscall_wrappers ladder

wait4Impl.h carried its own SYS_wait4/SYS_waitid fallback while
syscall_wrappers/wait4.h assumed SYS_wait4 exists, so the wrapper failed
to build on architectures that only provide waitid, such as rv32.
---
 .../linux/syscall_wrappers/CMakeLists.txt     |  3 +
 .../OSUtil/linux/syscall_wrappers/wait4.h     | 63 +++++++++++++
 libc/src/sys/wait/linux/CMakeLists.txt        | 18 +---
 libc/src/sys/wait/linux/wait.cpp              |  5 +-
 libc/src/sys/wait/linux/wait4.cpp             |  5 +-
 libc/src/sys/wait/linux/waitpid.cpp           |  5 +-
 libc/src/sys/wait/wait4Impl.h                 | 91 -------------------
 7 files changed, 78 insertions(+), 112 deletions(-)
 delete mode 100644 libc/src/sys/wait/wait4Impl.h

diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index e01f2a5789e37..98841113fc674 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -985,7 +985,10 @@ add_header_library(
   HDRS
     wait4.h
   DEPENDS
+    libc.hdr.signal_macros
+    libc.hdr.sys_wait_macros
     libc.hdr.types.pid_t
+    libc.hdr.types.siginfo_t
     libc.hdr.types.struct_rusage
     libc.src.__support.OSUtil.osutil
     libc.src.__support.common
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/wait4.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/wait4.h
index 30d19ebae65f2..ac17b93166ac5 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/wait4.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/wait4.h
@@ -14,7 +14,10 @@
 #ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_WAIT4_H
 #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_WAIT4_H
 
+#include "hdr/signal_macros.h"
+#include "hdr/sys_wait_macros.h"
 #include "hdr/types/pid_t.h"
+#include "hdr/types/siginfo_t.h"
 #include "hdr/types/struct_rusage.h"
 #include "src/__support/OSUtil/linux/syscall.h" // For syscall_checked
 #include "src/__support/common.h"
@@ -27,7 +30,67 @@ namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<pid_t> wait4(pid_t pid, int *wstatus, int options,
                                  struct rusage *rusage) {
+#ifdef SYS_wait4
   return syscall_checked<pid_t>(SYS_wait4, pid, wstatus, options, rusage);
+#elif defined(SYS_waitid)
+  // Architectures without wait4 (e.g. riscv32) provide waitid instead.
+  int idtype = P_PID;
+  if (pid == -1) {
+    idtype = P_ALL;
+  } else if (pid < -1) {
+    idtype = P_PGID;
+    pid *= -1;
+  } else if (pid == 0) {
+    idtype = P_PGID;
+  }
+
+  options |= WEXITED;
+
+  // Linux always writes si_pid and si_signo (see SYSCALL_DEFINE5(waitid) in
+  // kernel/exit.c), zeroing them when WNOHANG found nothing, so si_pid is a
+  // reliable "was anything reaped" flag. Initialize it anyway: POSIX only
+  // requires this since POSIX.1-2008 TC1.
+  siginfo_t info;
+  info.si_pid = 0;
+  auto result =
+      syscall_checked<pid_t>(SYS_waitid, idtype, pid, &info, options, rusage);
+  if (!result.has_value())
+    return result;
+
+  // WNOHANG with nothing to reap. Return 0 without touching wstatus, which is
+  // what wait4 does; falling through would clobber it via the default case.
+  if (info.si_pid == 0)
+    return 0;
+
+  if (wstatus) {
+    switch (info.si_code) {
+    case CLD_EXITED:
+      *wstatus = W_EXITCODE(info.si_status, 0);
+      break;
+    case CLD_DUMPED:
+      *wstatus = info.si_status | WCOREFLAG;
+      break;
+    case CLD_KILLED:
+      *wstatus = info.si_status;
+      break;
+    case CLD_TRAPPED:
+    case CLD_STOPPED:
+      *wstatus = W_STOPCODE(info.si_status);
+      break;
+    case CLD_CONTINUED:
+      // Set wstatus to a value that the caller can check via WIFCONTINUED.
+      // glibc has a non-POSIX macro definition __W_CONTINUED for this value.
+      *wstatus = 0xffff;
+      break;
+    default:
+      *wstatus = 0;
+      break;
+    }
+  }
+  return info.si_pid;
+#else
+#error "wait4 and waitid syscalls not available."
+#endif
 }
 
 } // namespace linux_syscalls
diff --git a/libc/src/sys/wait/linux/CMakeLists.txt b/libc/src/sys/wait/linux/CMakeLists.txt
index 207c3acc5df92..90a98b8c6f437 100644
--- a/libc/src/sys/wait/linux/CMakeLists.txt
+++ b/libc/src/sys/wait/linux/CMakeLists.txt
@@ -5,13 +5,9 @@ add_entrypoint_object(
   HDRS
     ../wait.h
   DEPENDS
-    libc.hdr.signal_macros
-    libc.hdr.sys_wait_macros
     libc.hdr.types.pid_t
-    libc.hdr.types.siginfo_t
     libc.hdr.types.struct_rusage
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.wait4
     libc.src.errno.errno
 )
 
@@ -22,13 +18,9 @@ add_entrypoint_object(
   HDRS
     ../wait4.h
   DEPENDS
-    libc.hdr.signal_macros
-    libc.hdr.sys_wait_macros
     libc.hdr.types.pid_t
-    libc.hdr.types.siginfo_t
     libc.hdr.types.struct_rusage
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.wait4
     libc.src.errno.errno
 )
 
@@ -39,12 +31,8 @@ add_entrypoint_object(
   HDRS
     ../waitpid.h
   DEPENDS
-    libc.hdr.signal_macros
-    libc.hdr.sys_wait_macros
     libc.hdr.types.pid_t
-    libc.hdr.types.siginfo_t
     libc.hdr.types.struct_rusage
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.wait4
     libc.src.errno.errno
 )
diff --git a/libc/src/sys/wait/linux/wait.cpp b/libc/src/sys/wait/linux/wait.cpp
index dc97d0a4ff172..020766e4e77f0 100644
--- a/libc/src/sys/wait/linux/wait.cpp
+++ b/libc/src/sys/wait/linux/wait.cpp
@@ -6,17 +6,18 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/OSUtil/linux/syscall_wrappers/wait4.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_assert.h"
+#include "src/__support/libc_errno.h"
 
 #include "src/__support/macros/config.h"
 #include "src/sys/wait/wait.h"
-#include "src/sys/wait/wait4Impl.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(pid_t, wait, (int *wait_status)) {
-  auto result = internal::wait4impl(-1, wait_status, 0, 0);
+  auto result = linux_syscalls::wait4(-1, wait_status, 0, nullptr);
   if (!result.has_value()) {
     libc_errno = result.error();
     return -1;
diff --git a/libc/src/sys/wait/linux/wait4.cpp b/libc/src/sys/wait/linux/wait4.cpp
index ac6d16933dc87..c398967e7c424 100644
--- a/libc/src/sys/wait/linux/wait4.cpp
+++ b/libc/src/sys/wait/linux/wait4.cpp
@@ -6,19 +6,20 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/OSUtil/linux/syscall_wrappers/wait4.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_assert.h"
+#include "src/__support/libc_errno.h"
 
 #include "src/__support/macros/config.h"
 #include "src/sys/wait/wait4.h"
-#include "src/sys/wait/wait4Impl.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(pid_t, wait4,
                    (pid_t pid, int *wait_status, int options,
                     struct rusage *usage)) {
-  auto result = internal::wait4impl(pid, wait_status, options, usage);
+  auto result = linux_syscalls::wait4(pid, wait_status, options, usage);
   if (!result.has_value()) {
     libc_errno = result.error();
     return -1;
diff --git a/libc/src/sys/wait/linux/waitpid.cpp b/libc/src/sys/wait/linux/waitpid.cpp
index cb763a686353d..c5d9dd97d99d0 100644
--- a/libc/src/sys/wait/linux/waitpid.cpp
+++ b/libc/src/sys/wait/linux/waitpid.cpp
@@ -6,17 +6,18 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "src/__support/OSUtil/linux/syscall_wrappers/wait4.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_assert.h"
+#include "src/__support/libc_errno.h"
 
 #include "src/__support/macros/config.h"
-#include "src/sys/wait/wait4Impl.h"
 #include "src/sys/wait/waitpid.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(pid_t, waitpid, (pid_t pid, int *wait_status, int options)) {
-  auto result = internal::wait4impl(pid, wait_status, options, 0);
+  auto result = linux_syscalls::wait4(pid, wait_status, options, nullptr);
   if (!result.has_value()) {
     libc_errno = result.error();
     return -1;
diff --git a/libc/src/sys/wait/wait4Impl.h b/libc/src/sys/wait/wait4Impl.h
deleted file mode 100644
index 984363a6682a7..0000000000000
--- a/libc/src/sys/wait/wait4Impl.h
+++ /dev/null
@@ -1,91 +0,0 @@
-//===-- String to integer conversion utils ----------------------*- 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_SYS_WAIT_WAIT4IMPL_H
-#define LLVM_LIBC_SRC_SYS_WAIT_WAIT4IMPL_H
-
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
-#include "src/__support/common.h"
-#include "src/__support/error_or.h"
-#include "src/__support/libc_errno.h"
-#include "src/__support/macros/config.h"
-
-#include "hdr/signal_macros.h"
-#include "hdr/sys_wait_macros.h"
-#include "hdr/types/pid_t.h"
-#include "hdr/types/siginfo_t.h"
-#include "hdr/types/struct_rusage.h"
-#include <sys/syscall.h> // For syscall numbers.
-
-namespace LIBC_NAMESPACE_DECL {
-namespace internal {
-
-// The implementation of wait here is very minimal. We will add more
-// functionality and standard compliance in future.
-
-LIBC_INLINE ErrorOr<pid_t> wait4impl(pid_t pid, int *wait_status, int options,
-                                     struct rusage *usage) {
-#if SYS_wait4
-  pid = LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_wait4, pid, wait_status,
-                                            options, usage);
-#elif defined(SYS_waitid)
-  int idtype = P_PID;
-  if (pid == -1) {
-    idtype = P_ALL;
-  } else if (pid < -1) {
-    idtype = P_PGID;
-    pid *= -1;
-  } else if (pid == 0) {
-    idtype = P_PGID;
-  }
-
-  options |= WEXITED;
-
-  siginfo_t info;
-  pid = LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_waitid, idtype, pid, &info,
-                                            options, usage);
-  if (pid >= 0)
-    pid = info.si_pid;
-
-  if (wait_status) {
-    switch (info.si_code) {
-    case CLD_EXITED:
-      *wait_status = W_EXITCODE(info.si_status, 0);
-      break;
-    case CLD_DUMPED:
-      *wait_status = info.si_status | WCOREFLAG;
-      break;
-    case CLD_KILLED:
-      *wait_status = info.si_status;
-      break;
-    case CLD_TRAPPED:
-    case CLD_STOPPED:
-      *wait_status = W_STOPCODE(info.si_status);
-      break;
-    case CLD_CONTINUED:
-      // Set wait_status to a value that the caller can check via WIFCONTINUED.
-      // glibc has a non-POSIX macro definition __W_CONTINUED for this value.
-      *wait_status = 0xffff;
-      break;
-    default:
-      *wait_status = 0;
-      break;
-    }
-  }
-#else
-#error "wait4 and waitid syscalls not available."
-#endif
-  if (pid < 0)
-    return Error(-pid);
-  return pid;
-}
-
-} // namespace internal
-} // namespace LIBC_NAMESPACE_DECL
-
-#endif // LLVM_LIBC_SRC_SYS_WAIT_WAIT4IMPL_H



More information about the libc-commits mailing list