[libc-commits] [libc] [libc] add proc number parser and sysconf wrapper (PR #194159)

Schrodinger ZHU Yifan via libc-commits libc-commits at lists.llvm.org
Sun Apr 26 06:41:31 PDT 2026


https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/194159

>From 1dd11124fda2d2507288ef920ef7c0f0272a2708 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Sat, 25 Apr 2026 12:39:35 -0400
Subject: [PATCH 1/5] [libc] add proc number parser and sysconf wrapper

Assisted-by: Codex with gpt-5.4 high fast
---
 .../llvm-libc-macros/linux/unistd-macros.h    |   2 +
 libc/include/unistd.yaml                      |   8 +
 .../src/__support/OSUtil/linux/CMakeLists.txt |  17 ++
 .../linux/syscall_wrappers/CMakeLists.txt     |  14 ++
 .../syscall_wrappers/sched_getaffinity.h      |  36 ++++
 libc/src/__support/OSUtil/linux/sysinfo.h     | 188 ++++++++++++++++++
 libc/src/unistd/linux/CMakeLists.txt          |   1 +
 libc/src/unistd/linux/sysconf.cpp             |  20 +-
 .../src/__support/OSUtil/linux/CMakeLists.txt |  12 ++
 .../__support/OSUtil/linux/sysinfo_test.cpp   |  99 +++++++++
 libc/test/src/unistd/sysconf_test.cpp         |  19 ++
 11 files changed, 409 insertions(+), 7 deletions(-)
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getaffinity.h
 create mode 100644 libc/src/__support/OSUtil/linux/sysinfo.h
 create mode 100644 libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp

diff --git a/libc/include/llvm-libc-macros/linux/unistd-macros.h b/libc/include/llvm-libc-macros/linux/unistd-macros.h
index a4c8e3cd91f7e..ba1ae48f17b78 100644
--- a/libc/include/llvm-libc-macros/linux/unistd-macros.h
+++ b/libc/include/llvm-libc-macros/linux/unistd-macros.h
@@ -17,6 +17,8 @@
 
 #define _SC_PAGESIZE 1
 #define _SC_PAGE_SIZE _SC_PAGESIZE
+#define _SC_NPROCESSORS_CONF 83
+#define _SC_NPROCESSORS_ONLN 84
 
 #define _PC_FILESIZEBITS 0
 #define _PC_LINK_MAX 1
diff --git a/libc/include/unistd.yaml b/libc/include/unistd.yaml
index 5966ab9199890..4c6856ccca4bd 100644
--- a/libc/include/unistd.yaml
+++ b/libc/include/unistd.yaml
@@ -14,6 +14,14 @@ macros:
     macro_header: unistd-macros.h
   - macro_name: STDERR_FILENO
     macro_header: unistd-macros.h
+  - macro_name: _SC_PAGESIZE
+    macro_header: unistd-macros.h
+  - macro_name: _SC_PAGE_SIZE
+    macro_header: unistd-macros.h
+  - macro_name: _SC_NPROCESSORS_CONF
+    macro_header: unistd-macros.h
+  - macro_name: _SC_NPROCESSORS_ONLN
+    macro_header: unistd-macros.h
 types:
   - type_name: uid_t
   - type_name: gid_t
diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index b02fa141fa456..2f41d88ae3875 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -38,6 +38,23 @@ add_header_library(
     libc.src.__support.threads.callonce
 )
 
+add_header_library(
+  sysinfo
+  HDRS
+    sysinfo.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.src.__support.CPP.array
+    libc.src.__support.CPP.bit
+    libc.src.__support.CPP.optional
+    libc.src.__support.CPP.string_view
+    libc.src.__support.OSUtil.linux.syscall_wrappers.close
+    libc.src.__support.OSUtil.linux.syscall_wrappers.open
+    libc.src.__support.OSUtil.linux.syscall_wrappers.read
+    libc.src.__support.OSUtil.linux.syscall_wrappers.sched_getaffinity
+    libc.src.__support.ctype_utils
+)
+
 add_header_library(
   vdso_sym
   HDRS
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 049eeac913780..ddabd0c39b858 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -11,6 +11,20 @@ add_header_library(
     libc.include.sys_syscall
 )
 
+add_header_library(
+  sched_getaffinity
+  HDRS
+    sched_getaffinity.h
+  DEPENDS
+    libc.hdr.types.pid_t
+    libc.src.__support.CPP.span
+    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(
   close
   HDRS
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getaffinity.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getaffinity.h
new file mode 100644
index 0000000000000..33a7bb41481de
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getaffinity.h
@@ -0,0 +1,36 @@
+//===-- Implementation header for sched_getaffinity -----------------------===//
+//
+// 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_SCHED_GETAFFINITY_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETAFFINITY_H
+
+#include "hdr/types/pid_t.h"
+#include "src/__support/CPP/span.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 linux_syscalls {
+
+LIBC_INLINE ErrorOr<int> sched_getaffinity(pid_t tid,
+                                           cpp::span<unsigned char> mask) {
+  int ret =
+      syscall_impl<int>(SYS_sched_getaffinity, tid, mask.size(), mask.data());
+  if (ret < 0)
+    return Error(-ret);
+  return ret;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETAFFINITY_H
diff --git a/libc/src/__support/OSUtil/linux/sysinfo.h b/libc/src/__support/OSUtil/linux/sysinfo.h
new file mode 100644
index 0000000000000..c1389fb4d6337
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/sysinfo.h
@@ -0,0 +1,188 @@
+//===------------- Linux sysinfo support -------------------------------------//
+//
+// 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_LINUX_SYSINFO_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSINFO_H
+
+#include "hdr/errno_macros.h"
+#include "src/__support/CPP/array.h"
+#include "src/__support/CPP/bit.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/CPP/string_view.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/close.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/open.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/read.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/sched_getaffinity.h"
+#include "src/__support/ctype_utils.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+namespace sysinfo {
+
+LIBC_INLINE_VAR constexpr cpp::string_view POSSIBLE_NPROC_PATH =
+    "/sys/devices/system/cpu/possible";
+LIBC_INLINE_VAR constexpr cpp::string_view ONLINE_NPROC_PATH =
+    "/sys/devices/system/cpu/online";
+
+// Parses Linux CPU-list syntax:
+//   list  := item (',' item)*
+//   item  := number | number '-' number
+//   number := [0-9]+
+class ProcParser {
+  enum class ProcParserState {
+    ParseUnstarted,
+    ParseNumber,
+    ParseRangeSeparator,
+    ParseRangeEnd
+  };
+
+  ProcParserState state;
+  cpp::array<char, 128> buffer;
+  int fd;
+  size_t cursor;
+  size_t buffer_end;
+  size_t cpu_count;
+  size_t current_number;
+  size_t range_start;
+  bool has_error;
+
+  LIBC_INLINE static int open_path(cpp::string_view path) {
+    ErrorOr<int> open_result =
+        linux_syscalls::open(path.data(), O_RDONLY | O_CLOEXEC, 0);
+    return open_result ? *open_result : -1;
+  }
+
+  LIBC_INLINE cpp::optional<char> next_char() {
+    if (fd < 0)
+      return cpp::nullopt;
+
+    while (cursor == buffer_end) {
+      ErrorOr<ssize_t> bytes_read =
+          linux_syscalls::read(fd, buffer.data(), buffer.size());
+      if (!bytes_read) {
+        if (bytes_read.error() == EINTR)
+          continue;
+        has_error = true;
+        return cpp::nullopt;
+      }
+
+      if (*bytes_read == 0)
+        return cpp::nullopt;
+
+      cursor = 0;
+      buffer_end = static_cast<size_t>(*bytes_read);
+    }
+
+    return buffer[cursor++];
+  }
+
+  LIBC_INLINE bool finish_group() {
+    if (state == ProcParserState::ParseUnstarted)
+      return true;
+    if (state == ProcParserState::ParseRangeSeparator)
+      return false;
+
+    if (state == ProcParserState::ParseRangeEnd) {
+      if (current_number < range_start)
+        return false;
+      cpu_count += current_number - range_start + 1;
+    } else {
+      ++cpu_count;
+    }
+
+    current_number = 0;
+    range_start = 0;
+    state = ProcParserState::ParseUnstarted;
+    return true;
+  }
+
+  LIBC_INLINE bool consume(char ch) {
+    if (internal::isdigit(ch)) {
+      current_number = current_number * 10 + static_cast<size_t>(ch - '0');
+      if (state == ProcParserState::ParseUnstarted)
+        state = ProcParserState::ParseNumber;
+      else if (state == ProcParserState::ParseRangeSeparator)
+        state = ProcParserState::ParseRangeEnd;
+      return true;
+    }
+
+    if (ch == '-') {
+      if (state != ProcParserState::ParseNumber)
+        return false;
+      range_start = current_number;
+      current_number = 0;
+      state = ProcParserState::ParseRangeSeparator;
+      return true;
+    }
+
+    if (ch == ',' || ch == '\n')
+      return finish_group();
+
+    if (ch == ' ' || ch == '\t' || ch == '\r')
+      return state == ProcParserState::ParseUnstarted ? true : finish_group();
+
+    return false;
+  }
+
+public:
+  LIBC_INLINE explicit ProcParser(cpp::string_view path)
+      : state(ProcParserState::ParseUnstarted), buffer{}, fd(open_path(path)),
+        cursor(buffer.size()), buffer_end(buffer.size()), cpu_count(0),
+        current_number(0), range_start(0), has_error(fd < 0) {}
+
+  LIBC_INLINE ~ProcParser() {
+    if (fd >= 0)
+      linux_syscalls::close(fd);
+  }
+
+  LIBC_INLINE cpp::optional<size_t> parse() {
+    if (fd < 0)
+      return cpp::nullopt;
+
+    while (cpp::optional<char> ch = next_char())
+      if (!consume(*ch))
+        return cpp::nullopt;
+
+    if (has_error)
+      return cpp::nullopt;
+
+    if (!finish_group())
+      return cpp::nullopt;
+
+    if (cpu_count == 0)
+      return cpp::nullopt;
+    return cpu_count;
+  }
+};
+
+LIBC_INLINE cpp::optional<size_t> parse_nproc_from(cpp::string_view path) {
+  return ProcParser(path).parse();
+}
+
+LIBC_INLINE size_t parse_nproc_with_fallback_from(cpp::string_view path) {
+  if (cpp::optional<size_t> cpu_count = parse_nproc_from(path))
+    return *cpu_count;
+
+  cpp::array<unsigned char, 128> mask_buffer = {};
+
+  ErrorOr<int> affinity_result =
+      linux_syscalls::sched_getaffinity(0, mask_buffer);
+  if (!affinity_result)
+    return 1;
+
+  size_t cpu_count = 0;
+  for (size_t i = 0; i < mask_buffer.size(); ++i)
+    cpu_count += static_cast<size_t>(cpp::popcount(mask_buffer[i]));
+
+  return cpu_count > 0 ? cpu_count : 1;
+}
+
+} // namespace sysinfo
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_LINUX_SYSINFO_H
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index c31fe24ac85cb..56a43d31d808b 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -614,6 +614,7 @@ add_entrypoint_object(
   DEPENDS
     libc.include.unistd
     libc.include.sys_auxv
+    libc.src.__support.OSUtil.linux.sysinfo
     libc.src.__support.libc_errno
     libc.src.__support.OSUtil.linux.auxv
 )
diff --git a/libc/src/unistd/linux/sysconf.cpp b/libc/src/unistd/linux/sysconf.cpp
index 979e178cb45ee..3243b7afa5596 100644
--- a/libc/src/unistd/linux/sysconf.cpp
+++ b/libc/src/unistd/linux/sysconf.cpp
@@ -12,26 +12,32 @@
 
 #include "hdr/unistd_macros.h"
 #include "src/__support/OSUtil/linux/auxv.h"
+#include "src/__support/OSUtil/linux/sysinfo.h"
 #include "src/__support/libc_errno.h"
 #include "src/__support/macros/config.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
 LLVM_LIBC_FUNCTION(long, sysconf, (int name)) {
-  long ret = 0;
   if (name == _SC_PAGESIZE) {
     cpp::optional<unsigned long> page_size = auxv::get(AT_PAGESZ);
     if (page_size)
       return static_cast<long>(*page_size);
-    ret = -1;
-  }
-
-  // TODO: Complete the rest of the sysconf options.
-  if (ret < 0) {
     libc_errno = EINVAL;
     return -1;
   }
-  return ret;
+
+  if (name == _SC_NPROCESSORS_CONF)
+    return static_cast<long>(
+        sysinfo::parse_nproc_with_fallback_from(sysinfo::POSSIBLE_NPROC_PATH));
+
+  if (name == _SC_NPROCESSORS_ONLN)
+    return static_cast<long>(
+        sysinfo::parse_nproc_with_fallback_from(sysinfo::ONLINE_NPROC_PATH));
+
+  // TODO: Complete the rest of the sysconf options.
+  libc_errno = EINVAL;
+  return -1;
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
index ff82616cc4a70..2549a8edf9d91 100644
--- a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
@@ -2,6 +2,18 @@ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_ARCHITECTURE})
   add_subdirectory(${LIBC_TARGET_ARCHITECTURE})
 endif()
 
+add_libc_test(
+  sysinfo_test
+  SUITE libc-osutil-tests
+  SRCS sysinfo_test.cpp
+  DEPENDS
+    libc.src.__support.OSUtil.linux.sysinfo
+    libc.src.fcntl.open
+    libc.src.unistd.close
+    libc.src.unistd.unlink
+    libc.src.unistd.write
+)
+
 add_libc_test(
   vdso_test
   SUITE libc-osutil-tests
diff --git a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
new file mode 100644
index 0000000000000..e4e54ff12124b
--- /dev/null
+++ b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
@@ -0,0 +1,99 @@
+//===-- Unittests for Linux sysinfo support -------------------------------===//
+//
+// 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/__support/CPP/string_view.h"
+#include "src/__support/OSUtil/linux/sysinfo.h"
+#include "src/fcntl/open.h"
+#include "src/unistd/close.h"
+#include "src/unistd/unlink.h"
+#include "src/unistd/write.h"
+#include "test/UnitTest/Test.h"
+
+#include <sys/sysinfo.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+static int write_test_file(cpp::string_view path, cpp::string_view contents) {
+  int fd = LIBC_NAMESPACE::open(path.data(), O_WRONLY | O_CREAT | O_TRUNC, 0600);
+  if (fd < 0)
+    return fd;
+
+  if (LIBC_NAMESPACE::write(fd, contents.data(), contents.size()) !=
+      static_cast<ssize_t>(contents.size())) {
+    LIBC_NAMESPACE::close(fd);
+    return -1;
+  }
+
+  return LIBC_NAMESPACE::close(fd);
+}
+
+TEST(LlvmLibcOSUtilSysinfoTest, PossibleCpuCountMatchesHostSysconf) {
+  int cpu_count = ::get_nprocs_conf();
+  ASSERT_GT(cpu_count, 0);
+  cpp::optional<size_t> parsed =
+      sysinfo::parse_nproc_from(sysinfo::POSSIBLE_NPROC_PATH);
+  ASSERT_TRUE(static_cast<bool>(parsed));
+  EXPECT_EQ(*parsed, static_cast<size_t>(cpu_count));
+  EXPECT_EQ(sysinfo::parse_nproc_with_fallback_from(sysinfo::POSSIBLE_NPROC_PATH),
+            static_cast<size_t>(cpu_count));
+}
+
+TEST(LlvmLibcOSUtilSysinfoTest, OnlineCpuCountMatchesHostSysconf) {
+  int cpu_count = ::get_nprocs();
+  ASSERT_GT(cpu_count, 0);
+  cpp::optional<size_t> parsed =
+      sysinfo::parse_nproc_from(sysinfo::ONLINE_NPROC_PATH);
+  ASSERT_TRUE(static_cast<bool>(parsed));
+  EXPECT_EQ(*parsed, static_cast<size_t>(cpu_count));
+  EXPECT_EQ(sysinfo::parse_nproc_with_fallback_from(sysinfo::ONLINE_NPROC_PATH),
+            static_cast<size_t>(cpu_count));
+}
+
+TEST(LlvmLibcOSUtilSysinfoTest, SyntheticCpuLists) {
+  constexpr const char *FILENAME =
+      APPEND_LIBC_TEST("sysinfo.synthetic_cpu_list.test");
+  CString test_file = libc_make_test_file_path(FILENAME);
+  cpp::string_view test_file_path = static_cast<const char *>(test_file);
+
+  struct TestCase {
+    cpp::string_view contents;
+    cpp::optional<size_t> expected;
+  };
+
+  constexpr TestCase TEST_CASES[] = {
+      {"0\n", 1},
+      {"0-7\n", 8},
+      {"0-0,2,4-6\n", 5},
+      {"0-3,8-11\n", 8},
+      {"0-3,8-11,16\n", 9},
+      {"1,2,3,4-9,99\n", 10},
+      {"3-1\n", cpp::nullopt},
+      {"0-\n", cpp::nullopt},
+  };
+
+  for (const TestCase &test_case : TEST_CASES) {
+    ASSERT_EQ(write_test_file(test_file_path, test_case.contents), 0);
+    cpp::optional<size_t> parsed = sysinfo::parse_nproc_from(test_file_path);
+    EXPECT_EQ(static_cast<bool>(parsed), static_cast<bool>(test_case.expected));
+    if (parsed)
+      EXPECT_EQ(*parsed, *test_case.expected);
+    EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(test_file_path), size_t(0));
+  }
+
+  ASSERT_EQ(LIBC_NAMESPACE::unlink(test_file_path.data()), 0);
+}
+
+TEST(LlvmLibcOSUtilSysinfoTest, NonexistentPath) {
+  constexpr cpp::string_view test_file_path =
+      "/not-exist-at-all-path-for-libc-nproc-test";
+
+  EXPECT_FALSE(static_cast<bool>(sysinfo::parse_nproc_from(test_file_path)));
+  EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(test_file_path), size_t(0));
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/unistd/sysconf_test.cpp b/libc/test/src/unistd/sysconf_test.cpp
index 85bc1258a4863..d02c0a17391dc 100644
--- a/libc/test/src/unistd/sysconf_test.cpp
+++ b/libc/test/src/unistd/sysconf_test.cpp
@@ -9,9 +9,28 @@
 #include "src/unistd/sysconf.h"
 #include "test/UnitTest/Test.h"
 
+#include <sys/sysinfo.h>
 #include <unistd.h>
 
 TEST(LlvmLibcSysconfTest, PagesizeTest) {
   long pagesize = LIBC_NAMESPACE::sysconf(_SC_PAGESIZE);
   ASSERT_GT(pagesize, 0l);
 }
+
+TEST(LlvmLibcSysconfTest, NprocessorsConfTest) {
+  int cpu_count = ::get_nprocs_conf();
+  ASSERT_GT(cpu_count, 0);
+
+  long sysconf_count = LIBC_NAMESPACE::sysconf(_SC_NPROCESSORS_CONF);
+  ASSERT_GT(sysconf_count, 0l);
+  EXPECT_EQ(sysconf_count, static_cast<long>(cpu_count));
+}
+
+TEST(LlvmLibcSysconfTest, NprocessorsOnlnTest) {
+  int cpu_count = ::get_nprocs();
+  ASSERT_GT(cpu_count, 0);
+
+  long sysconf_count = LIBC_NAMESPACE::sysconf(_SC_NPROCESSORS_ONLN);
+  ASSERT_GT(sysconf_count, 0l);
+  EXPECT_EQ(sysconf_count, static_cast<long>(cpu_count));
+}

>From 626216a3b2bdea7b81151f24874132e91886fb54 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Sat, 25 Apr 2026 12:41:31 -0400
Subject: [PATCH 2/5] fix

---
 libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
index e4e54ff12124b..ff5d5dca12cf0 100644
--- a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
@@ -19,7 +19,8 @@
 namespace LIBC_NAMESPACE_DECL {
 
 static int write_test_file(cpp::string_view path, cpp::string_view contents) {
-  int fd = LIBC_NAMESPACE::open(path.data(), O_WRONLY | O_CREAT | O_TRUNC, 0600);
+  int fd =
+      LIBC_NAMESPACE::open(path.data(), O_WRONLY | O_CREAT | O_TRUNC, 0600);
   if (fd < 0)
     return fd;
 
@@ -39,8 +40,9 @@ TEST(LlvmLibcOSUtilSysinfoTest, PossibleCpuCountMatchesHostSysconf) {
       sysinfo::parse_nproc_from(sysinfo::POSSIBLE_NPROC_PATH);
   ASSERT_TRUE(static_cast<bool>(parsed));
   EXPECT_EQ(*parsed, static_cast<size_t>(cpu_count));
-  EXPECT_EQ(sysinfo::parse_nproc_with_fallback_from(sysinfo::POSSIBLE_NPROC_PATH),
-            static_cast<size_t>(cpu_count));
+  EXPECT_EQ(
+      sysinfo::parse_nproc_with_fallback_from(sysinfo::POSSIBLE_NPROC_PATH),
+      static_cast<size_t>(cpu_count));
 }
 
 TEST(LlvmLibcOSUtilSysinfoTest, OnlineCpuCountMatchesHostSysconf) {
@@ -82,7 +84,8 @@ TEST(LlvmLibcOSUtilSysinfoTest, SyntheticCpuLists) {
     EXPECT_EQ(static_cast<bool>(parsed), static_cast<bool>(test_case.expected));
     if (parsed)
       EXPECT_EQ(*parsed, *test_case.expected);
-    EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(test_file_path), size_t(0));
+    EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(test_file_path),
+              size_t(0));
   }
 
   ASSERT_EQ(LIBC_NAMESPACE::unlink(test_file_path.data()), 0);

>From 44778bca6b4eeb9506b0b1063c6c7c9f1b36321a Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Sat, 25 Apr 2026 12:42:11 -0400
Subject: [PATCH 3/5] test

---
 .../__support/OSUtil/linux/sysinfo_test.cpp   | 29 +++++++------------
 libc/test/src/unistd/sysconf_test.cpp         |  9 ------
 2 files changed, 11 insertions(+), 27 deletions(-)

diff --git a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
index ff5d5dca12cf0..752dc73ffea06 100644
--- a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
@@ -14,8 +14,6 @@
 #include "src/unistd/write.h"
 #include "test/UnitTest/Test.h"
 
-#include <sys/sysinfo.h>
-
 namespace LIBC_NAMESPACE_DECL {
 
 static int write_test_file(cpp::string_view path, cpp::string_view contents) {
@@ -33,27 +31,22 @@ static int write_test_file(cpp::string_view path, cpp::string_view contents) {
   return LIBC_NAMESPACE::close(fd);
 }
 
-TEST(LlvmLibcOSUtilSysinfoTest, PossibleCpuCountMatchesHostSysconf) {
-  int cpu_count = ::get_nprocs_conf();
-  ASSERT_GT(cpu_count, 0);
+TEST(LlvmLibcOSUtilSysinfoTest, PossibleCpuCountSmokeTest) {
   cpp::optional<size_t> parsed =
       sysinfo::parse_nproc_from(sysinfo::POSSIBLE_NPROC_PATH);
   ASSERT_TRUE(static_cast<bool>(parsed));
-  EXPECT_EQ(*parsed, static_cast<size_t>(cpu_count));
-  EXPECT_EQ(
-      sysinfo::parse_nproc_with_fallback_from(sysinfo::POSSIBLE_NPROC_PATH),
-      static_cast<size_t>(cpu_count));
+  EXPECT_GT(*parsed, size_t(0));
+  EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(sysinfo::POSSIBLE_NPROC_PATH),
+            size_t(0));
 }
 
-TEST(LlvmLibcOSUtilSysinfoTest, OnlineCpuCountMatchesHostSysconf) {
-  int cpu_count = ::get_nprocs();
-  ASSERT_GT(cpu_count, 0);
+TEST(LlvmLibcOSUtilSysinfoTest, OnlineCpuCountSmokeTest) {
   cpp::optional<size_t> parsed =
       sysinfo::parse_nproc_from(sysinfo::ONLINE_NPROC_PATH);
   ASSERT_TRUE(static_cast<bool>(parsed));
-  EXPECT_EQ(*parsed, static_cast<size_t>(cpu_count));
-  EXPECT_EQ(sysinfo::parse_nproc_with_fallback_from(sysinfo::ONLINE_NPROC_PATH),
-            static_cast<size_t>(cpu_count));
+  EXPECT_GT(*parsed, size_t(0));
+  EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(sysinfo::ONLINE_NPROC_PATH),
+            size_t(0));
 }
 
 TEST(LlvmLibcOSUtilSysinfoTest, SyntheticCpuLists) {
@@ -92,11 +85,11 @@ TEST(LlvmLibcOSUtilSysinfoTest, SyntheticCpuLists) {
 }
 
 TEST(LlvmLibcOSUtilSysinfoTest, NonexistentPath) {
-  constexpr cpp::string_view test_file_path =
+  constexpr cpp::string_view TEST_PATH =
       "/not-exist-at-all-path-for-libc-nproc-test";
 
-  EXPECT_FALSE(static_cast<bool>(sysinfo::parse_nproc_from(test_file_path)));
-  EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(test_file_path), size_t(0));
+  EXPECT_FALSE(static_cast<bool>(sysinfo::parse_nproc_from(TEST_PATH)));
+  EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(TEST_PATH), size_t(0));
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/test/src/unistd/sysconf_test.cpp b/libc/test/src/unistd/sysconf_test.cpp
index d02c0a17391dc..e780e2c515585 100644
--- a/libc/test/src/unistd/sysconf_test.cpp
+++ b/libc/test/src/unistd/sysconf_test.cpp
@@ -9,7 +9,6 @@
 #include "src/unistd/sysconf.h"
 #include "test/UnitTest/Test.h"
 
-#include <sys/sysinfo.h>
 #include <unistd.h>
 
 TEST(LlvmLibcSysconfTest, PagesizeTest) {
@@ -18,19 +17,11 @@ TEST(LlvmLibcSysconfTest, PagesizeTest) {
 }
 
 TEST(LlvmLibcSysconfTest, NprocessorsConfTest) {
-  int cpu_count = ::get_nprocs_conf();
-  ASSERT_GT(cpu_count, 0);
-
   long sysconf_count = LIBC_NAMESPACE::sysconf(_SC_NPROCESSORS_CONF);
   ASSERT_GT(sysconf_count, 0l);
-  EXPECT_EQ(sysconf_count, static_cast<long>(cpu_count));
 }
 
 TEST(LlvmLibcSysconfTest, NprocessorsOnlnTest) {
-  int cpu_count = ::get_nprocs();
-  ASSERT_GT(cpu_count, 0);
-
   long sysconf_count = LIBC_NAMESPACE::sysconf(_SC_NPROCESSORS_ONLN);
   ASSERT_GT(sysconf_count, 0l);
-  EXPECT_EQ(sysconf_count, static_cast<long>(cpu_count));
 }

>From b9e80d2f59466822002351cadfd5bbd487bb626b Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Sat, 25 Apr 2026 13:17:44 -0400
Subject: [PATCH 4/5] fix

---
 libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
index 752dc73ffea06..96350dd9d7c18 100644
--- a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
@@ -36,8 +36,9 @@ TEST(LlvmLibcOSUtilSysinfoTest, PossibleCpuCountSmokeTest) {
       sysinfo::parse_nproc_from(sysinfo::POSSIBLE_NPROC_PATH);
   ASSERT_TRUE(static_cast<bool>(parsed));
   EXPECT_GT(*parsed, size_t(0));
-  EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(sysinfo::POSSIBLE_NPROC_PATH),
-            size_t(0));
+  EXPECT_GT(
+      sysinfo::parse_nproc_with_fallback_from(sysinfo::POSSIBLE_NPROC_PATH),
+      size_t(0));
 }
 
 TEST(LlvmLibcOSUtilSysinfoTest, OnlineCpuCountSmokeTest) {

>From fb772772c4a2cb01a201133047541bbc436c353e Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Sun, 26 Apr 2026 09:41:17 -0400
Subject: [PATCH 5/5] ensure nul termination

---
 libc/src/__support/OSUtil/linux/CMakeLists.txt        | 1 +
 libc/src/__support/OSUtil/linux/sysinfo.h             | 6 +++++-
 libc/test/src/__support/OSUtil/linux/CMakeLists.txt   | 1 +
 libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp | 7 +++++--
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index 2f41d88ae3875..1790a84cdebba 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -53,6 +53,7 @@ add_header_library(
     libc.src.__support.OSUtil.linux.syscall_wrappers.read
     libc.src.__support.OSUtil.linux.syscall_wrappers.sched_getaffinity
     libc.src.__support.ctype_utils
+    libc.src.string.memory_utils.inline_memcpy
 )
 
 add_header_library(
diff --git a/libc/src/__support/OSUtil/linux/sysinfo.h b/libc/src/__support/OSUtil/linux/sysinfo.h
index c1389fb4d6337..ecf1240f7f507 100644
--- a/libc/src/__support/OSUtil/linux/sysinfo.h
+++ b/libc/src/__support/OSUtil/linux/sysinfo.h
@@ -20,6 +20,7 @@
 #include "src/__support/OSUtil/linux/syscall_wrappers/sched_getaffinity.h"
 #include "src/__support/ctype_utils.h"
 #include "src/__support/macros/config.h"
+#include "src/string/memory_utils/inline_memcpy.h"
 
 namespace LIBC_NAMESPACE_DECL {
 namespace sysinfo {
@@ -52,8 +53,11 @@ class ProcParser {
   bool has_error;
 
   LIBC_INLINE static int open_path(cpp::string_view path) {
+    __extension__ char buf[path.size() + 1];
+    inline_memcpy(buf, path.data(), path.size());
+    buf[path.size()] = '\0';
     ErrorOr<int> open_result =
-        linux_syscalls::open(path.data(), O_RDONLY | O_CLOEXEC, 0);
+        linux_syscalls::open(buf, O_RDONLY | O_CLOEXEC, 0);
     return open_result ? *open_result : -1;
   }
 
diff --git a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
index 2549a8edf9d91..941646d5a9d4d 100644
--- a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
@@ -9,6 +9,7 @@ add_libc_test(
   DEPENDS
     libc.src.__support.OSUtil.linux.sysinfo
     libc.src.fcntl.open
+    libc.src.string.memory_utils.inline_memcpy
     libc.src.unistd.close
     libc.src.unistd.unlink
     libc.src.unistd.write
diff --git a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
index 96350dd9d7c18..73d42a8e6ed87 100644
--- a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
@@ -9,6 +9,7 @@
 #include "src/__support/CPP/string_view.h"
 #include "src/__support/OSUtil/linux/sysinfo.h"
 #include "src/fcntl/open.h"
+#include "src/string/memory_utils/inline_memcpy.h"
 #include "src/unistd/close.h"
 #include "src/unistd/unlink.h"
 #include "src/unistd/write.h"
@@ -17,8 +18,10 @@
 namespace LIBC_NAMESPACE_DECL {
 
 static int write_test_file(cpp::string_view path, cpp::string_view contents) {
-  int fd =
-      LIBC_NAMESPACE::open(path.data(), O_WRONLY | O_CREAT | O_TRUNC, 0600);
+  __extension__ char buf[path.size() + 1];
+  inline_memcpy(buf, path.data(), path.size());
+  buf[path.size()] = '\0';
+  int fd = LIBC_NAMESPACE::open(buf, O_WRONLY | O_CREAT | O_TRUNC, 0600);
   if (fd < 0)
     return fd;
 



More information about the libc-commits mailing list