[libc-commits] [libc] [libc] Implement pthread_setschedparam and getschedparam (PR #205770)

Jeff Bailey via libc-commits libc-commits at lists.llvm.org
Tue Jul 21 06:57:55 PDT 2026


https://github.com/kaladron updated https://github.com/llvm/llvm-project/pull/205770

>From d5e493a2db02805ba94283c5c98aa8cc35a0ada3 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Thu, 25 Jun 2026 08:32:09 +0100
Subject: [PATCH 1/2] [libc] Implement pthread_setschedparam and getschedparam

Implemented the pthread_setschedparam and pthread_getschedparam
functions.

Added Linux syscall wrappers:
* sched_setscheduler
* sched_getscheduler
* sched_getparam

Updated the Thread class to support getting and setting scheduling
parameters.

Added integration tests to verify the implementation.

Assisted-by: Automated tooling, human reviewed.
---
 libc/config/linux/aarch64/entrypoints.txt     |  2 +
 libc/config/linux/riscv/entrypoints.txt       |  2 +
 libc/config/linux/x86_64/entrypoints.txt      |  2 +
 libc/include/pthread.yaml                     | 12 +++
 .../linux/syscall_wrappers/CMakeLists.txt     | 41 +++++++++
 .../linux/syscall_wrappers/sched_getparam.h   | 39 ++++++++
 .../syscall_wrappers/sched_getscheduler.h     | 38 ++++++++
 .../syscall_wrappers/sched_setscheduler.h     | 40 ++++++++
 .../__support/threads/linux/CMakeLists.txt    |  3 +
 libc/src/__support/threads/linux/thread.cpp   | 24 +++++
 libc/src/__support/threads/thread.h           | 16 ++++
 libc/src/pthread/CMakeLists.txt               | 24 +++++
 libc/src/pthread/pthread_getschedparam.cpp    | 37 ++++++++
 libc/src/pthread/pthread_getschedparam.h      | 27 ++++++
 libc/src/pthread/pthread_setschedparam.cpp    | 36 ++++++++
 libc/src/pthread/pthread_setschedparam.h      | 27 ++++++
 .../integration/src/pthread/CMakeLists.txt    | 17 ++++
 .../pthread/pthread_setschedparam_test.cpp    | 92 +++++++++++++++++++
 18 files changed, 479 insertions(+)
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getparam.h
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h
 create mode 100644 libc/src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h
 create mode 100644 libc/src/pthread/pthread_getschedparam.cpp
 create mode 100644 libc/src/pthread/pthread_getschedparam.h
 create mode 100644 libc/src/pthread/pthread_setschedparam.cpp
 create mode 100644 libc/src/pthread/pthread_setschedparam.h
 create mode 100644 libc/test/integration/src/pthread/pthread_setschedparam_test.cpp

diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt
index 2e7b9276ab068..8eaa4871837bd 100644
--- a/libc/config/linux/aarch64/entrypoints.txt
+++ b/libc/config/linux/aarch64/entrypoints.txt
@@ -1085,6 +1085,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_equal
     libc.src.pthread.pthread_exit
     libc.src.pthread.pthread_getname_np
+    libc.src.pthread.pthread_getschedparam
     libc.src.pthread.pthread_getspecific
     libc.src.pthread.pthread_getthreadid_np
     libc.src.pthread.pthread_getunique_np
@@ -1129,6 +1130,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_spin_unlock
     libc.src.pthread.pthread_self
     libc.src.pthread.pthread_setname_np
+    libc.src.pthread.pthread_setschedparam
     libc.src.pthread.pthread_setspecific
 
     # sched.h entrypoints
diff --git a/libc/config/linux/riscv/entrypoints.txt b/libc/config/linux/riscv/entrypoints.txt
index 8a29e77ffe0fd..c6a4b431f33de 100644
--- a/libc/config/linux/riscv/entrypoints.txt
+++ b/libc/config/linux/riscv/entrypoints.txt
@@ -1279,6 +1279,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_equal
     libc.src.pthread.pthread_exit
     libc.src.pthread.pthread_getname_np
+    libc.src.pthread.pthread_getschedparam
     libc.src.pthread.pthread_getspecific
     libc.src.pthread.pthread_getthreadid_np
     libc.src.pthread.pthread_getunique_np
@@ -1326,6 +1327,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_spin_unlock
     libc.src.pthread.pthread_self
     libc.src.pthread.pthread_setname_np
+    libc.src.pthread.pthread_setschedparam
     libc.src.pthread.pthread_setspecific
 
     # sched.h entrypoints
diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt
index 0a4fb747c2940..fb0886e2e650a 100644
--- a/libc/config/linux/x86_64/entrypoints.txt
+++ b/libc/config/linux/x86_64/entrypoints.txt
@@ -1284,6 +1284,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_equal
     libc.src.pthread.pthread_exit
     libc.src.pthread.pthread_getname_np
+    libc.src.pthread.pthread_getschedparam
     libc.src.pthread.pthread_getspecific
     libc.src.pthread.pthread_getthreadid_np
     libc.src.pthread.pthread_getunique_np
@@ -1331,6 +1332,7 @@ if(LLVM_LIBC_FULL_BUILD)
     libc.src.pthread.pthread_spin_unlock
     libc.src.pthread.pthread_self
     libc.src.pthread.pthread_setname_np
+    libc.src.pthread.pthread_setschedparam
     libc.src.pthread.pthread_setspecific
 
     # sched.h entrypoints
diff --git a/libc/include/pthread.yaml b/libc/include/pthread.yaml
index eeb8a200b0038..c3e967c67ee8f 100644
--- a/libc/include/pthread.yaml
+++ b/libc/include/pthread.yaml
@@ -232,6 +232,12 @@ functions:
       - type: pthread_t
       - type: char *
       - type: size_t
+  - name: pthread_getschedparam
+    return_type: int
+    arguments:
+      - type: pthread_t
+      - type: int *__restrict
+      - type: struct sched_param *__restrict
   - name: pthread_getspecific
     return_type: void *
     arguments:
@@ -422,6 +428,12 @@ functions:
     arguments:
       - type: pthread_t
       - type: const char *
+  - name: pthread_setschedparam
+    return_type: int
+    arguments:
+      - type: pthread_t
+      - type: int
+      - type: const struct sched_param *
   - name: pthread_setspecific
     return_type: int
     arguments:
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
index 27df4c3f22afb..7d5f94513d0de 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/CMakeLists.txt
@@ -40,6 +40,47 @@ add_header_library(
     libc.include.sys_syscall
 )
 
+add_header_library(
+  sched_setscheduler
+  HDRS
+    sched_setscheduler.h
+  DEPENDS
+    libc.hdr.types.pid_t
+    libc.hdr.types.struct_sched_param
+    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(
+  sched_getscheduler
+  HDRS
+    sched_getscheduler.h
+  DEPENDS
+    libc.hdr.types.pid_t
+    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(
+  sched_getparam
+  HDRS
+    sched_getparam.h
+  DEPENDS
+    libc.hdr.types.pid_t
+    libc.hdr.types.struct_sched_param
+    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_getparam.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getparam.h
new file mode 100644
index 0000000000000..7eab051c67972
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getparam.h
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_getparam syscall wrapper.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETPARAM_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETPARAM_H
+
+#include "hdr/types/pid_t.h"
+#include "hdr/types/struct_sched_param.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_getparam(pid_t tid, struct sched_param *param) {
+  int ret = syscall_impl<int>(SYS_sched_getparam, tid, param);
+  if (ret < 0)
+    return Error(-ret);
+  return ret;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETPARAM_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h
new file mode 100644
index 0000000000000..84ebf1aecc4ad
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h
@@ -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
+/// Implementation header for sched_getscheduler syscall wrapper.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETSCHEDULER_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETSCHEDULER_H
+
+#include "hdr/types/pid_t.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_getscheduler(pid_t tid) {
+  int ret = syscall_impl<int>(SYS_sched_getscheduler, tid);
+  if (ret < 0)
+    return Error(-ret);
+  return ret;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETSCHEDULER_H
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h
new file mode 100644
index 0000000000000..122f4c1e7c4ed
--- /dev/null
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h
@@ -0,0 +1,40 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_setscheduler syscall wrapper.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_SETSCHEDULER_H
+#define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_SETSCHEDULER_H
+
+#include "hdr/types/pid_t.h"
+#include "hdr/types/struct_sched_param.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_setscheduler(pid_t tid, int policy,
+                                            const struct sched_param *param) {
+  int ret = syscall_impl<int>(SYS_sched_setscheduler, tid, policy, param);
+  if (ret < 0)
+    return Error(-ret);
+  return ret;
+}
+
+} // namespace linux_syscalls
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_SETSCHEDULER_H
diff --git a/libc/src/__support/threads/linux/CMakeLists.txt b/libc/src/__support/threads/linux/CMakeLists.txt
index f9f2a455cd7a1..1124d1254ba76 100644
--- a/libc/src/__support/threads/linux/CMakeLists.txt
+++ b/libc/src/__support/threads/linux/CMakeLists.txt
@@ -47,6 +47,9 @@ add_object_library(
     libc.src.__support.OSUtil.linux.syscall_wrappers.munmap
     libc.src.__support.OSUtil.linux.syscall_wrappers.open
     libc.src.__support.OSUtil.linux.syscall_wrappers.read
+    libc.src.__support.OSUtil.linux.syscall_wrappers.sched_getparam
+    libc.src.__support.OSUtil.linux.syscall_wrappers.sched_getscheduler
+    libc.src.__support.OSUtil.linux.syscall_wrappers.sched_setscheduler
     libc.src.__support.OSUtil.linux.syscall_wrappers.write
     libc.src.__support.threads.thread_common
   COMPILE_OPTIONS
diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp
index f094484b64062..4d43f59f8ea9d 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -17,6 +17,9 @@
 #include "src/__support/OSUtil/linux/syscall_wrappers/munmap.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_getparam.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h"
+#include "src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h"
 #include "src/__support/OSUtil/linux/syscall_wrappers/write.h"
 #include "src/__support/OSUtil/syscall.h" // For syscall functions.
 #include "src/__support/common.h"
@@ -490,6 +493,27 @@ int Thread::get_name(cpp::StringStream &name) const {
   return 0;
 }
 
+int Thread::setschedparam(int policy, const struct sched_param *param) {
+  auto result = linux_syscalls::sched_setscheduler(attrib->tid, policy, param);
+  if (!result.has_value())
+    return result.error();
+  return 0;
+}
+
+int Thread::getschedparam(int *policy, struct sched_param *param) const {
+  auto pol_result = linux_syscalls::sched_getscheduler(attrib->tid);
+  if (!pol_result.has_value())
+    return pol_result.error();
+
+  auto param_result = linux_syscalls::sched_getparam(attrib->tid, param);
+  if (!param_result.has_value())
+    return param_result.error();
+
+  if (policy != nullptr)
+    *policy = pol_result.value();
+  return 0;
+}
+
 void thread_exit(ThreadReturnValue retval, ThreadStyle style) {
   auto attrib = self.attrib;
 
diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h
index 232b300bbba5b..9c66db5a15598 100644
--- a/libc/src/__support/threads/thread.h
+++ b/libc/src/__support/threads/thread.h
@@ -23,6 +23,8 @@
 
 #include <stddef.h> // For size_t
 
+struct sched_param;
+
 namespace LIBC_NAMESPACE_DECL {
 
 using ThreadRunnerPosix = void *(void *);
@@ -230,6 +232,20 @@ struct Thread {
 
   // Return the name of the thread in |name|. Return the error number of error.
   int get_name(cpp::StringStream &name) const;
+
+  /// Set the scheduling policy and parameters of the thread.
+  ///
+  /// \param policy The new scheduling policy.
+  /// \param param The new scheduling parameters.
+  /// \return 0 on success, or an error number on failure.
+  int setschedparam(int policy, const struct sched_param *param);
+
+  /// Get the scheduling policy and parameters of the thread.
+  ///
+  /// \param policy Pointer to store the retrieved policy (can be null).
+  /// \param param Pointer to store the retrieved parameters.
+  /// \return 0 on success, or an error number on failure.
+  int getschedparam(int *policy, struct sched_param *param) const;
 };
 
 LIBC_INLINE_VAR LIBC_THREAD_LOCAL Thread self;
diff --git a/libc/src/pthread/CMakeLists.txt b/libc/src/pthread/CMakeLists.txt
index 422116c978fb5..2b87a54b02002 100644
--- a/libc/src/pthread/CMakeLists.txt
+++ b/libc/src/pthread/CMakeLists.txt
@@ -941,3 +941,27 @@ add_entrypoint_object(
     libc.src.__support.threads.fork_callbacks
     libc.src.errno.errno
 )
+
+add_entrypoint_object(
+  pthread_setschedparam
+  SRCS
+    pthread_setschedparam.cpp
+  HDRS
+    pthread_setschedparam.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.thread
+    libc.src.__support.macros.null_check
+)
+
+add_entrypoint_object(
+  pthread_getschedparam
+  SRCS
+    pthread_getschedparam.cpp
+  HDRS
+    pthread_getschedparam.h
+  DEPENDS
+    libc.include.pthread
+    libc.src.__support.threads.thread
+    libc.src.__support.macros.null_check
+)
diff --git a/libc/src/pthread/pthread_getschedparam.cpp b/libc/src/pthread/pthread_getschedparam.cpp
new file mode 100644
index 0000000000000..ade50a11af263
--- /dev/null
+++ b/libc/src/pthread/pthread_getschedparam.cpp
@@ -0,0 +1,37 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 the pthread_getschedparam function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "pthread_getschedparam.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/__support/threads/thread.h"
+
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread),
+              "Mismatch between pthread_t and internal Thread.");
+
+LLVM_LIBC_FUNCTION(int, pthread_getschedparam,
+                   (pthread_t th, int *__restrict policy,
+                    struct sched_param *__restrict param)) {
+  LIBC_CRASH_ON_NULLPTR(policy);
+  LIBC_CRASH_ON_NULLPTR(param);
+  auto *thread = reinterpret_cast<Thread *>(&th);
+  return thread->getschedparam(policy, param);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_getschedparam.h b/libc/src/pthread/pthread_getschedparam.h
new file mode 100644
index 0000000000000..54c79811cc800
--- /dev/null
+++ b/libc/src/pthread/pthread_getschedparam.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 pthread_getschedparam.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETSCHEDPARAM_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETSCHEDPARAM_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_getschedparam(pthread_t thread, int *__restrict policy,
+                          struct sched_param *__restrict param);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETSCHEDPARAM_H
diff --git a/libc/src/pthread/pthread_setschedparam.cpp b/libc/src/pthread/pthread_setschedparam.cpp
new file mode 100644
index 0000000000000..c7b29848c58de
--- /dev/null
+++ b/libc/src/pthread/pthread_setschedparam.cpp
@@ -0,0 +1,36 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 the pthread_setschedparam function.
+///
+//===----------------------------------------------------------------------===//
+
+#include "pthread_setschedparam.h"
+
+#include "src/__support/common.h"
+#include "src/__support/macros/config.h"
+#include "src/__support/macros/null_check.h"
+#include "src/__support/threads/thread.h"
+
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+static_assert(sizeof(pthread_t) == sizeof(LIBC_NAMESPACE::Thread),
+              "Mismatch between pthread_t and internal Thread.");
+
+LLVM_LIBC_FUNCTION(int, pthread_setschedparam,
+                   (pthread_t th, int policy,
+                    const struct sched_param *param)) {
+  LIBC_CRASH_ON_NULLPTR(param);
+  auto *thread = reinterpret_cast<Thread *>(&th);
+  return thread->setschedparam(policy, param);
+}
+
+} // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_setschedparam.h b/libc/src/pthread/pthread_setschedparam.h
new file mode 100644
index 0000000000000..437d39f0fb522
--- /dev/null
+++ b/libc/src/pthread/pthread_setschedparam.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 pthread_setschedparam.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_SETSCHEDPARAM_H
+#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_SETSCHEDPARAM_H
+
+#include "src/__support/macros/config.h"
+#include <pthread.h>
+
+namespace LIBC_NAMESPACE_DECL {
+
+int pthread_setschedparam(pthread_t thread, int policy,
+                          const struct sched_param *param);
+
+} // namespace LIBC_NAMESPACE_DECL
+
+#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_SETSCHEDPARAM_H
diff --git a/libc/test/integration/src/pthread/CMakeLists.txt b/libc/test/integration/src/pthread/CMakeLists.txt
index 5afad2f674763..5c59c7fda5d29 100644
--- a/libc/test/integration/src/pthread/CMakeLists.txt
+++ b/libc/test/integration/src/pthread/CMakeLists.txt
@@ -291,3 +291,20 @@ add_integration_test(
     libc.src.__support.CPP.array
     libc.src.__support.CPP.new
 )
+
+add_integration_test(
+  pthread_setschedparam_test
+  SUITE
+    libc-pthread-integration-tests
+  SRCS
+    pthread_setschedparam_test.cpp
+  DEPENDS
+    libc.hdr.sched_macros
+    libc.include.pthread
+    libc.src.errno.errno
+    libc.src.pthread.pthread_create
+    libc.src.pthread.pthread_join
+    libc.src.pthread.pthread_self
+    libc.src.pthread.pthread_setschedparam
+    libc.src.pthread.pthread_getschedparam
+)
diff --git a/libc/test/integration/src/pthread/pthread_setschedparam_test.cpp b/libc/test/integration/src/pthread/pthread_setschedparam_test.cpp
new file mode 100644
index 0000000000000..555f8c54ca432
--- /dev/null
+++ b/libc/test/integration/src/pthread/pthread_setschedparam_test.cpp
@@ -0,0 +1,92 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+/// Integration tests for pthread_setschedparam and pthread_getschedparam.
+///
+//===----------------------------------------------------------------------===//
+
+#include "hdr/sched_macros.h"
+#include "src/pthread/pthread_create.h"
+#include "src/pthread/pthread_getschedparam.h"
+#include "src/pthread/pthread_join.h"
+#include "src/pthread/pthread_self.h"
+#include "src/pthread/pthread_setschedparam.h"
+#include "test/IntegrationTest/test.h"
+
+#include <errno.h>
+#include <pthread.h>
+
+static void *child_func(void *) { return nullptr; }
+
+TEST_MAIN() {
+  auto main_thread = LIBC_NAMESPACE::pthread_self();
+  struct sched_param param;
+  int policy;
+
+  // 1. Test getschedparam on self
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_getschedparam(main_thread, &policy, &param),
+            0);
+
+  // 2. Test setschedparam on self (Success)
+  param.sched_priority = 0;
+  ASSERT_EQ(
+      LIBC_NAMESPACE::pthread_setschedparam(main_thread, SCHED_OTHER, &param),
+      0);
+
+  // Verify it was set
+  int new_policy;
+  struct sched_param new_param;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_getschedparam(main_thread, &new_policy,
+                                                  &new_param),
+            0);
+  ASSERT_EQ(new_policy, SCHED_OTHER);
+  ASSERT_EQ(new_param.sched_priority, 0);
+
+  // 3. Test setschedparam on self (Failure - Invalid Policy)
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_setschedparam(main_thread, -1, &param),
+            EINVAL);
+
+  // 4. Test setschedparam on self (Failure - Invalid Priority for SCHED_OTHER)
+  param.sched_priority = 1; // Invalid for SCHED_OTHER
+  ASSERT_EQ(
+      LIBC_NAMESPACE::pthread_setschedparam(main_thread, SCHED_OTHER, &param),
+      EINVAL);
+  param.sched_priority = 0; // Reset
+
+  // 5. Test on Child Thread
+  pthread_t th;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_create(&th, nullptr, child_func, nullptr),
+            0);
+
+  // Get child's default sched param
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_getschedparam(th, &policy, &param), 0);
+
+  // Set child's sched param (Success)
+  param.sched_priority = 0;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_setschedparam(th, SCHED_OTHER, &param), 0);
+
+  // Verify child's sched param
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_getschedparam(th, &new_policy, &new_param),
+            0);
+  ASSERT_EQ(new_policy, SCHED_OTHER);
+  ASSERT_EQ(new_param.sched_priority, 0);
+
+  // Set child's sched param (Failure - Invalid Policy)
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_setschedparam(th, -1, &param), EINVAL);
+
+  // Set child's sched param (Failure - Invalid Priority)
+  param.sched_priority = 1;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_setschedparam(th, SCHED_OTHER, &param),
+            EINVAL);
+
+  void *retval;
+  ASSERT_EQ(LIBC_NAMESPACE::pthread_join(th, &retval), 0);
+
+  return 0;
+}

