28 changes: 28 additions & 0 deletions libc/src/sched/linux/sched_get_priority_max.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h> // 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
28 changes: 28 additions & 0 deletions libc/src/sched/linux/sched_get_priority_min.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h> // 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
29 changes: 29 additions & 0 deletions libc/src/sched/linux/sched_getparam.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h> // 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
28 changes: 28 additions & 0 deletions libc/src/sched/linux/sched_getscheduler.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h> // 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
29 changes: 29 additions & 0 deletions libc/src/sched/linux/sched_rr_get_interval.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h> // 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
29 changes: 29 additions & 0 deletions libc/src/sched/linux/sched_setparam.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h> // 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
30 changes: 30 additions & 0 deletions libc/src/sched/linux/sched_setscheduler.cpp
Original file line number Diff line number Diff line change
@@ -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 <sys/syscall.h> // 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
18 changes: 18 additions & 0 deletions libc/src/sched/sched_get_priority_max.h
Original file line number Diff line number Diff line change
@@ -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
18 changes: 18 additions & 0 deletions libc/src/sched/sched_get_priority_min.h
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions libc/src/sched/sched_getparam.h
Original file line number Diff line number Diff line change
@@ -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 <sched.h>

namespace __llvm_libc {

int sched_getparam(pid_t tid, struct sched_param *param);

} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_SCHED_SCHED_GETPARAM_H
20 changes: 20 additions & 0 deletions libc/src/sched/sched_getscheduler.h
Original file line number Diff line number Diff line change
@@ -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 <sched.h>

namespace __llvm_libc {

int sched_getscheduler(pid_t tid);

} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_SCHED_SCHED_GETSCHEDULER_H
20 changes: 20 additions & 0 deletions libc/src/sched/sched_rr_get_interval.h
Original file line number Diff line number Diff line change
@@ -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 <sched.h>

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
20 changes: 20 additions & 0 deletions libc/src/sched/sched_setparam.h
Original file line number Diff line number Diff line change
@@ -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 <sched.h>

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
20 changes: 20 additions & 0 deletions libc/src/sched/sched_setscheduler.h
Original file line number Diff line number Diff line change
@@ -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 <sched.h>

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
14 changes: 14 additions & 0 deletions libc/test/integration/src/pthread/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,3 +116,17 @@ add_integration_test(
libc.src.pthread.pthread_join
libc.src.__support.CPP.atomic
)

add_integration_test(
pthread_join_test
SUITE
libc-pthread-integration-tests
SRCS
pthread_join_test.cpp
DEPENDS
libc.include.pthread
libc.include.errno
libc.include.stdio
libc.src.pthread.pthread_create
libc.src.pthread.pthread_join
)
30 changes: 30 additions & 0 deletions libc/test/integration/src/pthread/pthread_join_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//===-- Tests for pthread_join-- ------------------------------------------===//
//
// 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/pthread/pthread_create.h"
#include "src/pthread/pthread_join.h"

#include "src/errno/libc_errno.h"

#include "test/IntegrationTest/test.h"
#include <pthread.h>

static void *simpleFunc(void *) { return nullptr; }
static void nullJoinTest() {
pthread_t Tid;
ASSERT_EQ(__llvm_libc::pthread_create(&Tid, nullptr, simpleFunc, nullptr), 0);
ASSERT_EQ(libc_errno, 0);
ASSERT_EQ(__llvm_libc::pthread_join(Tid, nullptr), 0);
ASSERT_EQ(libc_errno, 0);
}

TEST_MAIN() {
libc_errno = 0;
nullJoinTest();
return 0;
}
47 changes: 47 additions & 0 deletions libc/test/src/sched/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,53 @@ add_libc_unittest(
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
Expand Down
108 changes: 108 additions & 0 deletions libc/test/src/sched/get_priority_test.cpp
Original file line number Diff line number Diff line change
@@ -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 <sched.h>

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);
}
}
353 changes: 353 additions & 0 deletions libc/test/src/sched/param_and_scheduler_test.cpp
Original file line number Diff line number Diff line change
@@ -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 <sched.h>

// 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, &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);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

ASSERT_EQ(__llvm_libc::sched_getparam(-1, &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;

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);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

ASSERT_EQ(__llvm_libc::sched_getparam(-1, &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;

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, 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;

// 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);
ASSERT_EQ(libc_errno, EINVAL);
libc_errno = 0;

ASSERT_EQ(__llvm_libc::sched_getparam(-1, &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;

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, 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;
}
74 changes: 74 additions & 0 deletions libc/test/src/sched/sched_rr_get_interval_test.cpp
Original file line number Diff line number Diff line change
@@ -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 <sched.h>

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, &param), 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.
}