[libc-commits] [libc] [libc] Refactor core Linux syscalls to use syscall_wrappers (PR #185983)

Jeff Bailey via libc-commits libc-commits at lists.llvm.org
Tue Mar 17 07:46:38 PDT 2026


https://github.com/kaladron updated https://github.com/llvm/llvm-project/pull/185983

>From 3ed3d95cef99ea62188e8381058e0062a468a7fc Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Wed, 11 Mar 2026 20:27:50 +0000
Subject: [PATCH 1/2] [libc] Refactor core Linux syscalls to use
 syscall_wrappers

This patch initiates the refactoring of Linux syscalls as described in
the RFC (https://discourse.llvm.org/t/rfc-linux-syscall-cleanup/87248/).

It introduces a new infrastructure in `src/__support/OSUtil/linux/syscall_wrappers/`
to house header-only syscall wrappers. These wrappers utilize `ErrorOr`
to provide a consistent, type-safe interface for error handling across
the library, standardizing how syscall return values are converted into
errno-compatible Error objects.

Summary of changes:
- Created the `syscall_wrappers` directory and added `close.h`, `read.h`,
  `write.h`, and `open.h`.
- Moved the existing `getrandom.h` into the new `syscall_wrappers`
  directory and updated its callers (including HashTable/randomness.h).
- Refactored core entrypoints (`close`, `read`, `write`, `open`) to use
  the new wrappers, removing direct `syscall_impl` logic and manual
  errno setting.
- Updated `shm_open.cpp` to use the new `open` wrapper.
- Cleaned up `OSUtil/linux/fcntl.cpp` by removing redundant internal
  implementations of `open` and `close`.
- Added a developer guide in `docs/dev/syscall_wrapper_refactor.rst`
  outlining the established pattern for future migrations.

Co-authored-by: Michael Jones <michaelrj at google.com>
---
 libc/docs/dev/index.rst                       |  1 +
 libc/docs/dev/syscall_wrapper_refactor.rst    | 68 +++++++++++++++++++
 libc/src/__support/HashTable/CMakeLists.txt   |  2 +-
 libc/src/__support/HashTable/randomness.h     |  2 +-
 .../src/__support/OSUtil/linux/CMakeLists.txt |  1 +
 libc/src/__support/OSUtil/linux/fcntl.cpp     | 22 ------
 .../linux/syscall_wrappers/CMakeLists.txt     | 64 +++++++++++++++++
 .../OSUtil/linux/syscall_wrappers/close.h     | 31 +++++++++
 .../OSUtil/linux/syscall_wrappers/getrandom.h | 33 +++++++++
 .../OSUtil/linux/syscall_wrappers/open.h      | 37 ++++++++++
 .../{getrandom.h => syscall_wrappers/read.h}  | 17 ++---
 .../OSUtil/linux/syscall_wrappers/write.h     | 32 +++++++++
 libc/src/fcntl/linux/CMakeLists.txt           |  2 +-
 libc/src/fcntl/linux/open.cpp                 |  2 +-
 libc/src/sys/mman/linux/CMakeLists.txt        |  2 +
 libc/src/sys/mman/linux/shm_open.cpp          |  2 +-
 libc/src/sys/random/linux/CMakeLists.txt      |  3 +-
 libc/src/sys/random/linux/getrandom.cpp       |  3 +-
 libc/src/unistd/linux/CMakeLists.txt          |  9 +--
 libc/src/unistd/linux/close.cpp               |  3 +-
 libc/src/unistd/linux/read.cpp                | 11 ++-
 libc/src/unistd/linux/write.cpp               | 13 ++--
 22 files changed, 297 insertions(+), 63 deletions(-)
 create mode 100644 libc/docs/dev/syscall_wrapper_refactor.rst
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/close.h
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/getrandom.h
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/open.h
 rename libc/src/__support/OSUtil/linux/{getrandom.h => syscall_wrappers/read.h} (60%)
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/write.h

diff --git a/libc/docs/dev/index.rst b/libc/docs/dev/index.rst
index 91fb0b682e469..c0085e63cbadb 100644
--- a/libc/docs/dev/index.rst
+++ b/libc/docs/dev/index.rst
@@ -21,3 +21,4 @@ Navigate to the links below for information on the respective topics:
    implementation_standard
    undefined_behavior
    printf_behavior
+   syscall_wrapper_refactor
diff --git a/libc/docs/dev/syscall_wrapper_refactor.rst b/libc/docs/dev/syscall_wrapper_refactor.rst
new file mode 100644
index 0000000000000..edfcc69a25849
--- /dev/null
+++ b/libc/docs/dev/syscall_wrapper_refactor.rst
@@ -0,0 +1,68 @@
+.. _syscall_wrapper_refactor:
+
+==============================
+Syscall Wrapper Refactoring
+==============================
+
+Purpose
+=======
+
+LLVM-libc is transitioning to a centralized system for Linux syscalls. The goal
+is to move all direct ``syscall_impl`` calls into a dedicated directory:
+``src/__support/OSUtil/linux/syscall_wrappers/``.
+
+This refactor provides several benefits:
+
+* **Type Safety**: Using ``ErrorOr<T>`` ensures that error conditions are
+  handled explicitly.
+* **Consistency**: Standardizes the conversion of syscall return values into
+  errno-compatible objects.
+* **Maintainability**: Centralizes platform-specific syscall logic, making it
+  easier to audit and update.
+
+The Pattern
+===========
+
+Each syscall should have its own header-only library in the ``syscall_wrappers``
+directory. The wrapper function should return an ``ErrorOr<T>``.
+
+Example Wrapper (``src/__support/OSUtil/linux/syscall_wrappers/read.h``):
+--------------------------------------------------------------------------
+
+.. code-block:: c++
+
+    #include "src/__support/OSUtil/linux/syscall.h" // For syscall_impl
+    #include "src/__support/error_or.h"
+    #include "src/__support/common.h"
+    #include <sys/syscall.h> // For syscall numbers
+
+    namespace LIBC_NAMESPACE_DECL {
+    namespace internal {
+
+    LIBC_INLINE ErrorOr<ssize_t> read(int fd, void *buf, size_t count) {
+      ssize_t ret = syscall_impl<ssize_t>(SYS_read, fd, buf, count);
+      if (ret < 0) {
+        return Error(-static_cast<int>(ret));
+      }
+      return ret;
+    }
+
+    } // namespace internal
+    } // namespace LIBC_NAMESPACE_DECL
+
+How to Migrate
+==============
+
+1. **Create the Wrapper**: Add a new header file in
+   ``src/__support/OSUtil/linux/syscall_wrappers/``.
+2. **Update CMake**: Add a ``add_header_library`` target for the new wrapper in
+   ``src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt``.
+3. **Refactor Entrypoints**:
+
+   * Include the new wrapper header (e.g., ``read.h``).
+   * Replace direct ``syscall_impl`` calls with ``internal::<function_name>``.
+   * Update the entrypoint's ``DEPENDS`` in ``CMakeLists.txt`` to include the
+     new wrapper target.
+
+4. **Cleanup OSUtil**: If the syscall was previously implemented manually in
+   ``OSUtil/linux/fcntl.cpp`` (or similar), remove it to avoid name collisions.
diff --git a/libc/src/__support/HashTable/CMakeLists.txt b/libc/src/__support/HashTable/CMakeLists.txt
index d5861e7e825c2..82e88c02ae443 100644
--- a/libc/src/__support/HashTable/CMakeLists.txt
+++ b/libc/src/__support/HashTable/CMakeLists.txt
@@ -16,7 +16,7 @@ if (NOT ${getrandom_index} EQUAL -1)
   message(STATUS "Using getrandom for hashtable randomness")
   set(randomness_compile_flags -DLIBC_HASHTABLE_USE_GETRANDOM)
   set(randomness_extra_depends
-    libc.src.__support.OSUtil.linux.getrandom
+    libc.src.__support.OSUtil.linux.syscall_wrappers.getrandom
     libc.hdr.errno_macros)
 endif()
 
diff --git a/libc/src/__support/HashTable/randomness.h b/libc/src/__support/HashTable/randomness.h
index 7e54c9aa6ad1f..912b27629b533 100644
--- a/libc/src/__support/HashTable/randomness.h
+++ b/libc/src/__support/HashTable/randomness.h
@@ -15,7 +15,7 @@
 #include "src/__support/macros/config.h"
 #if defined(LIBC_HASHTABLE_USE_GETRANDOM)
 #include "hdr/errno_macros.h"
-#include "src/__support/OSUtil/linux/getrandom.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/getrandom.h"
 #endif
 
 namespace LIBC_NAMESPACE_DECL {
diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index 406c618eaba1c..8a686d4bce7dc 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -3,6 +3,7 @@ if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
 endif()
 
 add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
+add_subdirectory(syscall_wrappers)
 
 add_object_library(
   linux_util
diff --git a/libc/src/__support/OSUtil/linux/fcntl.cpp b/libc/src/__support/OSUtil/linux/fcntl.cpp
index 08db4859c6417..a31cb4ae3f600 100644
--- a/libc/src/__support/OSUtil/linux/fcntl.cpp
+++ b/libc/src/__support/OSUtil/linux/fcntl.cpp
@@ -116,27 +116,5 @@ ErrorOr<int> fcntl(int fd, int cmd, void *arg) {
   return ret;
 }
 
-ErrorOr<int> open(const char *path, int flags, mode_t mode_flags) {
-#ifdef SYS_open
-  int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_open, path, flags, mode_flags);
-#else
-  int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_openat, AT_FDCWD, path, flags,
-                                             mode_flags);
-#endif
-  if (fd < 0)
-    return Error(-fd);
-
-  return fd;
-}
-
-ErrorOr<int> close(int fd) {
-  int ret = LIBC_NAMESPACE::syscall_impl<int>(SYS_close, fd);
-
-  if (ret < 0)
-    return Error(-ret);
-
-  return ret;
-}
-
 } // namespace internal
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
new file mode 100644
index 0000000000000..8bc266941347a
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -0,0 +1,64 @@
+add_header_library(
+  getrandom
+  HDRS
+    getrandom.h
+  DEPENDS
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.common
+    libc.src.__support.error_or
+    libc.src.__support.macros.config
+    libc.hdr.types.ssize_t
+    libc.include.sys_syscall
+)
+
+add_header_library(
+  close
+  HDRS
+    close.h
+  DEPENDS
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.common
+    libc.src.__support.error_or
+    libc.src.__support.macros.config
+    libc.include.sys_syscall
+)
+
+add_header_library(
+  read
+  HDRS
+    read.h
+  DEPENDS
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.common
+    libc.src.__support.error_or
+    libc.src.__support.macros.config
+    libc.hdr.types.ssize_t
+    libc.include.sys_syscall
+)
+
+add_header_library(
+  write
+  HDRS
+    write.h
+  DEPENDS
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.common
+    libc.src.__support.error_or
+    libc.src.__support.macros.config
+    libc.hdr.types.ssize_t
+    libc.include.sys_syscall
+)
+
+add_header_library(
+  open
+  HDRS
+    open.h
+  DEPENDS
+    libc.src.__support.OSUtil.osutil
+    libc.src.__support.common
+    libc.src.__support.error_or
+    libc.src.__support.macros.config
+    libc.hdr.fcntl_macros
+    libc.hdr.types.mode_t
+    libc.include.sys_syscall
+)
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/close.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/close.h
new file mode 100644
index 0000000000000..b40b82a350d34
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/close.h
@@ -0,0 +1,31 @@
+//===-- Implementation header for close -------------------------*- 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___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CLOSE_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CLOSE_H
+
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+LIBC_INLINE ErrorOr<int> close(int fd) {
+  int ret = syscall_impl<int>(SYS_close, fd);
+  if (ret < 0)
+    return Error(-static_cast<int>(ret));
+  return ret;
+}
+
+} // namespace internal
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CLOSE_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/getrandom.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/getrandom.h
new file mode 100644
index 0000000000000..e06f53b3bef7b
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/getrandom.h
@@ -0,0 +1,33 @@
+//===-- Implementation header for getrandom ---------------------*- 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___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETRANDOM_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETRANDOM_H
+
+#include "hdr/types/ssize_t.h"
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+LIBC_INLINE ErrorOr<ssize_t> getrandom(void *buf, size_t buflen,
+                                       unsigned int flags) {
+  ssize_t ret = syscall_impl<ssize_t>(SYS_getrandom, buf, buflen, flags);
+  if (ret < 0)
+    return Error(-static_cast<int>(ret));
+  return ret;
+}
+
+} // namespace internal
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETRANDOM_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/open.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/open.h
new file mode 100644
index 0000000000000..3fad38cb1e86d
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/open.h
@@ -0,0 +1,37 @@
+//===-- Implementation header for open --------------------------*- 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___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_OPEN_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_OPEN_H
+
+#include "hdr/fcntl_macros.h"
+#include "hdr/types/mode_t.h"
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+LIBC_INLINE ErrorOr<int> open(const char *path, int flags, mode_t mode_flags) {
+#ifdef SYS_open
+  int fd = syscall_impl<int>(SYS_open, path, flags, mode_flags);
+#else
+  int fd = syscall_impl<int>(SYS_openat, AT_FDCWD, path, flags, mode_flags);
+#endif
+  if (fd < 0)
+    return Error(-fd);
+  return fd;
+}
+
+} // namespace internal
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_OPEN_H
diff --git a/libc/src/__support/OSUtil/linux/getrandom.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/read.h
similarity index 60%
rename from libc/src/__support/OSUtil/linux/getrandom.h
rename to libc/src/__support/OSUtil/linux/syscall_wrappers/read.h
index 793639472fee7..7cdb5393a7756 100644
--- a/libc/src/__support/OSUtil/linux/getrandom.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/read.h
@@ -1,4 +1,4 @@
-//===------------ Implementation of getrandom function ----------*- C++ -*-===//
+//===-- Implementation header for read --------------------------*- C++ -*-===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -6,8 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_GETRANDOM_H
-#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_GETRANDOM_H
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_READ_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_READ_H
 
 #include "hdr/types/ssize_t.h"
 #include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
