[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 07:15:39 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/6] [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/6] 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/6] 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/6] 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/6] 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/6] 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)));
More information about the libc-commits
mailing list