>From 85c06721421ec2bf17baf3a54b04c4c13bf62cc3 Mon Sep 17 00:00:00 2001
From: Jeff Bailey <jbailey at raspberryginger.com>
Date: Thu, 2 Jul 2026 23:21:09 +0100
Subject: [PATCH 2/2] [libc] Refactor internal thread scheduling APIs

Refactored the internal thread scheduling APIs to address PR comments:
* Use syscall_checked in scheduling syscall wrappers.
* Group scheduling policy and parameters into SchedParameters struct.
* Update Thread scheduling methods to use the new struct.
* Use ErrorOr for getschedparam to propagate errors.
* Remove redundant null checks in Thread implementation.

Assisted-by: Automated tooling, human reviewed.
---
 .../linux/syscall_wrappers/sched_getparam.h   |  7 ++-----
 .../syscall_wrappers/sched_getscheduler.h     |  7 ++-----
 .../syscall_wrappers/sched_setscheduler.h     |  7 ++-----
 libc/src/__support/threads/CMakeLists.txt     |  2 ++
 libc/src/__support/threads/linux/thread.cpp   | 18 +++++++++---------
 libc/src/__support/threads/thread.h           | 19 +++++++++++--------
 libc/src/pthread/pthread_getschedparam.cpp    |  8 +++++++-
 libc/src/pthread/pthread_setschedparam.cpp    |  2 +-
 8 files changed, 36 insertions(+), 34 deletions(-)

diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getparam.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getparam.h
index 7eab051c67972..e51c9f4ff3e32 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getparam.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getparam.h
@@ -16,7 +16,7 @@
 
 #include "hdr/types/pid_t.h"
 #include "hdr/types/struct_sched_param.h"
-#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked
 #include "src/__support/common.h"
 #include "src/__support/error_or.h"
 #include "src/__support/macros/config.h"
@@ -27,10 +27,7 @@ namespace LIBC_NAMESPACE_DECL {
 namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<int> sched_getparam(pid_t tid, struct sched_param *param) {
-  int ret = syscall_impl<int>(SYS_sched_getparam, tid, param);
-  if (ret < 0)
-    return Error(-ret);
-  return ret;
+  return syscall_checked<int>(SYS_sched_getparam, tid, param);
 }
 
 } // namespace linux_syscalls
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h
index 84ebf1aecc4ad..2db85d77be67b 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_getscheduler.h
@@ -15,7 +15,7 @@
 #define LLVM_LIBC_SRC___SUPPORT_OSUTIL_SYSCALL_WRAPPERS_SCHED_GETSCHEDULER_H
 
 #include "hdr/types/pid_t.h"
-#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked
 #include "src/__support/common.h"
 #include "src/__support/error_or.h"
 #include "src/__support/macros/config.h"
