#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "test.h" // ============================================================================ // Helper function // ============================================================================ #define MAX_CPU_NUM 1024 static int *g_online_cpu_idxs; int get_online_cpu() { int online_num = sysconf(_SC_NPROCESSORS_ONLN); cpu_set_t mask; int index = 0; g_online_cpu_idxs = (int *)calloc(online_num, sizeof(int)); CPU_ZERO(&mask); if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) < 0) { THROW_ERROR("failed to call sched_getaffinity"); } printf("Online Core No: "); for (int i = 0; index < online_num && i < MAX_CPU_NUM; i++) { if (CPU_ISSET(i, &mask)) { g_online_cpu_idxs[index] = i; index++; printf("%d ", i); } } printf("\n"); return 0; } // ============================================================================ // Test cases for sched_cpu_affinity // ============================================================================ static int test_sched_getaffinity_with_self_pid() { cpu_set_t mask; if (sched_getaffinity(0, sizeof(cpu_set_t), &mask) < 0) { THROW_ERROR("failed to call sched_getaffinity"); } if (CPU_COUNT(&mask) <= 0) { THROW_ERROR("failed to get cpuset mask"); } if (sysconf(_SC_NPROCESSORS_ONLN) < CPU_COUNT(&mask)) { THROW_ERROR("cpuset num must be less or equal to _SC_NPROCESSORS_ONLN"); } return 0; } static int test_sched_setaffinity_with_self_pid() { int nproc = sysconf(_SC_NPROCESSORS_ONLN); cpu_set_t mask_old; CPU_ZERO(&mask_old); for (int i = 0; i < nproc; ++i) { CPU_SET(g_online_cpu_idxs[i], &mask_old); } cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(g_online_cpu_idxs[0], &mask); if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) < 0) { THROW_ERROR("failed to call sched_setaffinity \n"); } cpu_set_t mask2; if (sched_getaffinity(0, sizeof(cpu_set_t), &mask2) < 0) { THROW_ERROR("failed to call sched_getaffinity"); } if (!CPU_EQUAL(&mask, &mask2)) { THROW_ERROR("cpuset is wrong after get"); } if (sched_setaffinity(0, sizeof(cpu_set_t), &mask_old) < 0) { THROW_ERROR("recover cpuset error"); } return 0; } static int test_sched_xetaffinity_with_child_pid() { int status, child_pid; int num = sysconf(_SC_NPROCESSORS_ONLN); if (num <= 0) { THROW_ERROR("failed to get cpu number"); } cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(g_online_cpu_idxs[num - 1], &mask); int ret = posix_spawn(&child_pid, "/bin/getpid", NULL, NULL, NULL, NULL); if (ret < 0 ) { THROW_ERROR("spawn process error"); } printf("Spawn a child process with pid=%d\n", child_pid); if (sched_setaffinity(child_pid, sizeof(cpu_set_t), &mask) < 0) { THROW_ERROR("failed to set child affinity"); } cpu_set_t mask2; if (sched_getaffinity(child_pid, sizeof(cpu_set_t), &mask2) < 0) { THROW_ERROR("failed to get child affinity"); } if (!CPU_EQUAL(&mask, &mask2)) { THROW_ERROR("cpuset is wrong in child"); } ret = wait4(-1, &status, 0, NULL); if (ret < 0) { THROW_ERROR("failed to wait4 the child proces"); } return 0; } static int test_sched_xetaffinity_children_inheritance() { int status, child_pid; int num_core = sysconf(_SC_NPROCESSORS_ONLN); if (num_core <= 0) { THROW_ERROR("failed to get cpu number"); } cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(g_online_cpu_idxs[num_core - 1], &mask); if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) < 0) { THROW_ERROR("failed to set parent affinity"); } int ret = posix_spawn(&child_pid, "/bin/getpid", NULL, NULL, NULL, NULL); if (ret < 0 ) { THROW_ERROR("spawn process error"); } printf("Spawn a child process with pid=%d\n", child_pid); cpu_set_t mask2; if (sched_getaffinity(child_pid, sizeof(cpu_set_t), &mask2) < 0) { THROW_ERROR("failed to get child affinity"); } if (!CPU_EQUAL(&mask, &mask2)) { THROW_ERROR("affinity inherited from parent is wrong in child"); } // Set affinity to child should not affect parent process CPU_SET(g_online_cpu_idxs[0], &mask2); if (sched_setaffinity(child_pid, sizeof(cpu_set_t), &mask2) < 0) { THROW_ERROR("failed to set child affinity"); } CPU_ZERO(&mask2); if (sched_getaffinity(0, sizeof(cpu_set_t), &mask2) < 0) { THROW_ERROR("failed to get parent process affinity"); } if (!CPU_EQUAL(&mask, &mask2)) { THROW_ERROR("cpuset is wrong in parent process"); } ret = wait4(-1, &status, 0, NULL); if (ret < 0) { THROW_ERROR("failed to wait4 the child procces"); } return 0; } #define CPU_SET_SIZE_LIMIT (128) static int test_sched_getaffinity_via_explicit_syscall() { unsigned char buf[CPU_SET_SIZE_LIMIT] = { 0 }; int ret = syscall(__NR_sched_getaffinity, 0, CPU_SET_SIZE_LIMIT, buf); if (ret <= 0) { THROW_ERROR("failed to call __NR_sched_getaffinity"); } return 0; } static int test_sched_setaffinity_via_explicit_syscall() { cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(g_online_cpu_idxs[0], &mask); if (syscall(__NR_sched_setaffinity, 0, sizeof(cpu_set_t), &mask) < 0) { THROW_ERROR("failed to call __NR_sched_setaffinity"); } cpu_set_t mask2; CPU_ZERO(&mask2); int ret_nproc = syscall(__NR_sched_getaffinity, 0, sizeof(cpu_set_t), &mask2); if (ret_nproc <= 0) { THROW_ERROR("failed to call __NR_sched_getaffinity"); } if (!CPU_EQUAL(&mask, &mask2)) { THROW_ERROR("explicit syscall cpuset is wrong"); } // Recover the affinity mask int nproc = sysconf(_SC_NPROCESSORS_ONLN); cpu_set_t mask_old; CPU_ZERO(&mask_old); for (int i = 0; i < nproc; ++i) { CPU_SET(g_online_cpu_idxs[i], &mask_old); } if (syscall(__NR_sched_setaffinity, 0, sizeof(cpu_set_t), &mask_old) < 0) { THROW_ERROR("recover cpuset error"); } return 0; } static int test_sched_getaffinity_with_zero_cpusetsize() { cpu_set_t mask; if (sched_getaffinity(0, 0, &mask) != -1) { THROW_ERROR("check invalid cpusetsize(0) fail"); } return 0; } static int test_sched_setaffinity_with_zero_cpusetsize() { cpu_set_t mask; if (sched_setaffinity(0, 0, &mask) != -1) { THROW_ERROR("check invalid cpusetsize(0) fail"); } return 0; } static int test_sched_getaffinity_with_null_buffer() { unsigned char *buf = NULL; if (sched_getaffinity(0, sizeof(cpu_set_t), (cpu_set_t *)buf) != -1) { THROW_ERROR("check invalid buffer pointer(NULL) fail"); } return 0; } static int test_sched_setaffinity_with_null_buffer() { unsigned char *buf = NULL; if (sched_setaffinity(0, sizeof(cpu_set_t), (cpu_set_t *)buf) != -1) { THROW_ERROR("check invalid buffer pointer(NULL) fail"); } return 0; } // ============================================================================ // Test cases for sched_yield // ============================================================================ static int test_sched_yield() { // In the Linux implementation, sched_yield() always succeeds. if (sched_yield() < 0) { THROW_ERROR("check sched yield fail"); } return 0; } // ============================================================================ // Test cases for getcpu // ============================================================================ static int test_getcpu() { int cpu, node; if (syscall(__NR_getcpu, &cpu, &node, NULL) < 0) { THROW_ERROR("getcpu with cpu&node fail"); } if (syscall(__NR_getcpu, &cpu, NULL, NULL) < 0) { THROW_ERROR("getcpu with cpu fail"); } if (syscall(__NR_getcpu, NULL, &node, NULL) < 0) { THROW_ERROR("getcpu with node fail"); } if (syscall(__NR_getcpu, NULL, NULL, NULL) < 0) { THROW_ERROR("getcpu with null fail"); } return 0; } static int test_getcpu_after_setaffinity() { int nproc = sysconf(_SC_NPROCESSORS_ONLN); cpu_set_t mask_old; CPU_ZERO(&mask_old); for (int i = 0; i < nproc; ++i) { CPU_SET(g_online_cpu_idxs[i], &mask_old); } cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(g_online_cpu_idxs[0], &mask); if (sched_setaffinity(0, sizeof(cpu_set_t), &mask) < 0) { THROW_ERROR("failed to call sched_setaffinity \n"); } int cpu; int ret = syscall(__NR_getcpu, &cpu, NULL, NULL); if (ret < 0) { THROW_ERROR("getcpu fail"); } if (cpu != g_online_cpu_idxs[0]) { THROW_ERROR("check processor id fail"); } if (sched_setaffinity(0, sizeof(cpu_set_t), &mask_old) < 0) { THROW_ERROR("recover cpuset error"); } return 0; } // ============================================================================ // Test cases for setpriority and getpriority // ============================================================================ static int test_set_get_priority(int which, id_t who, int prio) { if (setpriority(which, who, prio) < 0) { THROW_ERROR("failed to setpriority"); } errno = 0; int ret_prio = getpriority(which, who); if (errno != 0) { THROW_ERROR("failed to getpriority"); } if (ret_prio != prio) { THROW_ERROR("failed to check prio after set"); } return 0; } static int test_set_get_priority_process() { int which = PRIO_PROCESS; id_t who = getpid(); int prio = 10; if (test_set_get_priority(which, who, prio) < 0) { THROW_ERROR("failed to test process"); } return 0; } static int test_set_get_priority_pgrp() { int which = PRIO_PGRP; id_t who = getpgrp(); int prio = -10; if (test_set_get_priority(which, who, prio) < 0) { THROW_ERROR("failed to test pgrp"); } return 0; } static int test_set_get_priority_user() { int which = PRIO_USER; id_t who = 0; int prio = -1; if (test_set_get_priority(which, who, prio) < 0) { THROW_ERROR("failed to test user"); } return 0; } // ============================================================================ // Test suite main // ============================================================================ static test_case_t test_cases[] = { TEST_CASE(test_sched_xetaffinity_with_child_pid), TEST_CASE(test_sched_getaffinity_with_self_pid), TEST_CASE(test_sched_setaffinity_with_self_pid), TEST_CASE(test_sched_getaffinity_via_explicit_syscall), TEST_CASE(test_sched_setaffinity_via_explicit_syscall), TEST_CASE(test_sched_getaffinity_with_zero_cpusetsize), TEST_CASE(test_sched_setaffinity_with_zero_cpusetsize), TEST_CASE(test_sched_getaffinity_with_null_buffer), TEST_CASE(test_sched_setaffinity_with_null_buffer), TEST_CASE(test_sched_yield), TEST_CASE(test_sched_xetaffinity_children_inheritance), TEST_CASE(test_getcpu), TEST_CASE(test_getcpu_after_setaffinity), TEST_CASE(test_set_get_priority_process), TEST_CASE(test_set_get_priority_pgrp), TEST_CASE(test_set_get_priority_user), }; int main() { int ret; get_online_cpu(); ret = test_suite_run(test_cases, ARRAY_SIZE(test_cases)); free(g_online_cpu_idxs); return ret; }