[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
Tue Apr 28 08:54:15 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/9] [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/9] 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/9] 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/9] 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/9] 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;
 

>From 854dee512b5b2cd59531bebdaadda40b2253f112 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <i at zhuyi.fan>
Date: Sun, 26 Apr 2026 10:15:24 -0400
Subject: [PATCH 6/9] fix

---
 .../src/__support/OSUtil/linux/CMakeLists.txt |  2 --
 libc/src/__support/OSUtil/linux/sysinfo.h     | 21 ++++++++----------
 .../src/__support/OSUtil/linux/CMakeLists.txt |  2 +-
 .../__support/OSUtil/linux/sysinfo_test.cpp   | 22 +++++++------------
 4 files changed, 18 insertions(+), 29 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index 1790a84cdebba..355d052765514 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -47,13 +47,11 @@ add_header_library(
     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
-    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 ecf1240f7f507..a20707f8945c7 100644
--- a/libc/src/__support/OSUtil/linux/sysinfo.h
+++ b/libc/src/__support/OSUtil/linux/sysinfo.h
@@ -13,21 +13,19 @@
 #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"
-#include "src/string/memory_utils/inline_memcpy.h"
 
 namespace LIBC_NAMESPACE_DECL {
 namespace sysinfo {
 
-LIBC_INLINE_VAR constexpr cpp::string_view POSSIBLE_NPROC_PATH =
+LIBC_INLINE_VAR constexpr char POSSIBLE_NPROC_PATH[] =
     "/sys/devices/system/cpu/possible";
-LIBC_INLINE_VAR constexpr cpp::string_view ONLINE_NPROC_PATH =
+LIBC_INLINE_VAR constexpr char ONLINE_NPROC_PATH[] =
     "/sys/devices/system/cpu/online";
 
 // Parses Linux CPU-list syntax:
@@ -52,12 +50,9 @@ class ProcParser {
   size_t range_start;
   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';
+  LIBC_INLINE static int open_path(const char *path) {
     ErrorOr<int> open_result =
-        linux_syscalls::open(buf, O_RDONLY | O_CLOEXEC, 0);
+        linux_syscalls::open(path, O_RDONLY | O_CLOEXEC, 0);
     return open_result ? *open_result : -1;
   }
 
@@ -134,7 +129,9 @@ class ProcParser {
   }
 
 public:
-  LIBC_INLINE explicit ProcParser(cpp::string_view path)
+  // Using string view isn't exactly correct because we demands null-terminated
+  // strings.
+  LIBC_INLINE explicit ProcParser(const char *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) {}
@@ -164,11 +161,11 @@ class ProcParser {
   }
 };
 
-LIBC_INLINE cpp::optional<size_t> parse_nproc_from(cpp::string_view path) {
+LIBC_INLINE cpp::optional<size_t> parse_nproc_from(const char *path) {
   return ProcParser(path).parse();
 }
 
-LIBC_INLINE size_t parse_nproc_with_fallback_from(cpp::string_view path) {
+LIBC_INLINE size_t parse_nproc_with_fallback_from(const char *path) {
   if (cpp::optional<size_t> cpu_count = parse_nproc_from(path))
     return *cpu_count;
 
diff --git a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
index 941646d5a9d4d..8e6958941f289 100644
--- a/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/test/src/__support/OSUtil/linux/CMakeLists.txt
@@ -7,9 +7,9 @@ add_libc_test(
   SUITE libc-osutil-tests
   SRCS sysinfo_test.cpp
   DEPENDS
+    libc.src.__support.CPP.string_view
     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 73d42a8e6ed87..800f062343c2c 100644
--- a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
@@ -9,7 +9,6 @@
 #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,11 +16,8 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-static int write_test_file(cpp::string_view path, cpp::string_view contents) {
-  __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);
+static int write_test_file(const char *path, cpp::string_view contents) {
+  int fd = LIBC_NAMESPACE::open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
   if (fd < 0)
     return fd;
 
@@ -54,10 +50,9 @@ TEST(LlvmLibcOSUtilSysinfoTest, OnlineCpuCountSmokeTest) {
 }
 
 TEST(LlvmLibcOSUtilSysinfoTest, SyntheticCpuLists) {
-  constexpr const char *FILENAME =
+  constexpr 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;
@@ -76,20 +71,19 @@ TEST(LlvmLibcOSUtilSysinfoTest, SyntheticCpuLists) {
   };
 
   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);
+    ASSERT_EQ(write_test_file(test_file, test_case.contents), 0);
+    cpp::optional<size_t> parsed = sysinfo::parse_nproc_from(test_file);
     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), size_t(0));
   }
 
-  ASSERT_EQ(LIBC_NAMESPACE::unlink(test_file_path.data()), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::unlink(test_file), 0);
 }
 
 TEST(LlvmLibcOSUtilSysinfoTest, NonexistentPath) {
-  constexpr cpp::string_view TEST_PATH =
+  constexpr const char *TEST_PATH =
       "/not-exist-at-all-path-for-libc-nproc-test";
 
   EXPECT_FALSE(static_cast<bool>(sysinfo::parse_nproc_from(TEST_PATH)));

>From c9cee68aca02999f2b99fa0cedd82a43eade0a9d Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 27 Apr 2026 11:28:52 -0400
Subject: [PATCH 7/9] cleanup

---
 libc/include/unistd.yaml                        | 2 +-
 libc/src/__support/OSUtil/linux/sysinfo.h       | 4 ++--
 libc/src/unistd/linux/CMakeLists.txt            | 7 ++++---
 libc/src/unistd/linux/sysconf.cpp               | 1 +
 libc/test/src/sys/auxv/linux/CMakeLists.txt     | 4 ++--
 libc/test/src/sys/auxv/linux/getauxval_test.cpp | 8 +++++---
 6 files changed, 15 insertions(+), 11 deletions(-)

diff --git a/libc/include/unistd.yaml b/libc/include/unistd.yaml
index 4c6856ccca4bd..b3c19fe638d6d 100644
--- a/libc/include/unistd.yaml
+++ b/libc/include/unistd.yaml
@@ -372,7 +372,7 @@ functions:
   - name: sysconf
     standards:
       - POSIX
-    return_type: int
+    return_type: long
     arguments:
       - type: int
   - name: truncate
diff --git a/libc/src/__support/OSUtil/linux/sysinfo.h b/libc/src/__support/OSUtil/linux/sysinfo.h
index a20707f8945c7..2b041fd817117 100644
--- a/libc/src/__support/OSUtil/linux/sysinfo.h
+++ b/libc/src/__support/OSUtil/linux/sysinfo.h
@@ -177,8 +177,8 @@ LIBC_INLINE size_t parse_nproc_with_fallback_from(const char *path) {
     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]));
+  for (unsigned char byte : mask_buffer)
+    cpu_count += static_cast<size_t>(cpp::popcount(byte));
 
   return cpu_count > 0 ? cpu_count : 1;
 }
diff --git a/libc/src/unistd/linux/CMakeLists.txt b/libc/src/unistd/linux/CMakeLists.txt
index 56a43d31d808b..f979ba0669872 100644
--- a/libc/src/unistd/linux/CMakeLists.txt
+++ b/libc/src/unistd/linux/CMakeLists.txt
@@ -612,10 +612,11 @@ add_entrypoint_object(
   HDRS
     ../sysconf.h
   DEPENDS
-    libc.include.unistd
-    libc.include.sys_auxv
-    libc.src.__support.OSUtil.linux.sysinfo
+    libc.hdr.unistd_macros
+    libc.hdr.sys_auxv_macros
     libc.src.__support.libc_errno
+    libc.src.__support.macros.config
+    libc.src.__support.OSUtil.linux.sysinfo
     libc.src.__support.OSUtil.linux.auxv
 )
 
diff --git a/libc/src/unistd/linux/sysconf.cpp b/libc/src/unistd/linux/sysconf.cpp
index 3243b7afa5596..0578d3a6c319c 100644
--- a/libc/src/unistd/linux/sysconf.cpp
+++ b/libc/src/unistd/linux/sysconf.cpp
@@ -10,6 +10,7 @@
 
 #include "src/__support/common.h"
 
+#include "hdr/sys_auxv_macros.h"
 #include "hdr/unistd_macros.h"
 #include "src/__support/OSUtil/linux/auxv.h"
 #include "src/__support/OSUtil/linux/sysinfo.h"
diff --git a/libc/test/src/sys/auxv/linux/CMakeLists.txt b/libc/test/src/sys/auxv/linux/CMakeLists.txt
index 66370118bf6d6..3eb1c092b2070 100644
--- a/libc/test/src/sys/auxv/linux/CMakeLists.txt
+++ b/libc/test/src/sys/auxv/linux/CMakeLists.txt
@@ -6,10 +6,10 @@ add_libc_unittest(
   SRCS
     getauxval_test.cpp
   DEPENDS
-    libc.include.sys_auxv
+    libc.hdr.sys_auxv_macros
     libc.src.errno.errno
+    libc.src.string.memory_utils.inline_strstr
     libc.src.sys.auxv.getauxval
     libc.test.UnitTest.ErrnoCheckingTest
     libc.test.UnitTest.ErrnoSetterMatcher
-    libc.src.string.strstr
 )
diff --git a/libc/test/src/sys/auxv/linux/getauxval_test.cpp b/libc/test/src/sys/auxv/linux/getauxval_test.cpp
index b8728b7ad775c..f266717aa7c9c 100644
--- a/libc/test/src/sys/auxv/linux/getauxval_test.cpp
+++ b/libc/test/src/sys/auxv/linux/getauxval_test.cpp
@@ -6,12 +6,12 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "hdr/sys_auxv_macros.h"
+#include "src/string/memory_utils/inline_strstr.h"
 #include "src/sys/auxv/getauxval.h"
 #include "test/UnitTest/ErrnoCheckingTest.h"
 #include "test/UnitTest/ErrnoSetterMatcher.h"
 #include "test/UnitTest/Test.h"
-#include <src/string/strstr.h>
-#include <sys/auxv.h>
 
 using namespace LIBC_NAMESPACE::testing::ErrnoSetterMatcher;
 using LlvmLibcGetauxvalTest = LIBC_NAMESPACE::testing::ErrnoCheckingTest;
@@ -26,5 +26,7 @@ TEST_F(LlvmLibcGetauxvalTest, Basic) {
     return value;
   };
   EXPECT_THAT(getfilename(), returns(NE(0ul)).with_errno(EQ(0)));
-  ASSERT_TRUE(LIBC_NAMESPACE::strstr(filename, "getauxval_test") != nullptr);
+  ASSERT_TRUE(LIBC_NAMESPACE::inline_strstr(
+                  filename, "getauxval_test",
+                  [](char a, char b) { return a - b; }) != nullptr);
 }

