• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 can_set)39   void testSched(int policy, bool can_set) {
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 if we are root or not 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     // Some sched policies require permissions, so skip
84     param.sched_priority = min_priority;
85     // Success / missing permissions.
86     ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, &param),
87               can_set ? 0 : -1);
88     ASSERT_TRUE(can_set ? (LIBC_NAMESPACE::libc_errno == 0)
89                         : (LIBC_NAMESPACE::libc_errno == EINVAL ||
90                            LIBC_NAMESPACE::libc_errno == EPERM));
91     LIBC_NAMESPACE::libc_errno = 0;
92 
93     ASSERT_EQ(LIBC_NAMESPACE::sched_getscheduler(0),
94               can_set ? policy : init_policy);
95     ASSERT_ERRNO_SUCCESS();
96 
97     // Out of bounds priority
98     param.sched_priority = -1;
99     ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, &param), -1);
100     ASSERT_ERRNO_EQ(EINVAL);
101     LIBC_NAMESPACE::libc_errno = 0;
102 
103     param.sched_priority = max_priority + 1;
104     ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, &param), -1);
105     ASSERT_ERRNO_EQ(EINVAL);
106     LIBC_NAMESPACE::libc_errno = 0;
107 
108     for (int priority = min_priority; priority <= max_priority; ++priority) {
109       ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, &param), 0);
110       ASSERT_ERRNO_SUCCESS();
111       int init_priority = param.sched_priority;
112 
113       param.sched_priority = priority;
114 
115       // Negative pid
116       ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(-1, &param), -1);
117       ASSERT_ERRNO_EQ(EINVAL);
118       LIBC_NAMESPACE::libc_errno = 0;
119 
120       ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(-1, &param), -1);
121       ASSERT_ERRNO_EQ(EINVAL);
122       LIBC_NAMESPACE::libc_errno = 0;
123 
124       // Success / missing permissions
125       ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, &param), can_set ? 0 : -1);
126       ASSERT_TRUE(can_set ? (LIBC_NAMESPACE::libc_errno == 0)
127                           : (LIBC_NAMESPACE::libc_errno == EINVAL ||
128                              LIBC_NAMESPACE::libc_errno == EPERM));
129       LIBC_NAMESPACE::libc_errno = 0;
130 
131       ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, &param), 0);
132       ASSERT_ERRNO_SUCCESS();
133 
134       ASSERT_EQ(param.sched_priority, can_set ? priority : init_priority);
135     }
136 
137     // Null test
138     ASSERT_EQ(LIBC_NAMESPACE::sched_setscheduler(0, policy, nullptr), -1);
139     ASSERT_ERRNO_EQ(EINVAL);
140     LIBC_NAMESPACE::libc_errno = 0;
141   }
142 };
143 
144 #define LIST_SCHED_TESTS(policy, can_set)                                      \
145   using LlvmLibcSchedTest = SchedTest;                                         \
146   TEST_F(LlvmLibcSchedTest, Sched_##policy) { testSched(policy, can_set); }
147 
148 // Root is required to set these policies.
149 LIST_SCHED_TESTS(SCHED_FIFO, LIBC_NAMESPACE::getuid() == 0)
150 LIST_SCHED_TESTS(SCHED_RR, LIBC_NAMESPACE::getuid() == 0)
151 
152 // No root is required to set these policies.
LIST_SCHED_TESTS(SCHED_OTHER,true)153 LIST_SCHED_TESTS(SCHED_OTHER, true)
154 LIST_SCHED_TESTS(SCHED_BATCH, true)
155 LIST_SCHED_TESTS(SCHED_IDLE, true)
156 
157 TEST(LlvmLibcSchedParamAndSchedulerTest, NullParamTest) {
158   LIBC_NAMESPACE::libc_errno = 0;
159 
160   ASSERT_EQ(LIBC_NAMESPACE::sched_setparam(0, nullptr), -1);
161   ASSERT_ERRNO_EQ(EINVAL);
162   LIBC_NAMESPACE::libc_errno = 0;
163 
164   ASSERT_EQ(LIBC_NAMESPACE::sched_getparam(0, nullptr), -1);
165   ASSERT_ERRNO_EQ(EINVAL);
166   LIBC_NAMESPACE::libc_errno = 0;
167 }
168