| /* |
| * Copyright (c) 2018,2022 Intel Corporation. |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| #include "zephyr/ztest_test_new.h" |
| #include <zephyr/kernel.h> |
| #include <zephyr/ztest.h> |
| #include <zephyr/spinlock.h> |
| |
| BUILD_ASSERT(CONFIG_MP_MAX_NUM_CPUS > 1); |
| |
| static struct k_spinlock lock; |
| static struct k_spinlock mylock; |
| static k_spinlock_key_t key; |
| |
| /* Like all spin locks in Zephyr (and things that directly hold them), this must |
| * be placed globally in code paths that intel_adsp runs to be valid. Even if |
| * only used in a local function context as is the case here when SPIN_VALIDATE |
| * and KERNEL_COHERENCE are enabled. |
| * |
| * When both are enabled a check to verify that a spin lock is placed |
| * in coherent (uncached) memory is done and asserted on. Spin locks placed |
| * on a stack will fail on platforms where KERNEL_COHERENCE is needed such |
| * as intel_adsp. |
| * |
| * See kernel/Kconfig KERNEL_COHERENCE and subsys/debug/Kconfig SPIN_VALIDATE |
| * for more details. |
| */ |
| #ifdef CONFIG_SPIN_LOCK_TIME_LIMIT |
| static struct k_spinlock timeout_lock; |
| #endif |
| |
| |
| static ZTEST_DMEM volatile bool valid_assert; |
| static ZTEST_DMEM volatile bool unlock_after_assert; |
| |
| |
| static inline void set_assert_valid(bool valid, bool unlock) |
| { |
| valid_assert = valid; |
| unlock_after_assert = unlock; |
| } |
| |
| static void action_after_assert_fail(void) |
| { |
| if (unlock_after_assert) { |
| k_spin_unlock(&lock, key); |
| } |
| |
| ztest_test_pass(); |
| } |
| |
| #ifdef CONFIG_ASSERT_NO_FILE_INFO |
| void assert_post_action(void) |
| #else |
| void assert_post_action(const char *file, unsigned int line) |
| #endif |
| { |
| #ifndef CONFIG_ASSERT_NO_FILE_INFO |
| ARG_UNUSED(file); |
| ARG_UNUSED(line); |
| #endif |
| |
| printk("Caught an assert.\n"); |
| |
| if (valid_assert) { |
| valid_assert = false; /* reset back to normal */ |
| printk("Assert error expected as part of test case.\n"); |
| |
| /* do some action after fatal error happened */ |
| action_after_assert_fail(); |
| } else { |
| printk("Assert failed was unexpected, aborting...\n"); |
| #ifdef CONFIG_USERSPACE |
| /* User threads aren't allowed to induce kernel panics; generate |
| * an oops instead. |
| */ |
| if (k_is_user_context()) { |
| k_oops(); |
| } |
| #endif |
| k_panic(); |
| } |
| } |
| |
| |
| /** |
| * @brief Test spinlock cannot be recursive |
| * |
| * @details Validate using spinlock recursive will trigger assertion. |
| * |
| * @ingroup kernel_spinlock_tests |
| * |
| * @see k_spin_lock() |
| */ |
| ZTEST(spinlock, test_spinlock_no_recursive) |
| { |
| k_spinlock_key_t re; |
| |
| key = k_spin_lock(&lock); |
| |
| set_assert_valid(true, true); |
| re = k_spin_lock(&lock); |
| |
| ztest_test_fail(); |
| } |
| |
| /** |
| * @brief Test unlocking incorrect spinlock |
| * |
| * @details Validate unlocking incorrect spinlock will trigger assertion. |
| * |
| * @ingroup kernel_spinlock_tests |
| * |
| * @see k_spin_unlock() |
| */ |
| ZTEST(spinlock, test_spinlock_unlock_error) |
| { |
| key = k_spin_lock(&lock); |
| |
| set_assert_valid(true, true); |
| k_spin_unlock(&mylock, key); |
| |
| ztest_test_fail(); |
| } |
| |
| /** |
| * @brief Test unlocking incorrect spinlock |
| * |
| * @details Validate unlocking incorrect spinlock will trigger assertion. |
| * |
| * @ingroup kernel_spinlock_tests |
| * |
| * @see k_spin_release() |
| */ |
| ZTEST(spinlock, test_spinlock_release_error) |
| { |
| key = k_spin_lock(&lock); |
| |
| set_assert_valid(true, true); |
| k_spin_release(&mylock); |
| |
| ztest_test_fail(); |
| } |
| |
| |
| /** |
| * @brief Test unlocking spinlock held over the time limit |
| * |
| * @details Validate unlocking spinlock held past the time limit will trigger |
| * assertion. |
| * |
| * @ingroup kernel_spinlock_tests |
| * |
| * @see k_spin_unlock() |
| */ |
| ZTEST(spinlock, test_spinlock_lock_time_limit) |
| { |
| #ifndef CONFIG_SPIN_LOCK_TIME_LIMIT |
| ztest_test_skip(); |
| return; |
| #else |
| if (CONFIG_SPIN_LOCK_TIME_LIMIT == 0) { |
| ztest_test_skip(); |
| return; |
| } |
| |
| |
| |
| TC_PRINT("testing lock time limit, limit is %d!\n", CONFIG_SPIN_LOCK_TIME_LIMIT); |
| |
| |
| key = k_spin_lock(&timeout_lock); |
| |
| /* spin here a while, the spin lock limit is in terms of system clock |
| * not core clock. So a multiplier is needed here to ensure things |
| * go well past the time limit. |
| */ |
| for (volatile int i = 0; i < CONFIG_SPIN_LOCK_TIME_LIMIT*10; i++) { |
| } |
| |
| set_assert_valid(true, false); |
| k_spin_unlock(&timeout_lock, key); |
| |
| ztest_test_fail(); |
| #endif |
| } |