@@ -26,10 +26,7 @@ namespace LIBC_NAMESPACE_DECL {
 namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<int> sched_getscheduler(pid_t tid) {
-  int ret = syscall_impl<int>(SYS_sched_getscheduler, tid);
-  if (ret < 0)
-    return Error(-ret);
-  return ret;
+  return syscall_checked<int>(SYS_sched_getscheduler, tid);
 }
 
 } // namespace linux_syscalls
diff --git a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h
index 122f4c1e7c4ed..132d258f9680e 100644
--- a/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h
+++ b/libc/src/__support/OSUtil/linux/syscall_wrappers/sched_setscheduler.h
@@ -16,7 +16,7 @@
 
 #include "hdr/types/pid_t.h"
 #include "hdr/types/struct_sched_param.h"
-#include "src/__support/OSUtil/linux/syscall.h" // syscall_impl
+#include "src/__support/OSUtil/linux/syscall.h" // syscall_checked
 #include "src/__support/common.h"
 #include "src/__support/error_or.h"
 #include "src/__support/macros/config.h"
@@ -28,10 +28,7 @@ namespace linux_syscalls {
 
 LIBC_INLINE ErrorOr<int> sched_setscheduler(pid_t tid, int policy,
                                             const struct sched_param *param) {
-  int ret = syscall_impl<int>(SYS_sched_setscheduler, tid, policy, param);
-  if (ret < 0)
-    return Error(-ret);
-  return ret;
+  return syscall_checked<int>(SYS_sched_setscheduler, tid, policy, param);
 }
 
 } // namespace linux_syscalls
