| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include "test_sched.h" |
| #include <ksched.h> |
| |
| #define THREAD_NUM 4 |
| |
| static struct k_thread tdata_prio[THREAD_NUM]; |
| static struct k_thread tdata; |
| static int last_prio; |
| static uint8_t tid_num[4]; |
| static struct k_sem sync_sema; |
| |
| |
| static void thread_entry(void *p1, void *p2, void *p3) |
| { |
| last_prio = k_thread_priority_get(k_current_get()); |
| } |
| |
| static void thread_entry_prio(void *p1, void *p2, void *p3) |
| { |
| static int i; |
| |
| k_sem_take(&sync_sema, K_MSEC(100)); |
| |
| tid_num[i++] = POINTER_TO_INT(p1); |
| } |
| |
| |
| /* test cases */ |
| |
| /** |
| * @brief Validate that the cooperative thread will |
| * not be preempted |
| * |
| * @details Create a cooperative thread with priority higher |
| * than the current cooperative thread. Make sure that the higher |
| * priority thread will not preempt the lower priority cooperative |
| * thread. |
| * |
| * @ingroup kernel_sched_tests |
| */ |
| void test_priority_cooperative(void) |
| { |
| int old_prio = k_thread_priority_get(k_current_get()); |
| |
| /* set current thread to a negative priority */ |
| last_prio = -1; |
| k_thread_priority_set(k_current_get(), last_prio); |
| |
| /* spawn thread with higher priority */ |
| int spawn_prio = last_prio - 1; |
| |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| spawn_prio, 0, K_NO_WAIT); |
| /* checkpoint: current thread shouldn't preempted by higher thread */ |
| zassert_true(last_prio == k_thread_priority_get(k_current_get()), NULL); |
| k_sleep(K_MSEC(100)); |
| /* checkpoint: spawned thread get executed */ |
| zassert_true(last_prio == spawn_prio, NULL); |
| k_thread_abort(tid); |
| |
| /* restore environment */ |
| k_thread_priority_set(k_current_get(), old_prio); |
| } |
| |
| /** |
| * @brief Validate preemptiveness of preemptive thread |
| * |
| * @details Create a preemptive thread which is of priority |
| * lower than current thread. Current thread is made has preemptive. |
| * Make sure newly created thread is not preempted. Now create a |
| * preemptive thread which is of priority higher than current |
| * thread. Make sure newly created thread is preempted |
| * |
| * @ingroup kernel_sched_tests |
| */ |
| void test_priority_preemptible(void) |
| { |
| int old_prio = k_thread_priority_get(k_current_get()); |
| |
| /* set current thread to a non-negative priority */ |
| last_prio = 2; |
| k_thread_priority_set(k_current_get(), last_prio); |
| |
| int spawn_prio = last_prio - 1; |
| |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| spawn_prio, 0, K_NO_WAIT); |
| /* checkpoint: thread is preempted by higher thread */ |
| zassert_true(last_prio == spawn_prio, NULL); |
| |
| k_sleep(K_MSEC(100)); |
| k_thread_abort(tid); |
| |
| spawn_prio = last_prio + 1; |
| tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| spawn_prio, 0, K_NO_WAIT); |
| /* checkpoint: thread is not preempted by lower thread */ |
| zassert_false(last_prio == spawn_prio, NULL); |
| k_thread_abort(tid); |
| |
| /* restore environment */ |
| k_thread_priority_set(k_current_get(), old_prio); |
| } |
| |
| /** |
| * @brief Validate scheduling sequence of preemptive threads with start delay |
| * |
| * @details Create four preemptive threads which are of priority |
| * higher than current thread. Make sure that the highest priority |
| * and longest waiting thread is scheduled first. |
| * |
| * @ingroup kernel_sched_tests |
| */ |
| void test_priority_preemptible_wait_prio(void) |
| { |
| int old_prio = k_thread_priority_get(k_current_get()); |
| k_tid_t tid[THREAD_NUM]; |
| uint8_t tid_chk[4] = { 0, 1, 2, 3 }; |
| |
| k_sem_init(&sync_sema, 0, THREAD_NUM); |
| |
| /* Ensure that this code starts running at the start of a system tick */ |
| k_usleep(1); |
| |
| /* set current thread to a non-negative priority */ |
| last_prio = K_PRIO_PREEMPT(2); |
| k_thread_priority_set(k_current_get(), last_prio); |
| |
| /* the highest-priority thread that has waited the longest */ |
| tid[0] = k_thread_create(&tdata_prio[0], tstacks[0], STACK_SIZE, |
| thread_entry_prio, INT_TO_POINTER(0), NULL, NULL, |
| K_PRIO_PREEMPT(0), 0, K_MSEC(10)); |
| /* the highest-priority thread that has waited the shorter */ |
| tid[1] = k_thread_create(&tdata_prio[1], tstacks[1], STACK_SIZE, |
| thread_entry_prio, INT_TO_POINTER(1), NULL, NULL, |
| K_PRIO_PREEMPT(0), 0, K_MSEC(20)); |
| /* the lowest-priority thread that has waited longest */ |
| tid[2] = k_thread_create(&tdata_prio[2], tstacks[2], STACK_SIZE, |
| thread_entry_prio, INT_TO_POINTER(2), NULL, NULL, |
| K_PRIO_PREEMPT(1), 0, K_MSEC(10)); |
| /* the lowest-priority thread that has waited shorter */ |
| tid[3] = k_thread_create(&tdata_prio[3], tstacks[3], STACK_SIZE, |
| thread_entry_prio, INT_TO_POINTER(3), NULL, NULL, |
| K_PRIO_PREEMPT(1), 0, K_MSEC(20)); |
| |
| /* relinquish CPU for above threads to start */ |
| k_sleep(K_MSEC(30)); |
| |
| for (int i = 0; i < THREAD_NUM; i++) { |
| k_sem_give(&sync_sema); |
| } |
| |
| zassert_true((memcmp(tid_num, tid_chk, 4) == 0), |
| "scheduling priority failed"); |
| |
| /* test case tear down */ |
| for (int i = 0; i < THREAD_NUM; i++) { |
| k_thread_abort(tid[i]); |
| } |
| |
| /* restore environment */ |
| k_thread_priority_set(k_current_get(), old_prio); |
| } |
| |
| extern void idle(void *p1, void *p2, void *p3); |
| |
| /** |
| * Validate checking priority values |
| * |
| * Our test cases don't cover every outcome of whether a priority is valid, |
| * do so here. |
| * |
| * @ingroup kernel_sched_tests |
| */ |
| void test_bad_priorities(void) |
| { |
| struct prio_test { |
| int prio; |
| void *entry; |
| bool result; |
| } testcases[] = { |
| { K_IDLE_PRIO, idle, true }, |
| { K_IDLE_PRIO, NULL, false }, |
| { K_HIGHEST_APPLICATION_THREAD_PRIO - 1, NULL, false }, |
| { K_LOWEST_APPLICATION_THREAD_PRIO + 1, NULL, false }, |
| { K_HIGHEST_APPLICATION_THREAD_PRIO, NULL, true }, |
| { K_LOWEST_APPLICATION_THREAD_PRIO, NULL, true }, |
| { CONFIG_MAIN_THREAD_PRIORITY, NULL, true } |
| }; |
| |
| for (int i = 0; i < ARRAY_SIZE(testcases); i++) { |
| zassert_equal(_is_valid_prio(testcases[i].prio, |
| testcases[i].entry), |
| testcases[i].result, "failed check %d", i); |
| /* XXX why are these even separate APIs? */ |
| zassert_equal(Z_VALID_PRIO(testcases[i].prio, |
| testcases[i].entry), |
| testcases[i].result, "failed check %d", i); |
| } |
| } |