| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/ztest.h> |
| |
| #include "tests_thread_apis.h" |
| |
| static ZTEST_BMEM int last_prio; |
| |
| static void thread_entry(void *p1, void *p2, void *p3) |
| { |
| last_prio = k_thread_priority_get(k_current_get()); |
| } |
| |
| static void threads_suspend_resume(int prio) |
| { |
| /* set current thread */ |
| last_prio = prio; |
| k_thread_priority_set(k_current_get(), last_prio); |
| |
| /* create thread with lower priority */ |
| int create_prio = last_prio + 1; |
| |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| create_prio, K_USER, K_NO_WAIT); |
| /* checkpoint: suspend current thread */ |
| k_thread_suspend(tid); |
| k_msleep(100); |
| /* checkpoint: created thread shouldn't be executed after suspend */ |
| zassert_false(last_prio == create_prio); |
| k_thread_resume(tid); |
| k_msleep(100); |
| /* checkpoint: created thread should be executed after resume */ |
| zassert_true(last_prio == create_prio); |
| } |
| |
| /*test cases*/ |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * @brief Check the suspend and resume functionality in |
| * a cooperative thread |
| * |
| * @details Create a thread with the priority lower than the current |
| * thread which is cooperative and suspend it, make sure it doesn't |
| * gets scheduled, and resume and check if the entry function is executed. |
| * |
| * @see k_thread_suspend(), k_thread_resume() |
| */ |
| ZTEST(threads_lifecycle_1cpu, test_threads_suspend_resume_cooperative) |
| { |
| threads_suspend_resume(-2); |
| } |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * @brief Check the suspend and resume functionality in |
| * preemptive thread |
| * |
| * @details Create a thread with the priority lower than the current |
| * thread which is preemptive and suspend it, make sure it doesn't gets |
| * scheduled, and resume and check if the entry function is executed. |
| * |
| * @see k_thread_suspend(), k_thread_resume() |
| */ |
| ZTEST_USER(threads_lifecycle, test_threads_suspend_resume_preemptible) |
| { |
| threads_suspend_resume(1); |
| } |
| |
| static bool after_suspend; |
| |
| void suspend_myself(void *arg0, void *arg1, void *arg2) |
| { |
| ARG_UNUSED(arg0); |
| ARG_UNUSED(arg1); |
| ARG_UNUSED(arg2); |
| k_thread_suspend(k_current_get()); |
| after_suspend = true; |
| } |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * |
| * @brief Check that k_thread_suspend() is a schedule point when |
| * called on the current thread. |
| */ |
| ZTEST(threads_lifecycle, test_threads_suspend) |
| { |
| after_suspend = false; |
| |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| suspend_myself, NULL, NULL, NULL, |
| 0, K_USER, K_NO_WAIT); |
| |
| /* Give the thread a chance to start and verify that it |
| * stopped executing after suspending itself. |
| */ |
| k_msleep(100); |
| zassert_false(after_suspend, "thread woke up unexpectedly"); |
| |
| k_thread_abort(tid); |
| } |
| |
| void sleep_suspended(void *arg0, void *arg1, void *arg2) |
| { |
| ARG_UNUSED(arg0); |
| ARG_UNUSED(arg1); |
| ARG_UNUSED(arg2); |
| |
| /* Sleep a half second, then set the flag after we wake up. |
| * If we are suspended, the wakeup should not occur |
| */ |
| k_msleep(100); |
| after_suspend = true; |
| } |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * @brief Check that k_thread_suspend() cancels a preexisting thread timeout |
| * |
| * @details Suspended threads should not wake up unexpectedly if they |
| * happened to have been sleeping when suspended. |
| */ |
| ZTEST(threads_lifecycle, test_threads_suspend_timeout) |
| { |
| after_suspend = false; |
| |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| sleep_suspended, NULL, NULL, NULL, |
| 0, K_USER, K_NO_WAIT); |
| |
| k_msleep(50); |
| k_thread_suspend(tid); |
| |
| /* Give the timer long enough to expire, and verify that it |
| * has not (i.e. that the thread didn't wake up, because it |
| * has been suspended) |
| */ |
| k_msleep(200); |
| zassert_false(after_suspend, "thread woke up unexpectedly"); |
| |
| k_thread_abort(tid); |
| } |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * @brief Check resume an unsuspend thread |
| * |
| * @details Use k_thread_state_str() to get thread state. |
| * Resume an unsuspend thread will not change the thread state. |
| */ |
| ZTEST(threads_lifecycle, test_resume_unsuspend_thread) |
| { |
| char buffer[32]; |
| const char *str; |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| 0, K_USER, K_NO_WAIT); |
| |
| |
| /* Resume an unsuspend thread will not change the thread state. */ |
| str = k_thread_state_str(tid, buffer, sizeof(buffer)); |
| zassert_true(strcmp(str, "queued") == 0); |
| k_thread_resume(tid); |
| str = k_thread_state_str(tid, buffer, sizeof(buffer)); |
| zassert_true(strcmp(str, "queued") == 0); |
| |
| /* suspend created thread */ |
| k_thread_suspend(tid); |
| str = k_thread_state_str(tid, buffer, sizeof(buffer)); |
| zassert_true(strcmp(str, "suspended") == 0); |
| |
| /* Resume an suspend thread will make it to be next eligible.*/ |
| k_thread_resume(tid); |
| str = k_thread_state_str(tid, buffer, sizeof(buffer)); |
| zassert_true(strcmp(str, "queued") == 0); |
| k_thread_abort(tid); |
| } |