xref: /aosp_15_r20/external/llvm-libc/test/src/sched/param_and_scheduler_test.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "src/errno/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/Test.h"
18 
19 #include <sched.h>
20 
21 // We Test:
22 // SCHED_OTHER, SCHED_FIFO, SCHED_RR
23 //
24 // TODO: Missing two tests.
25 //       1) Missing permissions -> EPERM. Maybe doable by finding
26 //          another pid that exists and changing its policy, but that
27 //          seems risky. Maybe something with fork/clone would work.
28 //
29 //       2) Unkown pid -> ESRCH. Probably safe to choose a large range
30 //          number or scanning current pids and getting one that doesn't
31 //          exist, but again seems like it may risk actually changing
32 //          sched policy on a running task.
33 //
34 //       Linux specific test could also include:
35 //          SCHED_ISO, SCHED_DEADLINE
36 
37 class SchedTest : public LIBC_NAMESPACE::testing::Test {
38 public:
testSched(int policy,bool is_mandatory)39   void testSched(int policy, bool is_mandatory) {
40     LIBC_NAMESPACE::libc_errno = 0;
41 
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 pid
56     ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(-1, policy, &param), -1);
57     ASSERT_ERRNO_EQ(EINVAL);
58     LIBC_NAMESPACE::libc_errno = 0;
59 
60     ASSERT_EQ(LIBC_NAMESPACE::sched_getscheduler(-1), -1);
61     ASSERT_ERRNO_EQ(EINVAL);
62     LIBC_NAMESPACE::libc_errno = 0;
63 
64     // Invalid Policy
65     ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy | 128, &param), -1);
66     ASSERT_ERRNO_EQ(EINVAL);
67     LIBC_NAMESPACE::libc_errno = 0;
68 
69     // Out of bounds priority
70     param.sched_priority = min_priority - 1;
71     ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, &param), -1);
72     ASSERT_ERRNO_EQ(EINVAL);
73     LIBC_NAMESPACE::libc_errno = 0;
74 
75     param.sched_priority = max_priority + 1;
76     ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, &param), -1);
77     // A bit hard to test as depending on user privileges we can run into
78     // different issues.
79     ASSERT_TRUE(LIBC_NAMESPACE::libc_errno == EINVAL ||
80                 LIBC_NAMESPACE::libc_errno == EPERM);
81     LIBC_NAMESPACE::libc_errno = 0;
82 
83     param.sched_priority = min_priority;
84     // Success/unsupported policy/missing permissions.
85     int setscheduler_result =
86         LIBC_NAMESPACE::sched_setscheduler(0, policy, &param);
87     ASSERT_TRUE(setscheduler_result == 0 || setscheduler_result == -1);
88     ASSERT_TRUE(
89         setscheduler_result != -1
90             ? (LIBC_NAMESPACE::libc_errno == 0)
91             : ((!is_mandatory && LIBC_NAMESPACE::libc_errno == EINVAL) ||
92                LIBC_NAMESPACE::libc_errno == EPERM));
93     LIBC_NAMESPACE::libc_errno = 0;
94 
95     ASSERT_EQ(LIBC_NAMESPACE::sched_getscheduler(0),
96               setscheduler_result != -1 ? policy : init_policy);
97     ASSERT_ERRNO_SUCCESS();
98 
99     // Out of bounds priority
100     param.sched_priority = -1;
101     ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, &param), -1);
102     ASSERT_ERRNO_EQ(EINVAL);
103     LIBC_NAMESPACE::libc_errno = 0;
104 
105     param.sched_priority = max_priority + 1;
106     ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, &param), -1);
107     ASSERT_ERRNO_EQ(EINVAL);
108     LIBC_NAMESPACE::libc_errno = 0;
109 
110     for (int priority = min_priority; priority <= max_priority; ++priority) {
111       ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, &param), 0);
112       ASSERT_ERRNO_SUCCESS();
113       int init_priority = param.sched_priority;
114 
115       param.sched_priority = priority;
116 
117       // Negative pid
118       ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(-1, &param), -1);
119       ASSERT_ERRNO_EQ(EINVAL);
120       LIBC_NAMESPACE::libc_errno = 0;
121 
122       ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(-1, &param), -1);
123       ASSERT_ERRNO_EQ(EINVAL);
124       LIBC_NAMESPACE::libc_errno = 0;
125 
126       // Success/unsupported policy/missing permissions
127       int setparam_result = LIBC_NAMESPACE::sched_setparam(0, &param);
128       ASSERT_TRUE(setparam_result == 0 || setparam_result == -1);
129       ASSERT_TRUE(setparam_result != -1
130                       ? (LIBC_NAMESPACE::libc_errno == 0)
131                       : ((setscheduler_result == -1 &&
132                           LIBC_NAMESPACE::libc_errno == EINVAL) ||
133                          LIBC_NAMESPACE::libc_errno == EPERM));
134       LIBC_NAMESPACE::libc_errno = 0;
135 
136       ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, &param), 0);
137       ASSERT_ERRNO_SUCCESS();
138 
139       ASSERT_EQ(param.sched_priority,
140                 setparam_result != -1 ? priority : init_priority);
141     }
142 
143     // Null test
144     ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, nullptr), -1);
145     ASSERT_ERRNO_EQ(EINVAL);
146     LIBC_NAMESPACE::libc_errno = 0;
147   }
148 };
149 
150 #define LIST_SCHED_TESTS(policy, can_set)                                      \
151   using LlvmLibcSchedTest = SchedTest;                                         \
152   TEST_F(LlvmLibcSchedTest, Sched_##policy) { testSched(policy, can_set); }
153 
154 // Mandated by POSIX.
LIST_SCHED_TESTS(SCHED_OTHER,true)155 LIST_SCHED_TESTS(SCHED_OTHER, true)
156 LIST_SCHED_TESTS(SCHED_FIFO, true)
157 LIST_SCHED_TESTS(SCHED_RR, true)
158 
159 // Linux extensions.
160 LIST_SCHED_TESTS(SCHED_BATCH, true)
161 LIST_SCHED_TESTS(SCHED_IDLE, true)
162 
163 TEST(LlvmLibcSchedParamAndSchedulerTest, NullParamTest) {
164   LIBC_NAMESPACE::libc_errno = 0;
165 
166   ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, nullptr), -1);
167   ASSERT_ERRNO_EQ(EINVAL);
168   LIBC_NAMESPACE::libc_errno = 0;
169 
170   ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, nullptr), -1);
171   ASSERT_ERRNO_EQ(EINVAL);
172   LIBC_NAMESPACE::libc_errno = 0;
173 }
174