345 changes: 78 additions & 267 deletions libc/test/src/sched/param_and_scheduler_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,313 +32,124 @@
// sched policy on a running task.
//
// Linux specific test could also include:
// SCHED_BATCH, SCHED_ISO, SCHED_IDLE, SCHED_DEADLINE
// SCHED_ISO, 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, &param), -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, &param), -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, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

param.sched_priority = max_priority + 1;
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, &param), -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, &param),
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, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;
class SchedTest : public __llvm_libc::testing::Test {
public:
void testSched(int policy, bool can_set) {
libc_errno = 0;

param.sched_priority = max_priority + 1;
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;
int init_policy = __llvm_libc::sched_getscheduler(0);
ASSERT_GE(init_policy, 0);
ASSERT_EQ(libc_errno, 0);

for (int priority = min_priority; priority <= max_priority; ++priority) {
ASSERT_EQ(__llvm_libc::sched_getparam(0, &param), 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);
int init_priority = param.sched_priority;

param.sched_priority = priority;
struct sched_param param = {min_priority};

// Negative pid
ASSERT_EQ(__llvm_libc::sched_setparam(-1, &param), -1);
ASSERT_EQ(__llvm_libc::sched_setscheduler(-1, policy, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

ASSERT_EQ(__llvm_libc::sched_getparam(-1, &param), -1);
ASSERT_EQ(__llvm_libc::sched_getscheduler(-1), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

// Success / missing permissions
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), can_set ? 0 : -1);
ASSERT_TRUE(can_set ? (libc_errno == 0)
: (libc_errno == EINVAL || libc_errno == EPERM));
// Invalid Policy
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy | 128, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

ASSERT_EQ(__llvm_libc::sched_getparam(0, &param), 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, &param), -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, &param), -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, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

param.sched_priority = max_priority + 1;
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, &param), -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, &param),
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, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

param.sched_priority = max_priority + 1;
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), -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, &param), 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, &param), -1);
// Out of bounds priority
param.sched_priority = min_priority - 1;
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

ASSERT_EQ(__llvm_libc::sched_getparam(-1, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
param.sched_priority = max_priority + 1;
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, &param), -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;

// Success / missing permissions
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), can_set ? 0 : -1);
// Some sched policies require permissions, so skip
param.sched_priority = min_priority;
// Success / missing permissions.
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, &param),
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, &param), 0);
ASSERT_EQ(__llvm_libc::sched_getscheduler(0),
can_set ? policy : init_policy);
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, &param), -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;
// Out of bounds priority
param.sched_priority = -1;
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

// Invalid Policy
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy | 128, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;
param.sched_priority = max_priority + 1;
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), -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, &param), -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, &param), 0);
ASSERT_EQ(libc_errno, 0);
int init_priority = param.sched_priority;

param.sched_priority = max_priority + 1;
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, &param), -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;
param.sched_priority = priority;

// Some sched policies require permissions, so skip
param.sched_priority = min_priority;
// Success / missing permissions.
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, &param),
can_set ? 0 : -1);
ASSERT_TRUE(can_set ? (libc_errno == 0)
: (libc_errno == EINVAL || libc_errno == EPERM));
libc_errno = 0;
// Negative pid
ASSERT_EQ(__llvm_libc::sched_setparam(-1, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

ASSERT_EQ(__llvm_libc::sched_getscheduler(0), can_set ? policy : init_policy);
ASSERT_EQ(libc_errno, 0);
ASSERT_EQ(__llvm_libc::sched_getparam(-1, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

// Out of bounds priority
param.sched_priority = -1;
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;
// Success / missing permissions
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), can_set ? 0 : -1);
ASSERT_TRUE(can_set ? (libc_errno == 0)
: (libc_errno == EINVAL || libc_errno == EPERM));
libc_errno = 0;

param.sched_priority = max_priority + 1;
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;
ASSERT_EQ(__llvm_libc::sched_getparam(0, &param), 0);
ASSERT_EQ(libc_errno, 0);

for (int priority = min_priority; priority <= max_priority; ++priority) {
ASSERT_EQ(__llvm_libc::sched_getparam(0, &param), 0);
ASSERT_EQ(libc_errno, 0);
int init_priority = param.sched_priority;
ASSERT_EQ(param.sched_priority, can_set ? priority : init_priority);
}

param.sched_priority = priority;

// Negative pid
ASSERT_EQ(__llvm_libc::sched_setparam(-1, &param), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

ASSERT_EQ(__llvm_libc::sched_getparam(-1, &param), -1);
// Null test
ASSERT_EQ(__llvm_libc::sched_setscheduler(0, policy, nullptr), -1);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;
}
};

// Success / missing permissions
ASSERT_EQ(__llvm_libc::sched_setparam(0, &param), can_set ? 0 : -1);
ASSERT_TRUE(can_set ? (libc_errno == 0)
: (libc_errno == EINVAL || libc_errno == EPERM));
libc_errno = 0;
#define LIST_SCHED_TESTS(policy, can_set) \
using LlvmLibcSchedTest = SchedTest; \
TEST_F(LlvmLibcSchedTest, Sched_##policy) { testSched(policy, can_set); }

ASSERT_EQ(__llvm_libc::sched_getparam(0, &param), 0);
ASSERT_EQ(libc_errno, 0);
// Root is required to set these policies.
LIST_SCHED_TESTS(SCHED_FIFO, __llvm_libc::getuid() == 0)
LIST_SCHED_TESTS(SCHED_RR, __llvm_libc::getuid() == 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;
}
// No root is required to set these policies.
LIST_SCHED_TESTS(SCHED_OTHER, true)
LIST_SCHED_TESTS(SCHED_BATCH, true)
LIST_SCHED_TESTS(SCHED_IDLE, true)

TEST(LlvmLibcSchedParamAndSchedulerTest, NullParamTest) {
libc_errno = 0;
Expand Down