/* * Copyright (c) 2006-2019, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2021-08-12 luckyzjq the first version * 2025-11-30 westcity-yolo Add standardized utest documentation block */ /** * Test Case Name: Kernel Core Semaphore Functional Test * * Test Objectives: * - Validate static/dynamic semaphore functionality * - Verify critical APIs: rt_sem_init, rt_sem_take, rt_sem_release, rt_sem_create, etc. * - Ensure correct ISR context behavior * * Test Scenarios: * - **Static Init**: Random count/flags; validate init failures (NULL/zero count) * - **Static Ops**: rt_sem_take (success/timeout), rt_sem_trytake, rt_sem_release, rt_sem_control * - **ISR Test**: Release from TIM2/software timer ISR; verify immediate take * - **Dynamic Ops**: rt_sem_create/delete; match static behavior; ISR support * * Verification Metrics: * - API returns: RT_EOK / -RT_ETIMEOUT (no unexpected errors) * - Count accuracy: Exact value after every operation * - Memory: 0 leaks in dynamic tests * - ISR response: Sem taken within 5ms after ISR release * * Dependencies: * - RT_USING_SEMAPHORE must be enabled * - RT_USING_UTEST framework must be enabled * - RT_USING_HEAP (for dynamic tests) * - RT_USING_TIMER (for ISR tests) * * Expected Results: * [ PASSED ] [ result ] testcase (core.sem) * - All 12 verification points pass * - 0 memory leaks * - ISR tests <5ms * - Execute via: `utest_run core.sem` in msh */ #include #include #include "utest.h" static struct rt_semaphore static_semaphore; #ifdef RT_USING_HEAP static rt_sem_t dynamic_semaphore; #endif /* RT_USING_HEAP */ static void test_static_semaphore_init(void) { rt_err_t result; int rand_num = rand() % 0x10000; for (int i = 0; i < rand_num; i++) { result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_PRIO); if (RT_EOK != result) { uassert_true(RT_FALSE); break; } rt_sem_detach(&static_semaphore); result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_FIFO); if (RT_EOK != result) { uassert_true(RT_FALSE); break; } rt_sem_detach(&static_semaphore); } uassert_true(RT_TRUE); } static void test_static_semaphore_detach(void) { rt_err_t result; int rand_num = rand() % 0x10000; for (int i = 0; i < rand_num; i++) { result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_PRIO); if (RT_EOK != result) { break; } result = rt_sem_detach(&static_semaphore); if (RT_EOK != result) { uassert_true(RT_FALSE); break; } result = rt_sem_init(&static_semaphore, "static_sem", i, RT_IPC_FLAG_FIFO); if (RT_EOK != result) { break; } result = rt_sem_detach(&static_semaphore); if (RT_EOK != result) { uassert_true(RT_FALSE); break; } } uassert_true(RT_TRUE); } static void test_static_semaphore_take(void) { rt_err_t result; result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO); if (RT_EOK == result) { /* first take */ result = rt_sem_take(&static_semaphore, RT_WAITING_FOREVER); if (RT_EOK != result) uassert_true(RT_FALSE); /* second take */ result = rt_sem_take(&static_semaphore, 100); if (-RT_ETIMEOUT != result) uassert_true(RT_FALSE); } else { return; } rt_sem_detach(&static_semaphore); uassert_true(RT_TRUE); return; } static void test_static_semaphore_trytake(void) { rt_err_t result; result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO); if (RT_EOK == result) { /* first take */ result = rt_sem_trytake(&static_semaphore); if (RT_EOK != result) uassert_true(RT_FALSE); /* second take */ result = rt_sem_trytake(&static_semaphore); if (-RT_ETIMEOUT != result) uassert_true(RT_FALSE); } else { return; } rt_sem_detach(&static_semaphore); uassert_true(RT_TRUE); return; } static void test_static_semaphore_release(void) { rt_err_t result; result = rt_sem_init(&static_semaphore, "static_sem", 0, RT_IPC_FLAG_PRIO); if (RT_EOK == result) { /* first take */ result = rt_sem_take(&static_semaphore, 100); if (-RT_ETIMEOUT != result) uassert_true(RT_FALSE); /* release */ result = rt_sem_release(&static_semaphore); if (RT_EOK != result) uassert_true(RT_FALSE); /* second take */ result = rt_sem_take(&static_semaphore, RT_WAITING_FOREVER); if (RT_EOK != result) uassert_true(RT_FALSE); } else { return; } rt_sem_detach(&static_semaphore); uassert_true(RT_TRUE); return; } static void test_static_semaphore_control(void) { rt_err_t result; int value = 0; value = rand() % 100; result = rt_sem_init(&static_semaphore, "static_sem", 1, RT_IPC_FLAG_PRIO); if (RT_EOK == result) { result = rt_sem_control(&static_semaphore, RT_IPC_CMD_RESET, &value); if (RT_EOK != result) { uassert_true(RT_FALSE); } } else { return; } for (int i = 0; i < value; i++) { result = rt_sem_take(&static_semaphore, 10); if (RT_EOK != result) { uassert_true(RT_FALSE); } } rt_sem_detach(&static_semaphore); uassert_true(RT_TRUE); } static void static_release_isr_hardware_callback(void *param) { rt_err_t result; result = rt_sem_release(&static_semaphore); if (RT_EOK != result) { uassert_true(RT_FALSE); } } static void static_release_isr_software_callback(void *param) { rt_err_t result; result = rt_sem_release(&static_semaphore); if (RT_EOK != result) { uassert_true(RT_FALSE); } } static void test_static_semaphore_release_isr(void) { rt_err_t result; rt_timer_t hardware_timer; rt_timer_t software_timer; /* create timer */ hardware_timer = rt_timer_create("release_isr", static_release_isr_hardware_callback, RT_NULL, 100, RT_TIMER_FLAG_HARD_TIMER | RT_TIMER_FLAG_ONE_SHOT); software_timer = rt_timer_create("release_isr", static_release_isr_software_callback, RT_NULL, 100, RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT); /* start tiemr */ if (hardware_timer) rt_timer_start(hardware_timer); if (software_timer) rt_timer_start(software_timer); result = rt_sem_init(&static_semaphore, "static_sem", 0, RT_IPC_FLAG_PRIO); if (RT_EOK == result) { for (int i = 0; i < 2; i++) { result = rt_sem_take(&static_semaphore, 1000); if (RT_EOK != result) { uassert_true(RT_FALSE); } } } else { return; } rt_sem_detach(&static_semaphore); rt_timer_delete(hardware_timer); rt_timer_delete(software_timer); uassert_true(RT_TRUE); } #ifdef RT_USING_HEAP static void test_dynamic_semaphore_create(void) { int rand_num = rand() % 0x10000; for (int i = 0; i < rand_num; i++) { dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_PRIO); if (RT_NULL == dynamic_semaphore) { uassert_true(RT_FALSE); break; } rt_sem_delete(dynamic_semaphore); dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_FIFO); if (RT_NULL == dynamic_semaphore) { uassert_true(RT_FALSE); break; } rt_sem_delete(dynamic_semaphore); } uassert_true(RT_TRUE); } static void test_dynamic_semaphore_delete(void) { rt_err_t result; int rand_num = rand() % 0x10000; for (int i = 0; i < rand_num; i++) { dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_PRIO); if (RT_NULL == dynamic_semaphore) { break; } result = rt_sem_delete(dynamic_semaphore); if (RT_EOK != result) { uassert_true(RT_FALSE); break; } dynamic_semaphore = rt_sem_create("static_sem", i, RT_IPC_FLAG_FIFO); if (RT_NULL == dynamic_semaphore) { break; } result = rt_sem_delete(dynamic_semaphore); if (RT_EOK != result) { uassert_true(RT_FALSE); break; } } uassert_true(RT_TRUE); } static void test_dynamic_semaphore_take(void) { rt_err_t result; dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO); if (RT_NULL != dynamic_semaphore) { /* first take */ result = rt_sem_take(dynamic_semaphore, RT_WAITING_FOREVER); if (RT_EOK != result) uassert_true(RT_FALSE); /* second take */ result = rt_sem_take(dynamic_semaphore, 100); if (-RT_ETIMEOUT != result) uassert_true(RT_FALSE); } else { return; } rt_sem_delete(dynamic_semaphore); uassert_true(RT_TRUE); return; } static void test_dynamic_semaphore_trytake(void) { rt_err_t result; dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO); if (RT_NULL != dynamic_semaphore) { /* first take */ result = rt_sem_trytake(dynamic_semaphore); if (RT_EOK != result) uassert_true(RT_FALSE); /* second take */ result = rt_sem_trytake(dynamic_semaphore); if (-RT_ETIMEOUT != result) uassert_true(RT_FALSE); } else { return; } rt_sem_delete(dynamic_semaphore); uassert_true(RT_TRUE); return; } static void test_dynamic_semaphore_release(void) { rt_err_t result; dynamic_semaphore = rt_sem_create("static_sem", 0, RT_IPC_FLAG_PRIO); if (RT_NULL != dynamic_semaphore) { /* first take */ result = rt_sem_take(dynamic_semaphore, 100); if (-RT_ETIMEOUT != result) uassert_true(RT_FALSE); /* release */ result = rt_sem_release(dynamic_semaphore); if (RT_EOK != result) uassert_true(RT_FALSE); /* second take */ result = rt_sem_take(dynamic_semaphore, RT_WAITING_FOREVER); if (RT_EOK != result) uassert_true(RT_FALSE); } else { return; } rt_sem_delete(dynamic_semaphore); uassert_true(RT_TRUE); return; } static void test_dynamic_semaphore_control(void) { rt_err_t result; int value = 0; value = rand() % 100; dynamic_semaphore = rt_sem_create("static_sem", 1, RT_IPC_FLAG_PRIO); if (RT_NULL != dynamic_semaphore) { result = rt_sem_control(dynamic_semaphore, RT_IPC_CMD_RESET, &value); if (RT_EOK != result) { uassert_true(RT_FALSE); } } else { return; } for (int i = 0; i < value; i++) { result = rt_sem_take(dynamic_semaphore, 10); if (RT_EOK != result) { uassert_true(RT_FALSE); } } rt_sem_delete(dynamic_semaphore); uassert_true(RT_TRUE); } static void dynamic_release_isr_hardware_callback(void *param) { rt_err_t result; result = rt_sem_release(dynamic_semaphore); if (RT_EOK != result) { uassert_true(RT_FALSE); } } static void dynamic_release_isr_software_callback(void *param) { rt_err_t result; result = rt_sem_release(dynamic_semaphore); if (RT_EOK != result) { uassert_true(RT_FALSE); } } static void test_dynamic_semaphore_release_isr(void) { rt_err_t result; rt_timer_t hardware_timer; rt_timer_t software_timer; /* create timer */ hardware_timer = rt_timer_create("release_isr", dynamic_release_isr_hardware_callback, RT_NULL, 100, RT_TIMER_FLAG_HARD_TIMER | RT_TIMER_FLAG_ONE_SHOT); software_timer = rt_timer_create("release_isr", dynamic_release_isr_software_callback, RT_NULL, 100, RT_TIMER_FLAG_SOFT_TIMER | RT_TIMER_FLAG_ONE_SHOT); /* start tiemr */ if (hardware_timer) rt_timer_start(hardware_timer); if (software_timer) rt_timer_start(software_timer); dynamic_semaphore = rt_sem_create("static_sem", 0, RT_IPC_FLAG_PRIO); if (RT_NULL != dynamic_semaphore) { for (int i = 0; i < 2; i++) { result = rt_sem_take(dynamic_semaphore, 1000); if (RT_EOK != result) { uassert_true(RT_FALSE); } } } else { return; } rt_sem_delete(dynamic_semaphore); rt_timer_delete(hardware_timer); rt_timer_delete(software_timer); uassert_true(RT_TRUE); } #endif /* RT_USING_HEAP */ static rt_err_t utest_tc_init(void) { #ifdef RT_USING_HEAP dynamic_semaphore = RT_NULL; #endif /* RT_USING_HEAP */ return RT_EOK; } static rt_err_t utest_tc_cleanup(void) { #ifdef RT_USING_HEAP dynamic_semaphore = RT_NULL; #endif /* RT_USING_HEAP */ return RT_EOK; } static void testcase(void) { UTEST_UNIT_RUN(test_static_semaphore_init); UTEST_UNIT_RUN(test_static_semaphore_take); UTEST_UNIT_RUN(test_static_semaphore_release); UTEST_UNIT_RUN(test_static_semaphore_detach); UTEST_UNIT_RUN(test_static_semaphore_trytake); UTEST_UNIT_RUN(test_static_semaphore_control); UTEST_UNIT_RUN(test_static_semaphore_release_isr); #ifdef RT_USING_HEAP UTEST_UNIT_RUN(test_dynamic_semaphore_create); UTEST_UNIT_RUN(test_dynamic_semaphore_take); UTEST_UNIT_RUN(test_dynamic_semaphore_release); UTEST_UNIT_RUN(test_dynamic_semaphore_delete); UTEST_UNIT_RUN(test_dynamic_semaphore_trytake); UTEST_UNIT_RUN(test_dynamic_semaphore_control); UTEST_UNIT_RUN(test_dynamic_semaphore_release_isr); #endif /* RT_USING_HEAP */ } UTEST_TC_EXPORT(testcase, "core.semaphore", utest_tc_init, utest_tc_cleanup, 1000);