>From 7c22107f9dd14f9ba3d8f4b7e0e4b2a5061fbc10 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 27 Apr 2026 11:33:40 -0400
Subject: [PATCH 8/9] add comment

---
 libc/src/__support/OSUtil/linux/sysinfo.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libc/src/__support/OSUtil/linux/sysinfo.h b/libc/src/__support/OSUtil/linux/sysinfo.h
index 2b041fd817117..f793c7522fd1e 100644
--- a/libc/src/__support/OSUtil/linux/sysinfo.h
+++ b/libc/src/__support/OSUtil/linux/sysinfo.h
@@ -102,6 +102,8 @@ class ProcParser {
 
   LIBC_INLINE bool consume(char ch) {
     if (internal::isdigit(ch)) {
+      // Not using internal::strtointeger here because a number can be across
+      // two reads in rare cases.
       current_number = current_number * 10 + static_cast<size_t>(ch - '0');
       if (state == ProcParserState::ParseUnstarted)
         state = ProcParserState::ParseNumber;

>From 3cc439094e53509403ee01b7a62cd849227472c4 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Tue, 28 Apr 2026 11:53:54 -0400
Subject: [PATCH 9/9] fix

---
 .../src/__support/OSUtil/linux/CMakeLists.txt |  3 ++
 libc/src/__support/OSUtil/linux/sysinfo.h     | 29 +++++++++++++------
 .../__support/OSUtil/linux/sysinfo_test.cpp   |  9 +++---
 3 files changed, 28 insertions(+), 13 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/CMakeLists.txt b/libc/src/__support/OSUtil/linux/CMakeLists.txt
index 355d052765514..e872bb5e14189 100644
--- a/libc/src/__support/OSUtil/linux/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/CMakeLists.txt
@@ -47,11 +47,14 @@ add_header_library(
     libc.src.__support.CPP.array
     libc.src.__support.CPP.bit
     libc.src.__support.CPP.optional
+    libc.src.__support.CPP.string_view
+    libc.src.__support.libc_assert
     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
+    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 f793c7522fd1e..715ac3bc3d484 100644
--- a/libc/src/__support/OSUtil/linux/sysinfo.h
+++ b/libc/src/__support/OSUtil/linux/sysinfo.h
@@ -13,19 +13,22 @@
 #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/libc_assert.h"
 #include "src/__support/macros/config.h"
+#include "src/string/memory_utils/inline_memcpy.h"
 
 namespace LIBC_NAMESPACE_DECL {
 namespace sysinfo {
 
-LIBC_INLINE_VAR constexpr char POSSIBLE_NPROC_PATH[] =
+LIBC_INLINE_VAR constexpr cpp::string_view POSSIBLE_NPROC_PATH =
     "/sys/devices/system/cpu/possible";
-LIBC_INLINE_VAR constexpr char ONLINE_NPROC_PATH[] =
+LIBC_INLINE_VAR constexpr cpp::string_view ONLINE_NPROC_PATH =
     "/sys/devices/system/cpu/online";
 
 // Parses Linux CPU-list syntax:
@@ -50,9 +53,19 @@ class ProcParser {
   size_t range_start;
   bool has_error;
 
-  LIBC_INLINE static int open_path(const char *path) {
+  LIBC_INLINE static int open_path(cpp::string_view path) {
+    // Zero initialized
+    cpp::array<char, 64> buffer{};
+#ifdef NDEBUG
+    if (LIBC_UNLIKELY(path.size() <= buffer.size()))
+      __builtin_trap();
+#else
+    LIBC_ASSERT(path.size() < buffer.size() &&
+                "we don't support long paths in process parser");
+#endif
+    inline_memcpy(buffer.data(), path.data(), path.size());
     ErrorOr<int> open_result =
-        linux_syscalls::open(path, O_RDONLY | O_CLOEXEC, 0);
+        linux_syscalls::open(buffer.data(), O_RDONLY | O_CLOEXEC, 0);
     return open_result ? *open_result : -1;
   }
 
@@ -131,9 +144,7 @@ class ProcParser {
   }
 
 public:
-  // Using string view isn't exactly correct because we demands null-terminated
-  // strings.
-  LIBC_INLINE explicit ProcParser(const char *path)
+  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) {}
@@ -163,11 +174,11 @@ class ProcParser {
   }
 };
 
-LIBC_INLINE cpp::optional<size_t> parse_nproc_from(const char *path) {
+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(const char *path) {
+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;
 
diff --git a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
index 800f062343c2c..e891866cad021 100644
--- a/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
+++ b/libc/test/src/__support/OSUtil/linux/sysinfo_test.cpp
@@ -16,7 +16,7 @@
 
 namespace LIBC_NAMESPACE_DECL {
 
-static int write_test_file(const char *path, cpp::string_view contents) {
+static int write_test_file(const CString &path, cpp::string_view contents) {
   int fd = LIBC_NAMESPACE::open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600);
   if (fd < 0)
     return fd;
@@ -53,7 +53,7 @@ TEST(LlvmLibcOSUtilSysinfoTest, SyntheticCpuLists) {
   constexpr char FILENAME[] =
       APPEND_LIBC_TEST("sysinfo.synthetic_cpu_list.test");
   CString test_file = libc_make_test_file_path(FILENAME);
-
+  cpp::string_view test_file_view{static_cast<const char *>(test_file)};
   struct TestCase {
     cpp::string_view contents;
     cpp::optional<size_t> expected;
@@ -72,11 +72,12 @@ TEST(LlvmLibcOSUtilSysinfoTest, SyntheticCpuLists) {
 
   for (const TestCase &test_case : TEST_CASES) {
     ASSERT_EQ(write_test_file(test_file, test_case.contents), 0);
-    cpp::optional<size_t> parsed = sysinfo::parse_nproc_from(test_file);
+    cpp::optional<size_t> parsed = sysinfo::parse_nproc_from(test_file_view);
     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), size_t(0));
+    EXPECT_GT(sysinfo::parse_nproc_with_fallback_from(test_file_view),
+              size_t(0));
   }
 
   ASSERT_EQ(LIBC_NAMESPACE::unlink(test_file), 0);



More information about the libc-commits mailing list