158 lines · cpp
1//===-- Unittests for sched_{set,get}{scheduler,param} --------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "src/__support/libc_errno.h"10#include "src/sched/sched_get_priority_max.h"11#include "src/sched/sched_get_priority_min.h"12#include "src/sched/sched_getparam.h"13#include "src/sched/sched_getscheduler.h"14#include "src/sched/sched_setparam.h"15#include "src/sched/sched_setscheduler.h"16#include "src/unistd/getuid.h"17#include "test/UnitTest/ErrnoCheckingTest.h"18#include "test/UnitTest/Test.h"19 20#include "hdr/sched_macros.h"21#include "hdr/types/struct_sched_param.h"22 23// We Test:24// SCHED_OTHER, SCHED_FIFO, SCHED_RR25//26// TODO: Missing two tests.27// 1) Missing permissions -> EPERM. Maybe doable by finding28// another pid that exists and changing its policy, but that29// seems risky. Maybe something with fork/clone would work.30//31// 2) Unkown pid -> ESRCH. Probably safe to choose a large range32// number or scanning current pids and getting one that doesn't33// exist, but again seems like it may risk actually changing34// sched policy on a running task.35//36// Linux specific test could also include:37// SCHED_ISO, SCHED_DEADLINE38 39class SchedTest : public LIBC_NAMESPACE::testing::ErrnoCheckingTest {40public:41 void testSched(int policy, bool is_mandatory) {42 int init_policy = LIBC_NAMESPACE::sched_getscheduler(0);43 ASSERT_GE(init_policy, 0);44 ASSERT_ERRNO_SUCCESS();45 46 int max_priority = LIBC_NAMESPACE::sched_get_priority_max(policy);47 ASSERT_GE(max_priority, 0);48 ASSERT_ERRNO_SUCCESS();49 int min_priority = LIBC_NAMESPACE::sched_get_priority_min(policy);50 ASSERT_GE(min_priority, 0);51 ASSERT_ERRNO_SUCCESS();52 53 struct sched_param param = {min_priority};54 55 // Negative pid56 ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(-1, policy, ¶m), -1);57 ASSERT_ERRNO_EQ(EINVAL);58 59 ASSERT_EQ(LIBC_NAMESPACE::sched_getscheduler(-1), -1);60 ASSERT_ERRNO_EQ(EINVAL);61 62 // Invalid Policy63 ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy | 128, ¶m), -1);64 ASSERT_ERRNO_EQ(EINVAL);65 66 // Out of bounds priority67 param.sched_priority = min_priority - 1;68 ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, ¶m), -1);69 ASSERT_ERRNO_EQ(EINVAL);70 71 param.sched_priority = max_priority + 1;72 ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, ¶m), -1);73 // A bit hard to test as depending on user privileges we can run into74 // different issues.75 ASSERT_TRUE(libc_errno == EINVAL || libc_errno == EPERM);76 libc_errno = 0;77 78 param.sched_priority = min_priority;79 // Success/unsupported policy/missing permissions.80 int setscheduler_result =81 LIBC_NAMESPACE::sched_setscheduler(0, policy, ¶m);82 ASSERT_TRUE(setscheduler_result == 0 || setscheduler_result == -1);83 ASSERT_TRUE(84 setscheduler_result != -185 ? (libc_errno == 0)86 : ((!is_mandatory && libc_errno == EINVAL) || libc_errno == EPERM));87 libc_errno = 0;88 89 ASSERT_EQ(LIBC_NAMESPACE::sched_getscheduler(0),90 setscheduler_result != -1 ? policy : init_policy);91 ASSERT_ERRNO_SUCCESS();92 93 // Out of bounds priority94 param.sched_priority = -1;95 ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, ¶m), -1);96 ASSERT_ERRNO_EQ(EINVAL);97 98 param.sched_priority = max_priority + 1;99 ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, ¶m), -1);100 ASSERT_ERRNO_EQ(EINVAL);101 102 for (int priority = min_priority; priority <= max_priority; ++priority) {103 ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, ¶m), 0);104 ASSERT_ERRNO_SUCCESS();105 int init_priority = param.sched_priority;106 107 param.sched_priority = priority;108 109 // Negative pid110 ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(-1, ¶m), -1);111 ASSERT_ERRNO_EQ(EINVAL);112 113 ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(-1, ¶m), -1);114 ASSERT_ERRNO_EQ(EINVAL);115 116 // Success/unsupported policy/missing permissions117 int setparam_result = LIBC_NAMESPACE::sched_setparam(0, ¶m);118 ASSERT_TRUE(setparam_result == 0 || setparam_result == -1);119 ASSERT_TRUE(setparam_result != -1120 ? (libc_errno == 0)121 : ((setscheduler_result == -1 && libc_errno == EINVAL) ||122 libc_errno == EPERM));123 libc_errno = 0;124 125 ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, ¶m), 0);126 ASSERT_ERRNO_SUCCESS();127 128 ASSERT_EQ(param.sched_priority,129 setparam_result != -1 ? priority : init_priority);130 }131 132 // Null test133 ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, nullptr), -1);134 ASSERT_ERRNO_EQ(EINVAL);135 }136};137 138#define LIST_SCHED_TESTS(policy, can_set) \139 using LlvmLibcSchedTest = SchedTest; \140 TEST_F(LlvmLibcSchedTest, Sched_##policy) { testSched(policy, can_set); }141 142// Mandated by POSIX.143LIST_SCHED_TESTS(SCHED_OTHER, true)144LIST_SCHED_TESTS(SCHED_FIFO, true)145LIST_SCHED_TESTS(SCHED_RR, true)146 147// Linux extensions.148LIST_SCHED_TESTS(SCHED_BATCH, true)149LIST_SCHED_TESTS(SCHED_IDLE, true)150 151TEST(LlvmLibcSchedParamAndSchedulerTest, NullParamTest) {152 ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, nullptr), -1);153 ASSERT_ERRNO_EQ(EINVAL);154 155 ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, nullptr), -1);156 ASSERT_ERRNO_EQ(EINVAL);157}158