[libc-commits] [libc] [libc] Implement CPU_ALLOC and CPU_FREE (PR #202349)

Pavel Labath via libc-commits libc-commits at lists.llvm.org
Mon Jun 8 07:49:47 PDT 2026


https://github.com/labath created https://github.com/llvm/llvm-project/pull/202349

Like the other macros, this commit uses an internal (__-prefixed) entrypoint.

I added an internal typedef for the mask type to make bit set calculations slightly safer. I also removed the comment about supporting larger cpu counts, as increasing the struct size is not necessary to do that -- that's what these macros are for. Increasing it would be necessary to support operations on the fixed-size cpu sets, but that cannot be done lightly due to ABI stability.

I added a test that checks allocations for both small and large cpu set sizes.

Assisted by Gemini.

>From 928402ff47f0b5db7cd8e5879388cced88f13434 Mon Sep 17 00:00:00 2001
From: Pavel Labath <pavel at labath.sk>
Date: Mon, 8 Jun 2026 13:50:27 +0000
Subject: [PATCH] [libc] Implement CPU_ALLOC and CPU_FREE

Like the other macros, this commit uses an internal (__-prefixed)
entrypoint.

I added a test that checks allocations for both small and large cpu set
sizes.

Assisted by Gemini.
---
 libc/config/linux/aarch64/entrypoints.txt     |  2 +
 libc/config/linux/riscv/entrypoints.txt       |  2 +
 libc/config/linux/x86_64/entrypoints.txt      |  2 +
 .../llvm-libc-macros/linux/sched-macros.h     |  5 ++
 libc/include/llvm-libc-types/cpu_set_t.h      |  5 +-
 libc/include/sched.yaml                       | 12 ++++
 libc/src/sched/CMakeLists.txt                 | 14 ++++
 libc/src/sched/linux/CMakeLists.txt           | 32 +++++++++
 libc/src/sched/linux/sched_cpualloc.cpp       | 32 +++++++++
 libc/src/sched/linux/sched_cpufree.cpp        | 22 ++++++
 libc/src/sched/sched_cpualloc.h               | 21 ++++++
 libc/src/sched/sched_cpufree.h                | 21 ++++++
 libc/test/src/sched/CMakeLists.txt            | 17 +++++
 libc/test/src/sched/cpu_alloc_test.cpp        | 69 +++++++++++++++++++
 14 files changed, 253 insertions(+), 3 deletions(-)
 create mode 100644 libc/src/sched/linux/sched_cpualloc.cpp
 create mode 100644 libc/src/sched/linux/sched_cpufree.cpp
 create mode 100644 libc/src/sched/sched_cpualloc.h
 create mode 100644 libc/src/sched/sched_cpufree.h
 create mode 100644 libc/test/src/sched/cpu_alloc_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 590b8c19bf1ef..55a36b05ea033 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1092,6 +1092,8 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_setspecific
 
     # sched.h entrypoints
+    libc.src.sched.__sched_cpualloc
+    libc.src.sched.__sched_cpufree
     libc.src.sched.__sched_getcpucount
     libc.src.sched.__sched_setcpuzero
     libc.src.sched.__sched_setcpuset
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 5cea007a6c3ae..0aaba580826e0 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1225,6 +1225,8 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_setspecific
 
     # sched.h entrypoints
+    libc.src.sched.__sched_cpualloc
+    libc.src.sched.__sched_cpufree
     libc.src.sched.__sched_getcpucount
     libc.src.sched.__sched_setcpuzero
     libc.src.sched.__sched_setcpuset
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 0bf88f504cd3c..2ff189a59d24f 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1287,6 +1287,8 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_setspecific
 
     # sched.h entrypoints
+    libc.src.sched.__sched_cpualloc
+    libc.src.sched.__sched_cpufree
     libc.src.sched.__sched_getcpucount
     libc.src.sched.__sched_setcpuzero
     libc.src.sched.__sched_setcpuset
diff --git a/libc/include/llvm-libc-macros/linux/sched-macros.h b/libc/include/llvm-libc-macros/linux/sched-macros.h
index 4d8aafbc2df21..539b3530f6e14 100644
--- a/libc/include/llvm-libc-macros/linux/sched-macros.h
+++ b/libc/include/llvm-libc-macros/linux/sched-macros.h
@@ -34,4 +34,9 @@
 #define CPU_ISSET_S(cpu, setsize, set) __sched_getcpuisset(cpu, setsize, set)
 #define CPU_ISSET(cpu, set) CPU_ISSET_S(cpu, sizeof(cpu_set_t), set)
 
+#define CPU_ALLOC_SIZE(count)                                                  \
+  ((((count) + NCPUBITS - 1) / NCPUBITS) * sizeof(__cpu_set_mask_t))
+#define CPU_ALLOC(count) __sched_cpualloc(count)
+#define CPU_FREE(set) __sched_cpufree(set)
+
 #endif // LLVM_LIBC_MACROS_LINUX_SCHED_MACROS_H
diff --git a/libc/include/llvm-libc-types/cpu_set_t.h b/libc/include/llvm-libc-types/cpu_set_t.h
index 8c6859de5f1d4..420b0aa002402 100644
--- a/libc/include/llvm-libc-types/cpu_set_t.h
+++ b/libc/include/llvm-libc-types/cpu_set_t.h
@@ -11,11 +11,10 @@
 
 #define __CPU_SETSIZE 1024
 #define __NCPUBITS (8 * sizeof(unsigned long))
+typedef unsigned long __cpu_set_mask_t;
 
 typedef struct {
-  // If a processor with more than 1024 CPUs is to be supported in future,
-  // we need to adjust the size of this array.
-  unsigned long __mask[128 / sizeof(unsigned long)];
+  __cpu_set_mask_t __mask[__CPU_SETSIZE / __NCPUBITS];
 } cpu_set_t;
 
 #endif // LLVM_LIBC_TYPES_CPU_SET_T_H
diff --git a/libc/include/sched.yaml b/libc/include/sched.yaml
index f34fc73f9e8b2..82cc618fc8395 100644
--- a/libc/include/sched.yaml
+++ b/libc/include/sched.yaml
@@ -18,6 +18,18 @@ types:
 enums: []
 objects: []
 functions:
+  - name: __sched_cpualloc
+    standards:
+      - llvm_libc_ext
+    return_type: cpu_set_t *
+    arguments:
+      - type: int
+  - name: __sched_cpufree
+    standards:
+      - llvm_libc_ext
+    return_type: void
+    arguments:
+      - type: cpu_set_t *
   - name: __sched_getcpucount
     standards:
       - llvm_libc_ext
diff --git a/libc/src/sched/CMakeLists.txt b/libc/src/sched/CMakeLists.txt
index 39ac8c8c6f247..3aef41f996962 100644
--- a/libc/src/sched/CMakeLists.txt
+++ b/libc/src/sched/CMakeLists.txt
@@ -86,6 +86,20 @@ add_entrypoint_object(
     .${LIBC_TARGET_OS}.sched_rr_get_interval
 )
 
+add_entrypoint_object(
+  __sched_cpualloc
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.__sched_cpualloc
+)
+
+add_entrypoint_object(
+  __sched_cpufree
+  ALIAS
+  DEPENDS
+    .${LIBC_TARGET_OS}.__sched_cpufree
+)
+
 add_entrypoint_object(
   __sched_getcpucount
   ALIAS
diff --git a/libc/src/sched/linux/CMakeLists.txt b/libc/src/sched/linux/CMakeLists.txt
index 6cc41e97baa00..b8662c6383e74 100644
--- a/libc/src/sched/linux/CMakeLists.txt
+++ b/libc/src/sched/linux/CMakeLists.txt
@@ -168,6 +168,38 @@ add_entrypoint_object(
     libc.src.errno.errno
 )
 
+add_entrypoint_object(
+  __sched_cpualloc
+  SRCS
+    sched_cpualloc.cpp
+  HDRS
+    ../sched_cpualloc.h
+  DEPENDS
+    libc.hdr.errno_macros
+    libc.hdr.sched_macros
+    libc.hdr.stdint_proxy
+    libc.hdr.types.cpu_set_t
+    libc.src.__support.alloc_checker
+    libc.src.__support.common
+    libc.src.__support.CPP.new
+    libc.src.__support.macros.config
+    libc.src.errno.errno
+)
+
+add_entrypoint_object(
+  __sched_cpufree
+  SRCS
+    sched_cpufree.cpp
+  HDRS
+    ../sched_cpufree.h
+  DEPENDS
+    libc.hdr.stdint_proxy
+    libc.hdr.types.cpu_set_t
+    libc.src.__support.common
+    libc.src.__support.CPP.new
+    libc.src.__support.macros.config
+)
+
 add_entrypoint_object(
   __sched_setcpuzero
   SRCS
diff --git a/libc/src/sched/linux/sched_cpualloc.cpp b/libc/src/sched/linux/sched_cpualloc.cpp
new file mode 100644
index 0000000000000..d1ed5c933d683
--- /dev/null
+++ b/libc/src/sched/linux/sched_cpualloc.cpp
@@ -0,0 +1,32 @@
+//===-- Implementation of sched_cpualloc ----------------------------------===//
+//
+// 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/sched/sched_cpualloc.h"
+#include "hdr/errno_macros.h"
+#include "hdr/sched_macros.h"
+#include "hdr/stdint_proxy.h"
+#include "hdr/types/cpu_set_t.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/alloc-checker.h"
+#include "src/__support/common.h"
+#include "src/__support/libc_errno.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(cpu_set_t *, __sched_cpualloc, (int count)) {
+  AllocChecker ac;
+  uint8_t *bytes = new (ac) uint8_t[CPU_ALLOC_SIZE(count)];
+  if (!ac) {
+    libc_errno = ENOMEM;
+    return nullptr;
+  }
+  return reinterpret_cast<cpu_set_t *>(bytes);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sched/linux/sched_cpufree.cpp b/libc/src/sched/linux/sched_cpufree.cpp
new file mode 100644
index 0000000000000..a3d9629663e78
--- /dev/null
+++ b/libc/src/sched/linux/sched_cpufree.cpp
@@ -0,0 +1,22 @@
+//===-- Implementation of sched_cpufree -----------------------------------===//
+//
+// 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/sched/sched_cpufree.h"
+#include "hdr/stdint_proxy.h"
+#include "hdr/types/cpu_set_t.h"
+#include "src/__support/CPP/new.h"
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+LLVM_LIBC_FUNCTION(void, __sched_cpufree, (cpu_set_t *set)) {
+  delete[] reinterpret_cast<uint8_t *>(set);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/sched/sched_cpualloc.h b/libc/src/sched/sched_cpualloc.h
new file mode 100644
index 0000000000000..de427b26bdaec
--- /dev/null
+++ b/libc/src/sched/sched_cpualloc.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sched_cpualloc ----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SCHED_SCHED_CPUALLOC_H
+#define LLVM_LIBC_SRC_SCHED_SCHED_CPUALLOC_H
+
+#include "src/__support/macros/config.h"
+#include "hdr/types/cpu_set_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+cpu_set_t *__sched_cpualloc(int count);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SCHED_SCHED_CPUALLOC_H
diff --git a/libc/src/sched/sched_cpufree.h b/libc/src/sched/sched_cpufree.h
new file mode 100644
index 0000000000000..44391e59530a1
--- /dev/null
+++ b/libc/src/sched/sched_cpufree.h
@@ -0,0 +1,21 @@
+//===-- Implementation header for sched_cpufree -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SCHED_SCHED_CPUFREE_H
+#define LLVM_LIBC_SRC_SCHED_SCHED_CPUFREE_H
+
+#include "src/__support/macros/config.h"
+#include "hdr/types/cpu_set_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+void __sched_cpufree(cpu_set_t *set);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_SCHED_SCHED_CPUFREE_H
diff --git a/libc/test/src/sched/CMakeLists.txt b/libc/test/src/sched/CMakeLists.txt
index 421be2cf2743f..b8dbf609ecd0f 100644
--- a/libc/test/src/sched/CMakeLists.txt
+++ b/libc/test/src/sched/CMakeLists.txt
@@ -106,6 +106,23 @@ add_libc_unittest(
     libc.test.UnitTest.ErrnoCheckingTest
 )
 
+add_libc_unittest(
+  cpu_alloc_test
+  SUITE
+    libc_sched_unittests
+  SRCS
+    cpu_alloc_test.cpp
+  DEPENDS
+    libc.hdr.sched_macros
+    libc.hdr.types.cpu_set_t
+    libc.src.sched.__sched_cpualloc
+    libc.src.sched.__sched_cpufree
+    libc.src.sched.__sched_getcpucount
+    libc.src.sched.__sched_getcpuisset
+    libc.src.sched.__sched_setcpuset
+    libc.src.sched.__sched_setcpuzero
+)
+
 add_libc_unittest(
   cpu_count_test
   SUITE
diff --git a/libc/test/src/sched/cpu_alloc_test.cpp b/libc/test/src/sched/cpu_alloc_test.cpp
new file mode 100644
index 0000000000000..898da3c2ab7d0
--- /dev/null
+++ b/libc/test/src/sched/cpu_alloc_test.cpp
@@ -0,0 +1,69 @@
+//===-- Unittests for __sched_cpualloc and __sched_cpufree ----------------===//
+//
+// 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/sched/sched_cpualloc.h"
+#include "src/sched/sched_cpufree.h"
+#include "src/sched/sched_getcpucount.h"
+#include "src/sched/sched_getcpuisset.h"
+#include "src/sched/sched_setcpuset.h"
+#include "src/sched/sched_setcpuzero.h"
+#include "test/UnitTest/Test.h"
+#include "hdr/sched_macros.h"
+#include "hdr/types/cpu_set_t.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+using LlvmLibcSchedCpuAllocTest = testing::Test;
+
+TEST_F(LlvmLibcSchedCpuAllocTest, AllocAndFreeSmall) {
+  int num_cpus = 10;
+  size_t alloc_size = CPU_ALLOC_SIZE(num_cpus);
+  cpu_set_t *mask = CPU_ALLOC(num_cpus);
+  ASSERT_NE(mask, static_cast<cpu_set_t *>(nullptr));
+
+  CPU_ZERO_S(alloc_size, mask);
+  ASSERT_EQ(CPU_COUNT_S(alloc_size, mask), 0);
+  ASSERT_EQ(CPU_ISSET_S(1, alloc_size, mask), 0);
+
+  CPU_SET_S(1, alloc_size, mask);
+  ASSERT_EQ(CPU_ISSET_S(1, alloc_size, mask), 1);
+  ASSERT_EQ(CPU_COUNT_S(alloc_size, mask), 1);
+
+  CPU_SET_S(5, alloc_size, mask);
+  ASSERT_EQ(CPU_ISSET_S(5, alloc_size, mask), 1);
+  ASSERT_EQ(CPU_COUNT_S(alloc_size, mask), 2);
+
+  CPU_FREE(mask);
+}
+
+TEST_F(LlvmLibcSchedCpuAllocTest, AllocAndFreeLarge) {
+  int num_cpus = 4096;
+  size_t alloc_size = CPU_ALLOC_SIZE(num_cpus);
+  cpu_set_t *mask = CPU_ALLOC(num_cpus);
+  ASSERT_NE(mask, static_cast<cpu_set_t *>(nullptr));
+
+  CPU_ZERO_S(alloc_size, mask);
+  ASSERT_EQ(CPU_COUNT_S(alloc_size, mask), 0);
+  ASSERT_EQ(CPU_ISSET_S(1, alloc_size, mask), 0);
+
+  CPU_SET_S(1, alloc_size, mask);
+  ASSERT_EQ(CPU_ISSET_S(1, alloc_size, mask), 1);
+  ASSERT_EQ(CPU_COUNT_S(alloc_size, mask), 1);
+
+  CPU_SET_S(500, alloc_size, mask);
+  ASSERT_EQ(CPU_ISSET_S(500, alloc_size, mask), 1);
+  ASSERT_EQ(CPU_COUNT_S(alloc_size, mask), 2);
+
+  CPU_SET_S(4095, alloc_size, mask);
+  ASSERT_EQ(CPU_ISSET_S(4095, alloc_size, mask), 1);
+  ASSERT_EQ(CPU_COUNT_S(alloc_size, mask), 3);
+
+  CPU_FREE(mask);
+}
+
+} // namespace LIBC_NAMESPACE_DECL



More information about the libc-commits mailing list