diff --git a/libc/src/__support/threads/CMakeLists.txt b/libc/src/__support/threads/CMakeLists.txt
index 0846a78bbf904..cc51b4f239b89 100644
--- a/libc/src/__support/threads/CMakeLists.txt
+++ b/libc/src/__support/threads/CMakeLists.txt
@@ -112,7 +112,9 @@ add_header_library(
     thread.h
   DEPENDS
     libc.hdr.stdint_proxy
+    libc.hdr.types.struct_sched_param
     libc.src.__support.common
+    libc.src.__support.error_or
     libc.src.__support.CPP.atomic
     libc.src.__support.CPP.optional
     libc.src.__support.CPP.string_view
diff --git a/libc/src/__support/threads/linux/thread.cpp b/libc/src/__support/threads/linux/thread.cpp
index 4d43f59f8ea9d..704916fff95e6 100644
--- a/libc/src/__support/threads/linux/thread.cpp
+++ b/libc/src/__support/threads/linux/thread.cpp
@@ -493,25 +493,25 @@ int Thread::get_name(cpp::StringStream &name) const {
   return 0;
 }
 
-int Thread::setschedparam(int policy, const struct sched_param *param) {
-  auto result = linux_syscalls::sched_setscheduler(attrib->tid, policy, param);
+int Thread::setschedparam(SchedParameters params) {
+  auto result = linux_syscalls::sched_setscheduler(attrib->tid, params.policy,
+                                                   &params.param);
   if (!result.has_value())
     return result.error();
   return 0;
 }
 
-int Thread::getschedparam(int *policy, struct sched_param *param) const {
+ErrorOr<SchedParameters> Thread::getschedparam() const {
   auto pol_result = linux_syscalls::sched_getscheduler(attrib->tid);
   if (!pol_result.has_value())
-    return pol_result.error();
+    return Error(pol_result.error());
 
-  auto param_result = linux_syscalls::sched_getparam(attrib->tid, param);
+  struct sched_param param;
+  auto param_result = linux_syscalls::sched_getparam(attrib->tid, &param);
   if (!param_result.has_value())
-    return param_result.error();
+    return Error(param_result.error());
 
-  if (policy != nullptr)
-    *policy = pol_result.value();
-  return 0;
+  return SchedParameters{pol_result.value(), param};
 }
 
 void thread_exit(ThreadReturnValue retval, ThreadStyle style) {
diff --git a/libc/src/__support/threads/thread.h b/libc/src/__support/threads/thread.h
index 9c66db5a15598..94359cd626cd9 100644
--- a/libc/src/__support/threads/thread.h
+++ b/libc/src/__support/threads/thread.h
@@ -23,10 +23,16 @@
 
 #include <stddef.h> // For size_t
 
-struct sched_param;
+#include "hdr/types/struct_sched_param.h"
+#include "src/__support/error_or.h"
 
 namespace LIBC_NAMESPACE_DECL {
 
+struct SchedParameters {
+  int policy;
+  struct sched_param param;
+};
+
 using ThreadRunnerPosix = void *(void *);
 using ThreadRunnerStdc = int(void *);
 
@@ -235,17 +241,14 @@ struct Thread {
 
   /// Set the scheduling policy and parameters of the thread.
   ///
-  /// \param policy The new scheduling policy.
-  /// \param param The new scheduling parameters.
+  /// \param params The new scheduling policy and parameters.
   /// \return 0 on success, or an error number on failure.
-  int setschedparam(int policy, const struct sched_param *param);
+  int setschedparam(SchedParameters params);
 
   /// Get the scheduling policy and parameters of the thread.
   ///
-  /// \param policy Pointer to store the retrieved policy (can be null).
-  /// \param param Pointer to store the retrieved parameters.
-  /// \return 0 on success, or an error number on failure.
-  int getschedparam(int *policy, struct sched_param *param) const;
+  /// \return SchedParameters on success, or an error number on failure.
+  ErrorOr<SchedParameters> getschedparam() const;
 };
 
 LIBC_INLINE_VAR LIBC_THREAD_LOCAL Thread self;
diff --git a/libc/src/pthread/pthread_getschedparam.cpp b/libc/src/pthread/pthread_getschedparam.cpp
index ade50a11af263..31f6a162022d0 100644
--- a/libc/src/pthread/pthread_getschedparam.cpp
+++ b/libc/src/pthread/pthread_getschedparam.cpp
@@ -31,7 +31,13 @@ LLVM_LIBC_FUNCTION(int, pthread_getschedparam,
   LIBC_CRASH_ON_NULLPTR(policy);
   LIBC_CRASH_ON_NULLPTR(param);
   auto *thread = reinterpret_cast<Thread *>(&th);
-  return thread->getschedparam(policy, param);
+  auto result = thread->getschedparam();
+  if (!result.has_value())
+    return result.error();
+
+  *policy = result.value().policy;
+  *param = result.value().param;
+  return 0;
 }
 
 } // namespace LIBC_NAMESPACE_DECL
diff --git a/libc/src/pthread/pthread_setschedparam.cpp b/libc/src/pthread/pthread_setschedparam.cpp
index c7b29848c58de..9d1b5a5215ecf 100644
--- a/libc/src/pthread/pthread_setschedparam.cpp
+++ b/libc/src/pthread/pthread_setschedparam.cpp
@@ -30,7 +30,7 @@ LLVM_LIBC_FUNCTION(int, pthread_setschedparam,
                     const struct sched_param *param)) {
   LIBC_CRASH_ON_NULLPTR(param);
   auto *thread = reinterpret_cast<Thread *>(&th);
-  return thread->setschedparam(policy, param);
+  return thread->setschedparam({policy, *param});
 }
 
 } // namespace LIBC_NAMESPACE_DECL



More information about the libc-commits mailing list