diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -26,8 +26,15 @@ libc.src.fcntl.openat # sched.h entrypoints + libc.src.sched.sched_get_priority_max + libc.src.sched.sched_get_priority_min libc.src.sched.sched_getaffinity + libc.src.sched.sched_getparam + libc.src.sched.sched_getscheduler + libc.src.sched.sched_rr_get_interval libc.src.sched.sched_setaffinity + libc.src.sched.sched_setparam + libc.src.sched.sched_setscheduler libc.src.sched.sched_yield # string.h entrypoints diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -103,7 +103,15 @@ } def SchedAPI : PublicAPI<"sched.h"> { - let Types = ["pid_t", "size_t", "cpu_set_t"]; + let Types = [ + "pid_t", + "size_t", + "cpu_set_t", + "struct sched_param", + // Needed according to posix standard + "time_t", + "struct timespec", + ]; } def SysMManAPI : PublicAPI<"sys/mman.h"> { diff --git a/libc/config/linux/riscv64/entrypoints.txt b/libc/config/linux/riscv64/entrypoints.txt --- a/libc/config/linux/riscv64/entrypoints.txt +++ b/libc/config/linux/riscv64/entrypoints.txt @@ -26,8 +26,15 @@ libc.src.fcntl.openat # sched.h entrypoints + libc.src.sched.sched_get_priority_max + libc.src.sched.sched_get_priority_min libc.src.sched.sched_getaffinity + libc.src.sched.sched_getparam + libc.src.sched.sched_getscheduler + libc.src.sched.sched_rr_get_interval libc.src.sched.sched_setaffinity + libc.src.sched.sched_setparam + libc.src.sched.sched_setscheduler libc.src.sched.sched_yield # string.h entrypoints diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -26,8 +26,15 @@ libc.src.fcntl.openat # sched.h entrypoints + libc.src.sched.sched_get_priority_max + libc.src.sched.sched_get_priority_min libc.src.sched.sched_getaffinity + libc.src.sched.sched_getparam + libc.src.sched.sched_getscheduler + libc.src.sched.sched_rr_get_interval libc.src.sched.sched_setaffinity + libc.src.sched.sched_setparam + libc.src.sched.sched_setscheduler libc.src.sched.sched_yield # string.h entrypoints diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -248,9 +248,13 @@ DEPENDS .llvm_libc_common_h .llvm-libc-macros.sched_macros + .llvm-libc-types.cpu_set_t .llvm-libc-types.pid_t .llvm-libc-types.size_t - .llvm-libc-types.cpu_set_t + .llvm-libc-types.struct_sched_param + # Needed according to posix standard + .llvm-libc-types.time_t + .llvm-libc-types.struct_timespec ) add_gen_header( diff --git a/libc/include/llvm-libc-macros/linux/sched-macros.h b/libc/include/llvm-libc-macros/linux/sched-macros.h --- a/libc/include/llvm-libc-macros/linux/sched-macros.h +++ b/libc/include/llvm-libc-macros/linux/sched-macros.h @@ -9,6 +9,20 @@ #ifndef __LLVM_LIBC_MACROS_LINUX_SCHED_MACROS_H #define __LLVM_LIBC_MACROS_LINUX_SCHED_MACROS_H +// Definitions of SCHED_* macros must match was linux as at: +// https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/sched.h + +// Posix required +#define SCHED_OTHER 0 +#define SCHED_FIFO 1 +#define SCHED_RR 2 + +// Linux extentions +#define SCHED_BATCH 3 +#define SCHED_ISO 4 // Not yet implemented, reserved. +#define SCHED_IDLE 5 +#define SCHED_DEADLINE 6 + #define CPU_COUNT_S(setsize, set) __sched_getcpucount(setsize, set) #define CPU_COUNT(set) CPU_COUNT_S(sizeof(cpu_set_t), set) diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -60,6 +60,7 @@ add_header(struct_rlimit HDR struct_rlimit.h DEPENDS .rlim_t) add_header(struct_rusage HDR struct_rusage.h DEPENDS .struct_timeval) add_header(struct_dirent HDR struct_dirent.h DEPENDS .ino_t .off_t) +add_header(struct_sched_param HDR struct_sched_param.h) add_header(union_sigval HDR union_sigval.h) add_header(siginfo_t HDR siginfo_t.h DEPENDS .union_sigval .pid_t .uid_t) add_header(sig_atomic_t HDR sig_atomic_t.h) diff --git a/libc/include/llvm-libc-types/struct_sched_param.h b/libc/include/llvm-libc-types/struct_sched_param.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-types/struct_sched_param.h @@ -0,0 +1,21 @@ +//===-- Definition of type struct sched_param -----------------------------===// +// +// 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_TYPES_STRUCT_SCHED_PARAM_H__ +#define __LLVM_LIBC_TYPES_STRUCT_SCHED_PARAM_H__ + +#include +#include +#include + +struct sched_param { + // Process or thread execution scheduling priority. + int sched_priority; +}; + +#endif // __LLVM_LIBC_TYPES_STRUCT_SCHED_PARAM_H__ diff --git a/libc/spec/linux.td b/libc/spec/linux.td --- a/libc/spec/linux.td +++ b/libc/spec/linux.td @@ -58,6 +58,22 @@ ] >; + HeaderSpec Sched = HeaderSpec< + "sched.h", + [ + Macro<"SCHED_OTHER">, + Macro<"SCHED_FIFO">, + Macro<"SCHED_RR">, + Macro<"SCHED_BATCH">, + Macro<"SCHED_ISO">, + Macro<"SCHED_IDLE">, + Macro<"SCHED_DEADLINE">, + ], + [], // Types + [], // Enumerations + [] // Functions + >; + HeaderSpec SysMMan = HeaderSpec< "sys/mman.h", [Macro<"MAP_ANONYMOUS">] diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -45,6 +45,10 @@ def StructTimeSpec : NamedType<"struct timespec">; def StructTimeSpecPtr : PtrType; +def StructSchedParam : NamedType<"struct sched_param">; +def StructSchedParamPtr : PtrType; +def ConstStructSchedParamPtr : ConstType; + def ExecArgvT : NamedType<"__exec_argv_t">; def ExecEnvpT : NamedType<"__exec_envp_t">; @@ -633,13 +637,54 @@ HeaderSpec Sched = HeaderSpec< "sched.h", [], // Macros - [PidT, SizeTType, CpuSetT], // Types + [PidT, TimeTType, StructTimeSpec, StructSchedParam], // Types [], // Enumerations [ FunctionSpec< "sched_yield", RetValSpec, - [] + [ArgSpec] + >, + FunctionSpec< + "sched_setparam", + RetValSpec, + [ArgSpec, ArgSpec] + >, + + FunctionSpec< + "sched_getparam", + RetValSpec, + [ArgSpec, ArgSpec] + >, + + FunctionSpec< + "sched_setscheduler", + RetValSpec, + [ArgSpec] + >, + + FunctionSpec< + "sched_getscheduler", + RetValSpec, + [ArgSpec, ArgSpec, ArgSpec] + >, + + FunctionSpec< + "sched_get_priority_min", + RetValSpec, + [ArgSpec] + >, + + FunctionSpec< + "sched_get_priority_max", + RetValSpec, + [ArgSpec] + >, + + FunctionSpec< + "sched_rr_get_interval", + RetValSpec, + [ArgSpec, ArgSpec] >, ] >; diff --git a/libc/src/sched/CMakeLists.txt b/libc/src/sched/CMakeLists.txt --- a/libc/src/sched/CMakeLists.txt +++ b/libc/src/sched/CMakeLists.txt @@ -23,6 +23,55 @@ .${LIBC_TARGET_OS}.sched_yield ) +add_entrypoint_object( + sched_setparam + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.sched_setparam +) + +add_entrypoint_object( + sched_getparam + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.sched_getparam +) + +add_entrypoint_object( + sched_setscheduler + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.sched_setscheduler +) + +add_entrypoint_object( + sched_getscheduler + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.sched_getscheduler +) + +add_entrypoint_object( + sched_get_priority_min + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.sched_get_priority_min +) + +add_entrypoint_object( + sched_get_priority_max + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.sched_get_priority_max +) + +add_entrypoint_object( + sched_rr_get_interval + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.sched_rr_get_interval +) + add_entrypoint_object( __sched_getcpucount ALIAS diff --git a/libc/src/sched/linux/CMakeLists.txt b/libc/src/sched/linux/CMakeLists.txt --- a/libc/src/sched/linux/CMakeLists.txt +++ b/libc/src/sched/linux/CMakeLists.txt @@ -43,3 +43,87 @@ libc.src.__support.OSUtil.osutil libc.src.errno.errno ) + +add_entrypoint_object( + sched_setparam + SRCS + sched_setparam.cpp + HDRS + ../sched_setparam.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + sched_getparam + SRCS + sched_getparam.cpp + HDRS + ../sched_getparam.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + sched_setscheduler + SRCS + sched_setscheduler.cpp + HDRS + ../sched_setscheduler.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + sched_getscheduler + SRCS + sched_getscheduler.cpp + HDRS + ../sched_getscheduler.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + sched_get_priority_min + SRCS + sched_get_priority_min.cpp + HDRS + ../sched_get_priority_min.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + sched_get_priority_max + SRCS + sched_get_priority_max.cpp + HDRS + ../sched_get_priority_max.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) + +add_entrypoint_object( + sched_rr_get_interval + SRCS + sched_rr_get_interval.cpp + HDRS + ../sched_rr_get_interval.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil + libc.src.errno.errno +) diff --git a/libc/src/sched/linux/sched_get_priority_max.cpp b/libc/src/sched/linux/sched_get_priority_max.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sched/linux/sched_get_priority_max.cpp @@ -0,0 +1,28 @@ +//===-- Implementation of sched_get_priority_max --------------------------===// +// +// 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_get_priority_max.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" + +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, sched_get_priority_max, (int policy)) { + long ret = __llvm_libc::syscall_impl(SYS_sched_get_priority_min, policy); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return ret; +} + +} // namespace __llvm_libc diff --git a/libc/src/sched/linux/sched_get_priority_min.cpp b/libc/src/sched/linux/sched_get_priority_min.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sched/linux/sched_get_priority_min.cpp @@ -0,0 +1,28 @@ +//===-- Implementation of sched_get_priority_min --------------------------===// +// +// 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_get_priority_min.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" + +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, sched_get_priority_min, (int policy)) { + long ret = __llvm_libc::syscall_impl(SYS_sched_get_priority_min, policy); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return ret; +} + +} // namespace __llvm_libc diff --git a/libc/src/sched/linux/sched_getparam.cpp b/libc/src/sched/linux/sched_getparam.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sched/linux/sched_getparam.cpp @@ -0,0 +1,29 @@ +//===-- Implementation of sched_getparam ----------------------------------===// +// +// 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_getparam.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" + +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, sched_getparam, + (pid_t tid, struct sched_param *param)) { + long ret = __llvm_libc::syscall_impl(SYS_sched_getparam, tid, param); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/sched/linux/sched_getscheduler.cpp b/libc/src/sched/linux/sched_getscheduler.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sched/linux/sched_getscheduler.cpp @@ -0,0 +1,28 @@ +//===-- Implementation of sched_getscheduler ------------------------------===// +// +// 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_getscheduler.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" + +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, sched_getscheduler, (pid_t tid)) { + long ret = __llvm_libc::syscall_impl(SYS_sched_getscheduler, tid); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/sched/linux/sched_rr_get_interval.cpp b/libc/src/sched/linux/sched_rr_get_interval.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sched/linux/sched_rr_get_interval.cpp @@ -0,0 +1,29 @@ +//===-- Implementation of sched_rr_get_interval ---------------------------===// +// +// 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_rr_get_interval.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" + +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, sched_rr_get_interval, + (pid_t tid, struct timespec *tp)) { + long ret = __llvm_libc::syscall_impl(SYS_sched_rr_get_interval, tid, tp); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/sched/linux/sched_setparam.cpp b/libc/src/sched/linux/sched_setparam.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sched/linux/sched_setparam.cpp @@ -0,0 +1,29 @@ +//===-- Implementation of sched_setparam ----------------------------------===// +// +// 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_setparam.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" + +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, sched_setparam, + (pid_t tid, const struct sched_param *param)) { + long ret = __llvm_libc::syscall_impl(SYS_sched_setparam, tid, param); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/sched/linux/sched_setscheduler.cpp b/libc/src/sched/linux/sched_setscheduler.cpp new file mode 100644 --- /dev/null +++ b/libc/src/sched/linux/sched_setscheduler.cpp @@ -0,0 +1,30 @@ +//===-- Implementation of sched_setscheduler ------------------------------===// +// +// 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_setscheduler.h" + +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/__support/common.h" +#include "src/errno/libc_errno.h" + +#include // For syscall numbers. + +namespace __llvm_libc { + +LLVM_LIBC_FUNCTION(int, sched_setscheduler, + (pid_t tid, int policy, const struct sched_param *param)) { + long ret = + __llvm_libc::syscall_impl(SYS_sched_setscheduler, tid, policy, param); + if (ret < 0) { + libc_errno = -ret; + return -1; + } + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/sched/sched_get_priority_max.h b/libc/src/sched/sched_get_priority_max.h new file mode 100644 --- /dev/null +++ b/libc/src/sched/sched_get_priority_max.h @@ -0,0 +1,18 @@ +//===-- Implementation header for sched_get_priority_max ---------*- 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_GET_PRIORITY_MAX_H +#define LLVM_LIBC_SRC_SCHED_SCHED_GET_PRIORITY_MAX_H + +namespace __llvm_libc { + +int sched_get_priority_max(int policy); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SCHED_SCHED_GET_PRIORITY_MAX_H diff --git a/libc/src/sched/sched_get_priority_min.h b/libc/src/sched/sched_get_priority_min.h new file mode 100644 --- /dev/null +++ b/libc/src/sched/sched_get_priority_min.h @@ -0,0 +1,18 @@ +//===-- Implementation header for sched_get_priority_min ---------*- 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_GET_PRIORITY_MIN_H +#define LLVM_LIBC_SRC_SCHED_SCHED_GET_PRIORITY_MIN_H + +namespace __llvm_libc { + +int sched_get_priority_min(int policy); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SCHED_SCHED_GET_PRIORITY_MIN_H diff --git a/libc/src/sched/sched_getparam.h b/libc/src/sched/sched_getparam.h new file mode 100644 --- /dev/null +++ b/libc/src/sched/sched_getparam.h @@ -0,0 +1,20 @@ +//===-- Implementation header for sched_getparam ----------------*- 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_GETPARAM_H +#define LLVM_LIBC_SRC_SCHED_SCHED_GETPARAM_H + +#include + +namespace __llvm_libc { + +int sched_getparam(pid_t tid, struct sched_param *param); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SCHED_SCHED_GETPARAM_H diff --git a/libc/src/sched/sched_getscheduler.h b/libc/src/sched/sched_getscheduler.h new file mode 100644 --- /dev/null +++ b/libc/src/sched/sched_getscheduler.h @@ -0,0 +1,20 @@ +//===-- Implementation header for sched_getscheduler -------------*- 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_GETSCHEDULER_H +#define LLVM_LIBC_SRC_SCHED_SCHED_GETSCHEDULER_H + +#include + +namespace __llvm_libc { + +int sched_getscheduler(pid_t tid); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SCHED_SCHED_GETSCHEDULER_H diff --git a/libc/src/sched/sched_rr_get_interval.h b/libc/src/sched/sched_rr_get_interval.h new file mode 100644 --- /dev/null +++ b/libc/src/sched/sched_rr_get_interval.h @@ -0,0 +1,20 @@ +//===-- Implementation header for sched_rr_get_interval ----------*- 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_RR_GET_INTERVAL_H +#define LLVM_LIBC_SRC_SCHED_SCHED_RR_GET_INTERVAL_H + +#include + +namespace __llvm_libc { + +int sched_rr_get_interval(pid_t tid, struct timespec *tp); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SCHED_SCHED_RR_GET_INTERVAL_H diff --git a/libc/src/sched/sched_setparam.h b/libc/src/sched/sched_setparam.h new file mode 100644 --- /dev/null +++ b/libc/src/sched/sched_setparam.h @@ -0,0 +1,20 @@ +//===-- Implementation header for sched_setparam ----------------*- 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_SETPARAM_H +#define LLVM_LIBC_SRC_SCHED_SCHED_SETPARAM_H + +#include + +namespace __llvm_libc { + +int sched_setparam(pid_t tid, const struct sched_param *param); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SCHED_SCHED_SETPARAM_H diff --git a/libc/src/sched/sched_setscheduler.h b/libc/src/sched/sched_setscheduler.h new file mode 100644 --- /dev/null +++ b/libc/src/sched/sched_setscheduler.h @@ -0,0 +1,20 @@ +//===-- Implementation header for sched_setscheduler -------------*- 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_SETSCHEDULER_H +#define LLVM_LIBC_SRC_SCHED_SCHED_SETSCHEDULER_H + +#include + +namespace __llvm_libc { + +int sched_setscheduler(pid_t tid, int policy, const struct sched_param *param); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SCHED_SCHED_SETSCHEDULER_H diff --git a/libc/test/src/sched/CMakeLists.txt b/libc/test/src/sched/CMakeLists.txt --- a/libc/test/src/sched/CMakeLists.txt +++ b/libc/test/src/sched/CMakeLists.txt @@ -27,6 +27,53 @@ libc.src.sched.sched_yield ) +add_libc_unittest( + get_priority_test + SUITE + libc_sched_unittests + SRCS + get_priority_test.cpp + DEPENDS + libc.include.sched + libc.src.errno.errno + libc.src.sched.sched_get_priority_min + libc.src.sched.sched_get_priority_max +) + +add_libc_unittest( + scheduler_test + SUITE + libc_sched_unittests + SRCS + param_and_scheduler_test.cpp + DEPENDS + libc.include.sched + libc.src.errno.errno + libc.src.sched.sched_getscheduler + libc.src.sched.sched_setscheduler + libc.src.sched.sched_getparam + libc.src.sched.sched_setparam + libc.src.sched.sched_get_priority_min + libc.src.sched.sched_get_priority_max + libc.src.unistd.getuid +) + +add_libc_unittest( + sched_rr_get_interval_test + SUITE + libc_sched_unittests + SRCS + sched_rr_get_interval_test.cpp + DEPENDS + libc.include.sched + libc.src.errno.errno + libc.src.sched.sched_getscheduler + libc.src.sched.sched_setscheduler + libc.src.sched.sched_get_priority_min + libc.src.sched.sched_rr_get_interval + libc.src.unistd.getuid +) + add_libc_unittest( cpu_count_test SUITE diff --git a/libc/test/src/sched/get_priority_test.cpp b/libc/test/src/sched/get_priority_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/sched/get_priority_test.cpp @@ -0,0 +1,108 @@ +//===-- Unittests for sched_get_priority_{min,max} ------------------------===// +// +// 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/errno/libc_errno.h" +#include "src/sched/sched_get_priority_max.h" +#include "src/sched/sched_get_priority_min.h" +#include "test/UnitTest/Test.h" + +#include + +TEST(LlvmLibcSchedGetPriorityTest, HandleBadPolicyTest) { + + // Test arbitrary values for which there is no policy. + { + int policy = -1; + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_EQ(max_priority, -1); + ASSERT_EQ(libc_errno, EINVAL); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_EQ(min_priority, -1); + ASSERT_EQ(libc_errno, EINVAL); + } + + { + int policy = 30; + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_EQ(max_priority, -1); + ASSERT_EQ(libc_errno, EINVAL); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_EQ(min_priority, -1); + ASSERT_EQ(libc_errno, EINVAL); + } + + { + int policy = 80; + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_EQ(max_priority, -1); + ASSERT_EQ(libc_errno, EINVAL); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_EQ(min_priority, -1); + ASSERT_EQ(libc_errno, EINVAL); + } + + { + int policy = 110; + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_EQ(max_priority, -1); + ASSERT_EQ(libc_errno, EINVAL); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_EQ(min_priority, -1); + ASSERT_EQ(libc_errno, EINVAL); + } +} + +TEST(LlvmLibcSchedGetPriorityTest, SmokeTest) { + libc_errno = 0; + + // We Test: + // SCHED_OTHER, SCHED_FIFO, SCHED_RR + // Linux specific test could also include: + // SCHED_BATCH, SCHED_ISO, SCHED_IDLE, SCHED_DEADLINE + { + int policy = SCHED_OTHER; + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_GE(max_priority, 0); + ASSERT_EQ(libc_errno, 0); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_GE(min_priority, 0); + ASSERT_EQ(libc_errno, 0); + + ASSERT_LE(max_priority, 99); + ASSERT_GE(min_priority, 0); + ASSERT_GE(max_priority, min_priority); + } + + { + int policy = SCHED_FIFO; + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_GE(max_priority, 0); + ASSERT_EQ(libc_errno, 0); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_GE(min_priority, 0); + ASSERT_EQ(libc_errno, 0); + + ASSERT_LE(max_priority, 99); + ASSERT_GE(min_priority, 0); + ASSERT_GE(max_priority, min_priority); + } + + { + int policy = SCHED_RR; + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_GE(max_priority, 0); + ASSERT_EQ(libc_errno, 0); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_GE(min_priority, 0); + ASSERT_EQ(libc_errno, 0); + + ASSERT_LE(max_priority, 99); + ASSERT_GE(min_priority, 0); + ASSERT_GE(max_priority, min_priority); + } +} diff --git a/libc/test/src/sched/param_and_scheduler_test.cpp b/libc/test/src/sched/param_and_scheduler_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/sched/param_and_scheduler_test.cpp @@ -0,0 +1,353 @@ +//===-- Unittests for sched_{set,get}{scheduler,param} --------------------===// +// +// 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/errno/libc_errno.h" +#include "src/sched/sched_get_priority_max.h" +#include "src/sched/sched_get_priority_min.h" +#include "src/sched/sched_getparam.h" +#include "src/sched/sched_getscheduler.h" +#include "src/sched/sched_setparam.h" +#include "src/sched/sched_setscheduler.h" +#include "src/unistd/getuid.h" +#include "test/UnitTest/Test.h" + +#include + +// We Test: +// SCHED_OTHER, SCHED_FIFO, SCHED_RR +// +// TODO: Missing two tests. +// 1) Missing permissions -> EPERM. Maybe doable by finding +// another pid that exists and changing its policy, but that +// seems risky. Maybe something with fork/clone would work. +// +// 2) Unkown pid -> ESRCH. Probably safe to choose a large range +// number or scanning current pids and getting one that doesn't +// exist, but again seems like it may risk actually changing +// sched policy on a running task. +// +// Linux specific test could also include: +// SCHED_BATCH, SCHED_ISO, SCHED_IDLE, SCHED_DEADLINE + +TEST(LlvmLibcSchedParamAndSchedulerTest, SchedOtherTest) { + libc_errno = 0; + + int policy = SCHED_OTHER; + bool can_set = true; + + int init_policy = __llvm_libc::sched_getscheduler(0); + ASSERT_GE(init_policy, 0); + ASSERT_EQ(libc_errno, 0); + + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_GE(max_priority, 0); + ASSERT_EQ(libc_errno, 0); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_GE(min_priority, 0); + ASSERT_EQ(libc_errno, 0); + + struct sched_param param = {min_priority}; + + // Negative pid + ASSERT_EQ(__llvm_libc::sched_setscheduler(-1, policy, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getscheduler(-1), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Invalid Policy + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy | 128, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Out of bounds priority + param.sched_priority = min_priority - 1; + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + param.sched_priority = max_priority + 1; + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), -1); + // A bit hard to test as depending if we are root or not we can run into + // different issues. + ASSERT_TRUE(libc_errno == EINVAL || libc_errno == EPERM); + libc_errno = 0; + + // Some sched policies require permissions, so skip + param.sched_priority = min_priority; + // Success / missing permissions. + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), + can_set ? 0 : -1); + ASSERT_TRUE(can_set ? (libc_errno == 0) + : (libc_errno == EINVAL || libc_errno == EPERM)); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getscheduler(0), can_set ? policy : init_policy); + ASSERT_EQ(libc_errno, 0); + + // Out of bounds priority + param.sched_priority = -1; + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + param.sched_priority = max_priority + 1; + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + for (int priority = min_priority; priority <= max_priority; ++priority) { + ASSERT_EQ(__llvm_libc::sched_getparam(0, ¶m), 0); + ASSERT_EQ(libc_errno, 0); + int init_priority = param.sched_priority; + + param.sched_priority = priority; + + // Negative pid + ASSERT_EQ(__llvm_libc::sched_setparam(-1, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getparam(-1, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Success / missing permissions + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), can_set ? 0 : -1); + ASSERT_TRUE(can_set ? (libc_errno == 0) + : (libc_errno == EINVAL || libc_errno == EPERM)); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getparam(0, ¶m), 0); + ASSERT_EQ(libc_errno, 0); + + ASSERT_EQ(param.sched_priority, can_set ? priority : init_priority); + } + // Null test + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, nullptr), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; +} + +TEST(LlvmLibcSchedParamAndSchedulerTest, SchedFIFOTest) { + libc_errno = 0; + + int policy = SCHED_FIFO; + bool can_set = __llvm_libc::getuid() == 0; + + int init_policy = __llvm_libc::sched_getscheduler(0); + ASSERT_GE(init_policy, 0); + ASSERT_EQ(libc_errno, 0); + + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_GE(max_priority, 0); + ASSERT_EQ(libc_errno, 0); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_GE(min_priority, 0); + ASSERT_EQ(libc_errno, 0); + + struct sched_param param = {min_priority}; + + // Negative pid + ASSERT_EQ(__llvm_libc::sched_setscheduler(-1, policy, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getscheduler(-1), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Invalid Policy + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy | 128, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Out of bounds priority + param.sched_priority = min_priority - 1; + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + param.sched_priority = max_priority + 1; + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), -1); + // A bit hard to test as depending if we are root or not we can run into + // different issues. + ASSERT_TRUE(libc_errno == EINVAL || libc_errno == EPERM); + libc_errno = 0; + + // Some sched policies require permissions, so skip + param.sched_priority = min_priority; + // Success / missing permissions. + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), + can_set ? 0 : -1); + ASSERT_TRUE(can_set ? (libc_errno == 0) + : (libc_errno == EINVAL || libc_errno == EPERM)); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getscheduler(0), can_set ? policy : init_policy); + ASSERT_EQ(libc_errno, 0); + + // Out of bounds priority + param.sched_priority = -1; + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + param.sched_priority = max_priority + 1; + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + for (int priority = min_priority; priority <= max_priority; ++priority) { + ASSERT_EQ(__llvm_libc::sched_getparam(0, ¶m), 0); + ASSERT_EQ(libc_errno, 0); + int init_priority = param.sched_priority; + + param.sched_priority = priority; + + // Negative pid + ASSERT_EQ(__llvm_libc::sched_setparam(-1, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getparam(-1, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Success / missing permissions + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), can_set ? 0 : -1); + ASSERT_TRUE(can_set ? (libc_errno == 0) + : (libc_errno == EINVAL || libc_errno == EPERM)); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getparam(0, ¶m), 0); + ASSERT_EQ(libc_errno, 0); + + ASSERT_EQ(param.sched_priority, can_set ? priority : init_priority); + } + // Null test + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, nullptr), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; +} + +TEST(LlvmLibcSchedParamAndSchedulerTest, SchedRRTest) { + libc_errno = 0; + + int policy = SCHED_RR; + bool can_set = __llvm_libc::getuid() == 0; + + int init_policy = __llvm_libc::sched_getscheduler(0); + ASSERT_GE(init_policy, 0); + ASSERT_EQ(libc_errno, 0); + + int max_priority = __llvm_libc::sched_get_priority_max(policy); + ASSERT_GE(max_priority, 0); + ASSERT_EQ(libc_errno, 0); + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_GE(min_priority, 0); + ASSERT_EQ(libc_errno, 0); + + struct sched_param param = {min_priority}; + + // Negative pid + ASSERT_EQ(__llvm_libc::sched_setscheduler(-1, policy, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getscheduler(-1), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Invalid Policy + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy | 128, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Out of bounds priority + param.sched_priority = min_priority - 1; + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + param.sched_priority = max_priority + 1; + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), -1); + // A bit hard to test as depending if we are root or not we can run into + // different issues. + ASSERT_TRUE(libc_errno == EINVAL || libc_errno == EPERM); + libc_errno = 0; + + // Some sched policies require permissions, so skip + param.sched_priority = min_priority; + // Success / missing permissions. + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), + can_set ? 0 : -1); + ASSERT_TRUE(can_set ? (libc_errno == 0) + : (libc_errno == EINVAL || libc_errno == EPERM)); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getscheduler(0), can_set ? policy : init_policy); + ASSERT_EQ(libc_errno, 0); + + // Out of bounds priority + param.sched_priority = -1; + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + param.sched_priority = max_priority + 1; + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + for (int priority = min_priority; priority <= max_priority; ++priority) { + ASSERT_EQ(__llvm_libc::sched_getparam(0, ¶m), 0); + ASSERT_EQ(libc_errno, 0); + int init_priority = param.sched_priority; + + param.sched_priority = priority; + + // Negative pid + ASSERT_EQ(__llvm_libc::sched_setparam(-1, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getparam(-1, ¶m), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + // Success / missing permissions + ASSERT_EQ(__llvm_libc::sched_setparam(0, ¶m), can_set ? 0 : -1); + ASSERT_TRUE(can_set ? (libc_errno == 0) + : (libc_errno == EINVAL || libc_errno == EPERM)); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getparam(0, ¶m), 0); + ASSERT_EQ(libc_errno, 0); + + ASSERT_EQ(param.sched_priority, can_set ? priority : init_priority); + } + // Null test + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, nullptr), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; +} + +TEST(LlvmLibcSchedParamAndSchedulerTest, NullParamTest) { + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_setparam(0, nullptr), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + + ASSERT_EQ(__llvm_libc::sched_getparam(0, nullptr), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; +} diff --git a/libc/test/src/sched/sched_rr_get_interval_test.cpp b/libc/test/src/sched/sched_rr_get_interval_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/sched/sched_rr_get_interval_test.cpp @@ -0,0 +1,74 @@ +//===-- Unittests for sched_rr_get_interval -------------------------------===// +// +// 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/errno/libc_errno.h" +#include "src/sched/sched_get_priority_min.h" +#include "src/sched/sched_getscheduler.h" +#include "src/sched/sched_rr_get_interval.h" +#include "src/sched/sched_setscheduler.h" +#include "src/unistd/getuid.h" +#include "test/UnitTest/Test.h" + +#include + +TEST(LlvmLibcSchedRRGetIntervalTest, SmokeTest) { + libc_errno = 0; + auto SetSched = [&](int policy) { + int min_priority = __llvm_libc::sched_get_priority_min(policy); + ASSERT_GE(min_priority, 0); + ASSERT_EQ(libc_errno, 0); + struct sched_param param; + param.sched_priority = min_priority; + ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, ¶m), 0); + ASSERT_EQ(libc_errno, 0); + }; + + auto TimespecToNs = [](struct timespec t) { + return t.tv_sec * 1000UL * 1000UL * 1000UL + t.tv_nsec; + }; + + struct timespec ts; + + // We can only set SCHED_RR with CAP_SYS_ADMIN + if (__llvm_libc::getuid() == 0) + SetSched(SCHED_RR); + + int cur_policy = __llvm_libc::sched_getscheduler(0); + ASSERT_GE(cur_policy, 0); + ASSERT_EQ(libc_errno, 0); + + // We can actually run meaningful tests. + if (cur_policy == SCHED_RR) { + // Success + ASSERT_EQ(__llvm_libc::sched_rr_get_interval(0, &ts), 0); + ASSERT_EQ(libc_errno, 0); + + // Check that numbers make sense (liberal bound of 10ns - 30sec) + ASSERT_GT(TimespecToNs(ts), 10UL); + ASSERT_LT(TimespecToNs(ts), 30UL * 1000UL * 1000UL * 1000UL); + + // Null timespec + ASSERT_EQ(__llvm_libc::sched_rr_get_interval(0, nullptr), -1); + ASSERT_EQ(libc_errno, EFAULT); + libc_errno = 0; + + // Negative pid + ASSERT_EQ(__llvm_libc::sched_rr_get_interval(-1, &ts), -1); + ASSERT_EQ(libc_errno, EINVAL); + libc_errno = 0; + } + + // Negative tests don't have SCHED_RR set + SetSched(SCHED_OTHER); + ASSERT_EQ(__llvm_libc::sched_rr_get_interval(0, &ts), 0); + ASSERT_EQ(libc_errno, 0); + libc_errno = 0; + + // TODO: Missing unkown pid -> ESRCH. This is read only so safe to try a few + // unlikely values. +}