@@ -19,17 +19,14 @@
 namespace LIBC_NAMESPACE_DECL {
 namespace internal {
 
-LIBC_INLINE static ErrorOr<ssize_t> getrandom(void *buf, size_t buflen,
-                                              unsigned int flags) {
-  ssize_t ret =
-      LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_getrandom, buf, buflen, flags);
-  if (ret < 0) {
+LIBC_INLINE ErrorOr<ssize_t> read(int fd, void *buf, size_t count) {
+  ssize_t ret = syscall_impl<ssize_t>(SYS_read, fd, buf, count);
+  if (ret < 0)
     return Error(-static_cast<int>(ret));
-  }
   return ret;
 }
 
 } // namespace internal
 } // namespace LIBC_NAMESPACE_DECL
 
-#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_GETRANDOM_H
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_READ_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/write.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/write.h
new file mode 100644
index 0000000000000..3a1b442e08a3c
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/write.h
@@ -0,0 +1,32 @@
+//===-- Implementation header for write -------------------------*- 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___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_WRITE_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_WRITE_H
+
+#include "hdr/types/ssize_t.h"
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/common.h"
+#include "src/__support/error_or.h"
+#include "src/__support/macros/config.h"
+#include <sys/syscall.h> // For syscall numbers
+
+namespace LIBC_NAMESPACE_DECL {
+namespace internal {
+
+LIBC_INLINE ErrorOr<ssize_t> write(int fd, const void *buf, size_t count) {
+  ssize_t ret = syscall_impl<ssize_t>(SYS_write, fd, buf, count);
+  if (ret < 0)
+    return Error(-static_cast<int>(ret));
+  return ret;
+}
+
+} // namespace internal
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_WRITE_H
diff --git a/libc/src/fcntl/linux/CMakeLists.txt b/libc/src/fcntl/linux/CMakeLists.txt
index c31eb3f438c10..4c151edc0ab49 100644
--- a/libc/src/fcntl/linux/CMakeLists.txt
+++ b/libc/src/fcntl/linux/CMakeLists.txt
@@ -31,7 +31,7 @@ add_entrypoint_object(
   DEPENDS
     libc.hdr.types.mode_t
     libc.hdr.fcntl_macros
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.open
     libc.src.errno.errno
 )
 
diff --git a/libc/src/fcntl/linux/open.cpp b/libc/src/fcntl/linux/open.cpp
index 3a56d10554198..a759e93dcfee5 100644
--- a/libc/src/fcntl/linux/open.cpp
+++ b/libc/src/fcntl/linux/open.cpp
@@ -10,7 +10,7 @@
 
 #include "hdr/fcntl_macros.h"
 #include "hdr/types/mode_t.h"
-#include "src/__support/OSUtil/fcntl.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
diff --git a/libc/src/sys/mman/linux/CMakeLists.txt b/libc/src/sys/mman/linux/CMakeLists.txt
index 97c116f1d2e79..4c90ca0f01549 100644
--- a/libc/src/sys/mman/linux/CMakeLists.txt
+++ b/libc/src/sys/mman/linux/CMakeLists.txt
@@ -293,8 +293,10 @@ add_entrypoint_object(
   HDRS
     ../shm_open.h
   DEPENDS
+    libc.hdr.fcntl_macros
     libc.hdr.types.mode_t
     libc.src.errno.errno
+    libc.src.__support.OSUtil.linux.syscall_wrappers.open
     .shm_common
 )
 
diff --git a/libc/src/sys/mman/linux/shm_open.cpp b/libc/src/sys/mman/linux/shm_open.cpp
index 46231ba1279a8..37dc512cfec20 100644
--- a/libc/src/sys/mman/linux/shm_open.cpp
+++ b/libc/src/sys/mman/linux/shm_open.cpp
@@ -10,7 +10,7 @@
 
 #include "hdr/fcntl_macros.h"
 #include "hdr/types/mode_t.h"
-#include "src/__support/OSUtil/fcntl.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
 #include "src/sys/mman/linux/shm_common.h"
diff --git a/libc/src/sys/random/linux/CMakeLists.txt b/libc/src/sys/random/linux/CMakeLists.txt
index 474e275ee597a..60f6e486967ad 100644
--- a/libc/src/sys/random/linux/CMakeLists.txt
+++ b/libc/src/sys/random/linux/CMakeLists.txt
@@ -6,7 +6,6 @@ add_entrypoint_object(
     ../getrandom.h
   DEPENDS
     libc.include.sys_random
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.getrandom
     libc.src.errno.errno
 )
diff --git a/libc/src/sys/random/linux/getrandom.cpp b/libc/src/sys/random/linux/getrandom.cpp
index 4a95bddfa428e..789055b38fb0a 100644
--- a/libc/src/sys/random/linux/getrandom.cpp
+++ b/libc/src/sys/random/linux/getrandom.cpp
@@ -8,8 +8,7 @@
 
 #include "src/sys/random/getrandom.h"
 
-#include "src/__support/OSUtil/linux/getrandom.h"
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/OSUtil/linux/syscall_wrappers/getrandom.h"
 #include "src/__support/common.h"
 #include "src/__support/error_or.h"
 #include "src/__support/libc_errno.h"
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 560c78552fec8..a5006fd6e9e63 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -47,8 +47,7 @@ add_entrypoint_object(
     ../close.h
   DEPENDS
     libc.include.unistd
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.close
     libc.src.errno.errno
 )
 
@@ -502,8 +501,7 @@ add_entrypoint_object(
     libc.hdr.types.ssize_t
     libc.hdr.fcntl_macros
     libc.include.unistd
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.read
     libc.src.__support.macros.sanitizer
     libc.src.errno.errno
 )
@@ -674,8 +672,7 @@ add_entrypoint_object(
     libc.hdr.types.ssize_t
     libc.hdr.fcntl_macros
     libc.include.unistd
-    libc.include.sys_syscall
-    libc.src.__support.OSUtil.osutil
+    libc.src.__support.OSUtil.linux.syscall_wrappers.write
     libc.src.errno.errno
 )
 
diff --git a/libc/src/unistd/linux/close.cpp b/libc/src/unistd/linux/close.cpp
index 6ef3a3c6d63f0..c8ab7fe5e5eef 100644
--- a/libc/src/unistd/linux/close.cpp
+++ b/libc/src/unistd/linux/close.cpp
@@ -8,11 +8,10 @@
 
 #include "src/unistd/close.h"
 
-#include "src/__support/OSUtil/fcntl.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/close.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 {
 
diff --git a/libc/src/unistd/linux/read.cpp b/libc/src/unistd/linux/read.cpp
index 55676f3f7010a..4ac385b8149b7 100644
--- a/libc/src/unistd/linux/read.cpp
+++ b/libc/src/unistd/linux/read.cpp
@@ -8,25 +8,24 @@
 
 #include "src/unistd/read.h"
 
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/OSUtil/linux/syscall_wrappers/read.h"
 #include "src/__support/common.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
 #include "src/__support/macros/sanitizer.h" // for MSAN_UNPOISON
-#include <sys/syscall.h>                    // For syscall numbers.
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(ssize_t, read, (int fd, void *buf, size_t count)) {
-  ssize_t ret = LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_read, fd, buf, count);
-  if (ret < 0) {
-    libc_errno = static_cast<int>(-ret);
+  auto result = internal::read(fd, buf, count);
+  if (!result.has_value()) {
+    libc_errno = result.error();
     return -1;
   }
   // The cast is important since there is a check that dereferences the pointer
   // which fails on void*.
   MSAN_UNPOISON(reinterpret_cast<char *>(buf), count);
-  return ret;
+  return result.value();
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/unistd/linux/write.cpp b/libc/src/unistd/linux/write.cpp
index eecb74429182a..30cea7d0c0845 100644
--- a/libc/src/unistd/linux/write.cpp
+++ b/libc/src/unistd/linux/write.cpp
@@ -8,23 +8,20 @@
 
 #include "src/unistd/write.h"
 
-#include "src/__support/OSUtil/syscall.h" // For internal syscall function.
+#include "src/__support/OSUtil/linux/syscall_wrappers/write.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 {
 
 LLVM_LIBC_FUNCTION(ssize_t, write, (int fd, const void *buf, size_t count)) {
-  ssize_t ret =
-      LIBC_NAMESPACE::syscall_impl<ssize_t>(SYS_write, fd, buf, count);
-  if (ret < 0) {
-    libc_errno = static_cast<int>(-ret);
+  auto result = internal::write(fd, buf, count);
+  if (!result.has_value()) {
+    libc_errno = result.error();
     return -1;
   }
-  return ret;
+  return result.value();
 }
 
 } // namespace LIBC_NAMESPACE_DECL

>From 087170883fdb2bac7b91ca4a96a46c9c526e6e17 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jeffbailey at google.com>
Date: Tue, 17 Mar 2026 14:46:21 +0000
Subject: [PATCH 2/2] Address review feedback on syscall wrappers

- Add Reusability to the Purpose section of the developer guide, as
  suggested by vonosmas.
- Rename namespace from 'internal' to 'linux_syscalls' to make call
  sites self-documenting and clearly identify OS-specific code.
  Note: 'linux' cannot be used as a bare namespace name because GCC
  defines it as a predefined macro (#define linux 1) in -std=gnu++
  modes.
- Update the developer guide example to match the actual header
  includes used in the wrapper implementations.
- Reorder migration steps to put cleanup of existing implementations
  first, before creating the new wrapper.
---
 libc/docs/dev/syscall_wrapper_refactor.rst    | 29 ++++++++++++-------
 libc/src/__support/HashTable/randomness.h     |  2 +-
 .../OSUtil/linux/syscall_wrappers/close.h     |  4 +--
 .../OSUtil/linux/syscall_wrappers/getrandom.h |  4 +--
 .../OSUtil/linux/syscall_wrappers/open.h      |  4 +--
 .../OSUtil/linux/syscall_wrappers/read.h      |  4 +--
 .../OSUtil/linux/syscall_wrappers/write.h     |  4 +--
 libc/src/fcntl/linux/open.cpp                 |  2 +-
 libc/src/sys/mman/linux/shm_open.cpp          |  2 +-
 libc/src/sys/random/linux/getrandom.cpp       |  2 +-
 libc/src/unistd/linux/close.cpp               |  2 +-
 libc/src/unistd/linux/read.cpp                |  2 +-
 libc/src/unistd/linux/write.cpp               |  2 +-
 13 files changed, 35 insertions(+), 28 deletions(-)

diff --git a/libc/docs/dev/syscall_wrapper_refactor.rst b/libc/docs/dev/syscall_wrapper_refactor.rst
index edfcc69a25849..40535b04d90eb 100644
--- a/libc/docs/dev/syscall_wrapper_refactor.rst
+++ b/libc/docs/dev/syscall_wrapper_refactor.rst
@@ -13,6 +13,8 @@ is to move all direct ``syscall_impl`` calls into a dedicated directory:
 
 This refactor provides several benefits:
 
+* **Reusability**: Allows multiple entrypoints to share a single syscall
+  implementation without public APIs depending on other public APIs.
 * **Type Safety**: Using ``ErrorOr<T>`` ensures that error conditions are
   handled explicitly.
 * **Consistency**: Standardizes the conversion of syscall return values into
@@ -24,20 +26,24 @@ The Pattern
 ===========
 
 Each syscall should have its own header-only library in the ``syscall_wrappers``
-directory. The wrapper function should return an ``ErrorOr<T>``.
+directory. The wrapper function should return an ``ErrorOr<T>``. Wrappers live
+in the ``linux_syscalls`` namespace to make call sites self-documenting and to
+clearly identify any leakage into OS-generic code.
 
 Example Wrapper (``src/__support/OSUtil/linux/syscall_wrappers/read.h``):
 --------------------------------------------------------------------------
 
 .. code-block:: c++
 
+    #include "hdr/types/ssize_t.h"
     #include "src/__support/OSUtil/linux/syscall.h" // For syscall_impl
-    #include "src/__support/error_or.h"
     #include "src/__support/common.h"
+    #include "src/__support/error_or.h"
+    #include "src/__support/macros/config.h"
     #include <sys/syscall.h> // For syscall numbers
 
     namespace LIBC_NAMESPACE_DECL {
-    namespace internal {
+    namespace linux_syscalls {
 
     LIBC_INLINE ErrorOr<ssize_t> read(int fd, void *buf, size_t count) {
       ssize_t ret = syscall_impl<ssize_t>(SYS_read, fd, buf, count);
@@ -47,22 +53,23 @@ Example Wrapper (``src/__support/OSUtil/linux/syscall_wrappers/read.h``):
       return ret;
     }
 
-    } // namespace internal
+    } // namespace linux_syscalls
     } // namespace LIBC_NAMESPACE_DECL
 
 How to Migrate
 ==============
 
-1. **Create the Wrapper**: Add a new header file in
+1. **Cleanup Existing Implementation**: If the syscall was previously
+   implemented in ``OSUtil/linux/fcntl.cpp`` (or similar), remove the old
+   implementation to replace it with the new wrapper.
+2. **Create the Wrapper**: Add a new header file in
    ``src/__support/OSUtil/linux/syscall_wrappers/``.
-2. **Update CMake**: Add a ``add_header_library`` target for the new wrapper in
+3. **Update CMake**: Add a ``add_header_library`` target for the new wrapper in
    ``src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt``.
-3. **Refactor Entrypoints**:
+4. **Refactor Entrypoints**:
 
    * Include the new wrapper header (e.g., ``read.h``).
-   * Replace direct ``syscall_impl`` calls with ``internal::<function_name>``.
+   * Replace direct ``syscall_impl`` calls with
+     ``linux_syscalls::<function_name>``.
    * Update the entrypoint's ``DEPENDS`` in ``CMakeLists.txt`` to include the
      new wrapper target.
-
-4. **Cleanup OSUtil**: If the syscall was previously implemented manually in
-   ``OSUtil/linux/fcntl.cpp`` (or similar), remove it to avoid name collisions.
diff --git a/libc/src/__support/HashTable/randomness.h b/libc/src/__support/HashTable/randomness.h
index 912b27629b533..38dc703a0db9e 100644
--- a/libc/src/__support/HashTable/randomness.h
+++ b/libc/src/__support/HashTable/randomness.h
@@ -38,7 +38,7 @@ LIBC_INLINE uint64_t next_random_seed() {
     size_t count = sizeof(entropy);
     uint8_t *buffer = reinterpret_cast<uint8_t *>(entropy);
     while (count > 0) {
-      auto len = internal::getrandom(buffer, count, 0);
+      auto len = linux_syscalls::getrandom(buffer, count, 0);
       if (!len.has_value()) {
         if (len.error() == ENOSYS)
           break;
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/close.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/close.h
index b40b82a350d34..fe305af5051c0 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/close.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/close.h
@@ -16,7 +16,7 @@
 #include <sys/syscall.h> // For syscall numbers
 
 namespace LIBC_NAMESPACE_DECL {
-namespace internal {
+namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<int> close(int fd) {
   int ret = syscall_impl<int>(SYS_close, fd);
@@ -25,7 +25,7 @@ LIBC_INLINE ErrorOr<int> close(int fd) {
   return ret;
 }
 
-} // namespace internal
+} // namespace linux_syscalls
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_CLOSE_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/getrandom.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/getrandom.h
index e06f53b3bef7b..b5ef6201a2dc5 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/getrandom.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/getrandom.h
@@ -17,7 +17,7 @@
 #include <sys/syscall.h> // For syscall numbers
 
 namespace LIBC_NAMESPACE_DECL {
-namespace internal {
+namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<ssize_t> getrandom(void *buf, size_t buflen,
                                        unsigned int flags) {
@@ -27,7 +27,7 @@ LIBC_INLINE ErrorOr<ssize_t> getrandom(void *buf, size_t buflen,
   return ret;
 }
 
-} // namespace internal
+} // namespace linux_syscalls
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_GETRANDOM_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/open.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/open.h
index 3fad38cb1e86d..f487f2bb91637 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/open.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/open.h
@@ -18,7 +18,7 @@
 #include <sys/syscall.h> // For syscall numbers
 
 namespace LIBC_NAMESPACE_DECL {
-namespace internal {
+namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<int> open(const char *path, int flags, mode_t mode_flags) {
 #ifdef SYS_open
@@ -31,7 +31,7 @@ LIBC_INLINE ErrorOr<int> open(const char *path, int flags, mode_t mode_flags) {
   return fd;
 }
 
-} // namespace internal
+} // namespace linux_syscalls
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_OPEN_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/read.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/read.h
index 7cdb5393a7756..86123904fc6b2 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/read.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/read.h
@@ -17,7 +17,7 @@
 #include <sys/syscall.h> // For syscall numbers
 
 namespace LIBC_NAMESPACE_DECL {
-namespace internal {
+namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<ssize_t> read(int fd, void *buf, size_t count) {
   ssize_t ret = syscall_impl<ssize_t>(SYS_read, fd, buf, count);
@@ -26,7 +26,7 @@ LIBC_INLINE ErrorOr<ssize_t> read(int fd, void *buf, size_t count) {
   return ret;
 }
 
-} // namespace internal
+} // namespace linux_syscalls
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_READ_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/write.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/write.h
index 3a1b442e08a3c..e57986d357a21 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/write.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/write.h
@@ -17,7 +17,7 @@
 #include <sys/syscall.h> // For syscall numbers
 
 namespace LIBC_NAMESPACE_DECL {
-namespace internal {
+namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<ssize_t> write(int fd, const void *buf, size_t count) {
   ssize_t ret = syscall_impl<ssize_t>(SYS_write, fd, buf, count);
@@ -26,7 +26,7 @@ LIBC_INLINE ErrorOr<ssize_t> write(int fd, const void *buf, size_t count) {
   return ret;
 }
 
-} // namespace internal
+} // namespace linux_syscalls
 } // namespace LIBC_NAMESPACE_DECL
 
 #endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_WRITE_H
diff --git a/libc/src/fcntl/linux/open.cpp b/libc/src/fcntl/linux/open.cpp
index a759e93dcfee5..83a5cf8cc4346 100644
--- a/libc/src/fcntl/linux/open.cpp
+++ b/libc/src/fcntl/linux/open.cpp
@@ -29,7 +29,7 @@ LLVM_LIBC_FUNCTION(int, open, (const char *path, int flags, ...)) {
     va_end(varargs);
   }
 
-  auto result = internal::open(path, flags, mode_flags);
+  auto result = linux_syscalls::open(path, flags, mode_flags);
 
   if (!result.has_value()) {
     libc_errno = result.error();
diff --git a/libc/src/sys/mman/linux/shm_open.cpp b/libc/src/sys/mman/linux/shm_open.cpp
index 37dc512cfec20..9670e9abc4eac 100644
--- a/libc/src/sys/mman/linux/shm_open.cpp
+++ b/libc/src/sys/mman/linux/shm_open.cpp
@@ -27,7 +27,7 @@ LLVM_LIBC_FUNCTION(int, shm_open, (const char *name, int oflags, mode_t mode)) {
   }
 
   auto open_result =
-      internal::open(path_result->data(), oflags | DEFAULT_OFLAGS, mode);
+      linux_syscalls::open(path_result->data(), oflags | DEFAULT_OFLAGS, mode);
   if (!open_result.has_value()) {
     libc_errno = open_result.error();
     return -1;
diff --git a/libc/src/sys/random/linux/getrandom.cpp b/libc/src/sys/random/linux/getrandom.cpp
index 789055b38fb0a..48078e50c6309 100644
--- a/libc/src/sys/random/linux/getrandom.cpp
+++ b/libc/src/sys/random/linux/getrandom.cpp
@@ -18,7 +18,7 @@ namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(ssize_t, getrandom,
                    (void *buf, size_t buflen, unsigned int flags)) {
-  auto rand = internal::getrandom(buf, buflen, flags);
+  auto rand = linux_syscalls::getrandom(buf, buflen, flags);
   if (!rand.has_value()) {
     libc_errno = static_cast<int>(rand.error());
     return -1;
diff --git a/libc/src/unistd/linux/close.cpp b/libc/src/unistd/linux/close.cpp
index c8ab7fe5e5eef..f625d417c1ff9 100644
--- a/libc/src/unistd/linux/close.cpp
+++ b/libc/src/unistd/linux/close.cpp
@@ -16,7 +16,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(int, close, (int fd)) {
-  auto result = internal::close(fd);
+  auto result = linux_syscalls::close(fd);
 
   if (!result.has_value()) {
     libc_errno = result.error();
diff --git a/libc/src/unistd/linux/read.cpp b/libc/src/unistd/linux/read.cpp
index 4ac385b8149b7..d39627e57a483 100644
--- a/libc/src/unistd/linux/read.cpp
+++ b/libc/src/unistd/linux/read.cpp
@@ -17,7 +17,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(ssize_t, read, (int fd, void *buf, size_t count)) {
-  auto result = internal::read(fd, buf, count);
+  auto result = linux_syscalls::read(fd, buf, count);
   if (!result.has_value()) {
     libc_errno = result.error();
     return -1;
diff --git a/libc/src/unistd/linux/write.cpp b/libc/src/unistd/linux/write.cpp
index 30cea7d0c0845..d7e2d768d1b4c 100644
--- a/libc/src/unistd/linux/write.cpp
+++ b/libc/src/unistd/linux/write.cpp
@@ -16,7 +16,7 @@
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(ssize_t, write, (int fd, const void *buf, size_t count)) {
-  auto result = internal::write(fd, buf, count);
+  auto result = linux_syscalls::write(fd, buf, count);
   if (!result.has_value()) {
     libc_errno = result.error();
     return -1;



More information about the libc-commits mailing list