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

via libc-commits libc-commits at lists.llvm.org
Thu Jun 11 09:15:21 PDT 2026


Author: Pavel Labath
Date: 2026-06-11T16:15:15Z
New Revision: 053c94e66386931494074db1db02818ab0f9bec9

URL: https://github.com/llvm/llvm-project/commit/053c94e66386931494074db1db02818ab0f9bec9
DIFF: https://github.com/llvm/llvm-project/commit/053c94e66386931494074db1db02818ab0f9bec9.diff

LOG: [libc] Implement CPU_ALLOC and CPU_FREE (#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.

Added: 
    libc/src/sched/linux/sched_cpualloc.cpp
    libc/src/sched/linux/sched_cpufree.cpp
    libc/src/sched/sched_cpualloc.h
    libc/src/sched/sched_cpufree.h
    libc/test/src/sched/cpu_alloc_test.cpp

Modified: 
    libc/config/linux/aarch64/entrypoints.txt
    libc/config/linux/riscv/entrypoints.txt
    libc/config/linux/x86_64/entrypoints.txt
    libc/include/llvm-libc-macros/linux/sched-macros.h
    libc/include/llvm-libc-types/cpu_set_t.h
    libc/include/sched.yaml
    libc/src/sched/CMakeLists.txt
    libc/src/sched/linux/CMakeLists.txt
    libc/test/src/sched/CMakeLists.txt

Removed: 
    


################################################################################
diff  --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 9eb6b61f57729..88ae0e8389517 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1095,6 +1095,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 189f748279421..4eec6c8679fad 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1228,6 +1228,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 d70908f873cc6..42603ec89d4c8 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1290,6 +1290,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..afe357e38bf1c 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: size_t
+  - 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..8a00c1a136736
--- /dev/null
+++ b/libc/src/sched/linux/sched_cpualloc.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux implementation of __sched_cpualloc.
+///
+//===----------------------------------------------------------------------===//
+
+#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 "hdr/types/size_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, (size_t 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..aeb532a680e8e
--- /dev/null
+++ b/libc/src/sched/linux/sched_cpufree.cpp
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Linux implementation of __sched_cpufree.
+///
+//===----------------------------------------------------------------------===//
+
+#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..8a5d65b9d6c2f
--- /dev/null
+++ b/libc/src/sched/sched_cpualloc.h
@@ -0,0 +1,27 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for __sched_cpualloc.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SCHED_SCHED_CPUALLOC_H
+#define LLVM_LIBC_SRC_SCHED_SCHED_CPUALLOC_H
+
+#include "hdr/types/cpu_set_t.h"
+#include "hdr/types/size_t.h"
+#include "src/__support/macros/config.h"
+
+namespace LIBC_NAMESPACE_DECL {
+
+cpu_set_t *__sched_cpualloc(size_t 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..ac75c2d5d5132
--- /dev/null
+++ b/libc/src/sched/sched_cpufree.h
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Implementation header for __sched_cpufree.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_SCHED_SCHED_CPUFREE_H
+#define LLVM_LIBC_SRC_SCHED_SCHED_CPUFREE_H
+
+#include "hdr/types/cpu_set_t.h"
+#include "src/__support/macros/config.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..45f5a60db1eda
--- /dev/null
+++ b/libc/test/src/sched/cpu_alloc_test.cpp
@@ -0,0 +1,77 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Unit tests for __sched_cpualloc and __sched_cpufree.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sched_macros.h"
+#include "hdr/types/cpu_set_t.h"
+#include "include/llvm-libc-macros/linux/sched-macros.h"
+#include "include/llvm-libc-types/cpu_set_t.h"
+#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"
+
+using LlvmLibcSchedCpuAllocTest = LIBC_NAMESPACE::testing::Test;
+
+TEST_F(LlvmLibcSchedCpuAllocTest, AllocAndFreeSmall) {
+  int num_cpus = 10;
+  size_t alloc_size = CPU_ALLOC_SIZE(num_cpus);
+  cpu_set_t *mask = LIBC_NAMESPACE::__sched_cpualloc(num_cpus);
+  ASSERT_NE(mask, static_cast<cpu_set_t *>(nullptr));
+
+  LIBC_NAMESPACE::__sched_setcpuzero(alloc_size, mask);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpucount(alloc_size, mask), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpuisset(1, alloc_size, mask), 0);
+
+  LIBC_NAMESPACE::__sched_setcpuset(1, alloc_size, mask);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpuisset(1, alloc_size, mask), 1);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpucount(alloc_size, mask), 1);
+
+  LIBC_NAMESPACE::__sched_setcpuset(5, alloc_size, mask);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpuisset(5, alloc_size, mask), 1);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpucount(alloc_size, mask), 2);
+
+  LIBC_NAMESPACE::__sched_cpufree(mask);
+}
+
+TEST_F(LlvmLibcSchedCpuAllocTest, AllocAndFreeLarge) {
+  int num_cpus = 4096;
+  size_t alloc_size = CPU_ALLOC_SIZE(num_cpus);
+  cpu_set_t *mask = LIBC_NAMESPACE::__sched_cpualloc(num_cpus);
+  ASSERT_NE(mask, static_cast<cpu_set_t *>(nullptr));
+
+  LIBC_NAMESPACE::__sched_setcpuzero(alloc_size, mask);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpucount(alloc_size, mask), 0);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpuisset(1, alloc_size, mask), 0);
+
+  LIBC_NAMESPACE::__sched_setcpuset(1, alloc_size, mask);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpuisset(1, alloc_size, mask), 1);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpucount(alloc_size, mask), 1);
+
+  LIBC_NAMESPACE::__sched_setcpuset(500, alloc_size, mask);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpuisset(500, alloc_size, mask), 1);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpucount(alloc_size, mask), 2);
+
+  LIBC_NAMESPACE::__sched_setcpuset(4095, alloc_size, mask);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpuisset(4095, alloc_size, mask), 1);
+  ASSERT_EQ(LIBC_NAMESPACE::__sched_getcpucount(alloc_size, mask), 3);
+
+  LIBC_NAMESPACE::__sched_cpufree(mask);
+}
+
+TEST_F(LlvmLibcSchedCpuAllocTest, AllocAndFreeZero) {
+  cpu_set_t *mask = LIBC_NAMESPACE::__sched_cpualloc(/*count=*/0);
+  LIBC_NAMESPACE::__sched_cpufree(mask);
+}


        


More information about the libc-commits mailing list