| /* |
| * Copyright (c) 2016 Intel Corporation |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/ztest.h> |
| |
| #include "tests_thread_apis.h" |
| |
| static ZTEST_BMEM int execute_flag; |
| |
| K_SEM_DEFINE(sync_sema, 0, 1); |
| #define BLOCK_SIZE 64 |
| |
| static void thread_entry(void *p1, void *p2, void *p3) |
| { |
| execute_flag = 1; |
| k_msleep(100); |
| execute_flag = 2; |
| } |
| |
| static void thread_entry_abort(void *p1, void *p2, void *p3) |
| { |
| /**TESTPOINT: abort current thread*/ |
| execute_flag = 1; |
| k_thread_abort(k_current_get()); |
| /*unreachable*/ |
| execute_flag = 2; |
| zassert_true(1 == 0, NULL); |
| } |
| /** |
| * @ingroup kernel_thread_tests |
| * @brief Validate k_thread_abort() when called by current thread |
| * |
| * @details Create a user thread and let the thread execute. |
| * Then call k_thread_abort() and check if the thread is terminated. |
| * Here the main thread is also a user thread. |
| * |
| * @see k_thread_abort() |
| */ |
| void test_threads_abort_self(void) |
| { |
| execute_flag = 0; |
| k_thread_create(&tdata, tstack, STACK_SIZE, thread_entry_abort, |
| NULL, NULL, NULL, 0, K_USER, K_NO_WAIT); |
| k_msleep(100); |
| /**TESTPOINT: spawned thread executed but abort itself*/ |
| zassert_true(execute_flag == 1, NULL); |
| } |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * @brief Validate k_thread_abort() when called by other thread |
| * |
| * @details Create a user thread and abort the thread before its |
| * execution. Create a another user thread and abort the thread |
| * after it has started. |
| * |
| * @see k_thread_abort() |
| */ |
| void test_threads_abort_others(void) |
| { |
| execute_flag = 0; |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| 0, K_USER, K_NO_WAIT); |
| |
| k_thread_abort(tid); |
| k_msleep(100); |
| /**TESTPOINT: check not-started thread is aborted*/ |
| zassert_true(execute_flag == 0, NULL); |
| |
| tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| 0, K_USER, K_NO_WAIT); |
| k_msleep(50); |
| k_thread_abort(tid); |
| /**TESTPOINT: check running thread is aborted*/ |
| zassert_true(execute_flag == 1, NULL); |
| k_msleep(1000); |
| zassert_true(execute_flag == 1, NULL); |
| } |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * @brief Test abort on a terminated thread |
| * |
| * @see k_thread_abort() |
| */ |
| void test_threads_abort_repeat(void) |
| { |
| execute_flag = 0; |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| thread_entry, NULL, NULL, NULL, |
| 0, K_USER, K_NO_WAIT); |
| |
| k_thread_abort(tid); |
| k_msleep(100); |
| k_thread_abort(tid); |
| k_msleep(100); |
| k_thread_abort(tid); |
| /* If no fault occurred till now. The test case passed. */ |
| ztest_test_pass(); |
| } |
| |
| bool abort_called; |
| void *block; |
| |
| static void delayed_thread_entry(void *p1, void *p2, void *p3) |
| { |
| execute_flag = 1; |
| |
| zassert_unreachable("Delayed thread shouldn't be executed"); |
| } |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * @brief Test abort on delayed thread before it has started |
| * execution |
| * |
| * @see k_thread_abort() |
| */ |
| void test_delayed_thread_abort(void) |
| { |
| int current_prio = k_thread_priority_get(k_current_get()); |
| |
| execute_flag = 0; |
| /* Make current thread preemptive */ |
| k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(2)); |
| |
| /* Create a preemptive thread of higher priority than |
| * current thread |
| */ |
| k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, |
| (k_thread_entry_t)delayed_thread_entry, NULL, NULL, NULL, |
| K_PRIO_PREEMPT(1), 0, K_MSEC(100)); |
| |
| /* Give up CPU */ |
| k_msleep(50); |
| |
| /* Test point: check if thread delayed for 100ms has not started*/ |
| zassert_true(execute_flag == 0, "Delayed thread created is not" |
| " put to wait queue"); |
| |
| k_thread_abort(tid); |
| |
| /* Test point: Test abort of thread before its execution*/ |
| zassert_false(execute_flag == 1, "Delayed thread is has executed" |
| " before cancellation"); |
| |
| /* Restore the priority */ |
| k_thread_priority_set(k_current_get(), current_prio); |
| } |
| |
| static volatile bool isr_finished; |
| |
| static void offload_func(const void *param) |
| { |
| struct k_thread *t = (struct k_thread *)param; |
| |
| k_thread_abort(t); |
| |
| /* k_thread_abort() in an isr shouldn't affect the ISR's execution */ |
| isr_finished = true; |
| } |
| |
| static void entry_abort_isr(void *p1, void *p2, void *p3) |
| { |
| /* Simulate taking an interrupt which kills this thread */ |
| irq_offload(offload_func, k_current_get()); |
| |
| printk("shouldn't see this, thread should have been killed"); |
| ztest_test_fail(); |
| } |
| |
| extern struct k_sem offload_sem; |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * |
| * @brief Show that threads can be aborted from interrupt context by itself |
| * |
| * @details Spwan a thread, then enter ISR context in child thread and abort |
| * the child thread. Check if ISR completed and target thread was aborted. |
| * |
| * @see k_thread_abort() |
| */ |
| void test_abort_from_isr(void) |
| { |
| isr_finished = false; |
| k_thread_create(&tdata, tstack, STACK_SIZE, entry_abort_isr, |
| NULL, NULL, NULL, 0, 0, K_NO_WAIT); |
| |
| |
| k_thread_join(&tdata, K_FOREVER); |
| zassert_true(isr_finished, "ISR did not complete"); |
| |
| /* Notice: Recover back the offload_sem: This is use for releasing |
| * offload_sem which might be held when thread aborts itself in ISR |
| * context, it will cause irq_offload cannot be used again. |
| */ |
| k_sem_give(&offload_sem); |
| } |
| |
| /* use for sync thread start */ |
| static struct k_sem sem_abort; |
| |
| static void entry_aborted_thread(void *p1, void *p2, void *p3) |
| { |
| k_sem_give(&sem_abort); |
| |
| /* wait for being aborted */ |
| while (1) { |
| k_sleep(K_MSEC(1)); |
| } |
| zassert_unreachable("should not reach here"); |
| } |
| |
| /** |
| * @ingroup kernel_thread_tests |
| * |
| * @brief Show that threads can be aborted from interrupt context |
| * |
| * @details Spwan a thread, then enter ISR context in main thread and abort |
| * the child thread. Check if ISR completed and target thread was aborted. |
| * |
| * @see k_thread_abort() |
| */ |
| void test_abort_from_isr_not_self(void) |
| { |
| k_tid_t tid; |
| |
| isr_finished = false; |
| k_sem_init(&sem_abort, 0, 1); |
| |
| tid = k_thread_create(&tdata, tstack, STACK_SIZE, entry_aborted_thread, |
| NULL, NULL, NULL, 0, 0, K_NO_WAIT); |
| |
| /* wait for thread started */ |
| k_sem_take(&sem_abort, K_FOREVER); |
| |
| /* Simulate taking an interrupt which kills spwan thread */ |
| irq_offload(offload_func, (void *)tid); |
| |
| k_thread_join(&tdata, K_FOREVER); |
| zassert_true(isr_finished, "ISR did not complete"); |
| } |