diff --git a/FreeRTOS/Test/Target/boards/pico/tests/smp/interrupt_wait_critical/CMakeLists.txt b/FreeRTOS/Test/Target/boards/pico/tests/smp/interrupt_wait_critical/CMakeLists.txt new file mode 100644 index 0000000000..8a889c5318 --- /dev/null +++ b/FreeRTOS/Test/Target/boards/pico/tests/smp/interrupt_wait_critical/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.13) + +set(TEST_INCLUDE_PATHS ${CMAKE_CURRENT_LIST_DIR}/../../../../../tests/smp/interrupt_wait_critical) +set(TEST_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../../tests/smp/interrupt_wait_critical) + +add_library(interrupt_wait_critical INTERFACE) +target_sources(interrupt_wait_critical INTERFACE + ${BOARD_LIBRARY_DIR}/main.c + ${CMAKE_CURRENT_LIST_DIR}/interrupt_wait_critical_test_runner.c + ${TEST_SOURCE_DIR}/interrupt_wait_critical.c) + +target_include_directories(interrupt_wait_critical INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/../../.. + ${TEST_INCLUDE_PATHS} + ) + +target_link_libraries(interrupt_wait_critical INTERFACE + FreeRTOS-Kernel + FreeRTOS-Kernel-Heap4 + ${BOARD_LINK_LIBRARIES}) + +add_executable(test_interrupt_wait_critical) +enable_board_functions(test_interrupt_wait_critical) +target_link_libraries(test_interrupt_wait_critical interrupt_wait_critical) +target_include_directories(test_interrupt_wait_critical PUBLIC + ${BOARD_INCLUDE_PATHS}) +target_compile_definitions(test_interrupt_wait_critical PRIVATE + ${BOARD_DEFINES} +) diff --git a/FreeRTOS/Test/Target/boards/pico/tests/smp/interrupt_wait_critical/interrupt_wait_critical_test_runner.c b/FreeRTOS/Test/Target/boards/pico/tests/smp/interrupt_wait_critical/interrupt_wait_critical_test_runner.c new file mode 100644 index 0000000000..00dbcbda16 --- /dev/null +++ b/FreeRTOS/Test/Target/boards/pico/tests/smp/interrupt_wait_critical/interrupt_wait_critical_test_runner.c @@ -0,0 +1,75 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/** + * @file only_one_task_enter_critical_test_runner.c + * @brief The implementation of main function to start test runner task. + * + * Procedure: + * - Initialize environment. + * - Run the test case. + */ + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Unit testing support functions. */ +#include "unity.h" + +/* Pico includes. */ +#include "pico/multicore.h" +#include "pico/stdlib.h" + +/*-----------------------------------------------------------*/ + +static void prvTestRunnerTask( void * pvParameters ); + +extern void vRunInterruptWaitCriticalTest( void ); + +/*-----------------------------------------------------------*/ + +static void prvTestRunnerTask( void * pvParameters ) +{ + ( void ) pvParameters; + + /* Run test case. */ + vRunInterruptWaitCriticalTest(); + + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +void vRunTest( void ) +{ + xTaskCreate( prvTestRunnerTask, + "testRunner", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 1, + NULL ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Test/Target/tests/smp/interrupt_wait_critical/interrupt_wait_critical.c b/FreeRTOS/Test/Target/tests/smp/interrupt_wait_critical/interrupt_wait_critical.c new file mode 100644 index 0000000000..fd0485c57b --- /dev/null +++ b/FreeRTOS/Test/Target/tests/smp/interrupt_wait_critical/interrupt_wait_critical.c @@ -0,0 +1,341 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +/** + * @file interrupt_wait_critical.c + * @brief If a task is interrupted while it is waiting to enter a critical + * section, it shall relinquish the core instead of continuing to wait to + * enter the critical section. + * + * Procedure: + * - Create 1 low priority task, T0. + * - Create n - 1 high priority tasks, T1~Tn-1. + * - Create 1 high priority task, Tn. + * - Tasks T1~Tn-1 suspends themselves. + * - Tn enters critical section. + * - T0 attempts to enter critical section and busy waits to enter + * critical section. + * - Tn resumes tasks T1-Tn-1. + * - At this point, tasks T1-Tn are ready and must be running. As a result, T0 + * - must have been interrupted while busy waiting to enter critical section. + * - Tn leaves critical section. + * Expected: + * - T0 must not enter the critical section as it was interrupted while busy + * waiting to enter critical section. + */ + +/* Standard includes. */ +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Unit testing support functions. */ +#include "unity.h" +/*-----------------------------------------------------------*/ + +/** + * @brief Busy looping count to wait for other cores. + */ +#define TEST_BUSY_LOOPING_COUNT ( 10000U ) + +/** + * @brief Nop operation for busy looping. + */ +#ifdef portNOP + #define TEST_NOP portNOP +#else + #define TEST_NOP() __asm volatile ( "nop" ) +#endif + +/** + * @brief Timeout value to stop test. + */ +#define TEST_TIMEOUT_MS ( 1000 ) +/*-----------------------------------------------------------*/ + +#if ( configNUMBER_OF_CORES < 2 ) + #error This test is for FreeRTOS SMP and therefore, requires at least 2 cores. +#endif /* if ( configNUMBER_OF_CORES < 2 ) */ + +#if ( configRUN_MULTIPLE_PRIORITIES != 1 ) + #error configRUN_MULTIPLE_PRIORITIES must be enabled by including test_config.h in FreeRTOSConfig.h. +#endif /* if ( configRUN_MULTIPLE_PRIORITIES != 1 ) */ + +#if ( configMAX_PRIORITIES <= 3 ) + #error configMAX_PRIORITIES must be larger than 3 to avoid scheduling idle tasks unexpectedly. +#endif /* if ( configMAX_PRIORITIES <= 3 ) */ +/*-----------------------------------------------------------*/ + +/** + * @brief Low priority task function that tries to enter critical section. + */ +static void prvLowPriorityEnterCriticalTask( void * pvParameters ); + +/** + * @brief High priority task function that tries to enter critical section. + */ +static void prvHighPriorityEnterCriticalTask( void * pvParameters ); + +/** + * @brief Function that implements a never blocking FreeRTOS task. + */ +static void prvEverRunningTask( void * pvParameters ); + +/** + * @brief Test case "Interrupt Wait Critical". + */ +void Test_InterruptWaitCritical( void ); +/*-----------------------------------------------------------*/ + +/** + * @brief Handles of the tasks created in this test. + */ +static TaskHandle_t xTaskHandles[ configNUMBER_OF_CORES + 1 ]; + +/** + * @brief A flag to trace if high priority task entered critical section. + */ +static volatile BaseType_t xHighPriorityTaskEnterCriticalSection = pdFALSE; + +/** + * @brief A flag to trace if low priority task entered critical section. + */ +static volatile BaseType_t xLowPriorityTaskEnterCriticalSection = pdFALSE; +/*-----------------------------------------------------------*/ + +static void prvEverRunningTask( void * pvParameters ) +{ + /* Silence warnings about unused parameters. */ + ( void ) pvParameters; + + vTaskSuspend( NULL ); + + for( ; ; ) + { + TEST_NOP(); + } +} +/*-----------------------------------------------------------*/ + +static void prvLowPriorityEnterCriticalTask( void * pvParameters ) +{ + /* Silence warnings about unused parameters. */ + ( void ) pvParameters; + + /* Wait for the high priority task Tn to enter the critical section first. */ + while( xHighPriorityTaskEnterCriticalSection == pdFALSE ) + { + } + + /* The high priority task Tn is inside the critical section. So this low + * priority task must busy wait here to enter critical section. Tn resumes + * tasks T1~Tn-1 from within the critical section. As a result, n tasks + * T1~Tn are ready to run when this task is busy waiting here to enter + * critical section. Since n higher priority tasks are ready, this low + * priority task must be interrupted and relinquish the core. */ + taskENTER_CRITICAL(); + { + /* As this task must relinquish this core instead of entering the + * critical section, this line must not be run. */ + xLowPriorityTaskEnterCriticalSection = pdTRUE; + } + taskEXIT_CRITICAL(); + + for( ; ; ) + { + TEST_NOP(); + } +} +/*-----------------------------------------------------------*/ + +static void prvHighPriorityEnterCriticalTask( void * pvParameters ) +{ + uint32_t i; + eTaskState taskState; + BaseType_t xAllTasksInExpectedState = pdFALSE; + + /* Silence warnings about unused parameters. */ + ( void ) pvParameters; + + /* Check that low priority task T0 is running and high priority tasks + * T1~Tn-1 are suspended. */ + while( xAllTasksInExpectedState == pdFALSE ) + { + /* Check the state of low priority task T0. */ + taskState = eTaskGetState( xTaskHandles[ 0 ] ); + + if( taskState == eRunning ) + { + /* Check the state of high priority tasks T1~Tn-1. */ + for( i = 1; i < configNUMBER_OF_CORES; i++ ) + { + taskState = eTaskGetState( xTaskHandles[ i ] ); + + if( taskState != eSuspended ) + { + break; + } + } + + if( i == configNUMBER_OF_CORES ) + { + xAllTasksInExpectedState = pdTRUE; + } + } + } + + taskENTER_CRITICAL(); + { + xHighPriorityTaskEnterCriticalSection = pdTRUE; + + /* Busy looping here to wait for low priority task. */ + for( i = 0; i < TEST_BUSY_LOOPING_COUNT; i++ ) + { + TEST_NOP(); + } + + /* Resume tasks T1~Tn-1. All the n cores must be occupied by tasks T1~Tn + * as these are higher priority tasks. The low priority task T0 which is + * busy waiting to enter critical section, must be interrupted. */ + for( i = 1; i < configNUMBER_OF_CORES; i++ ) + { + vTaskResume( xTaskHandles[ i ] ); + } + } + taskEXIT_CRITICAL(); + + for( ; ; ) + { + /* Always running, put asm here to avoid optimization by compiler. */ + TEST_NOP(); + } +} +/*-----------------------------------------------------------*/ + +void Test_InterruptWaitCritical( void ) +{ + uint32_t i; + BaseType_t xTaskCreationResult; + + /* Create one task T0 with low priority. */ + xTaskCreationResult = xTaskCreate( prvLowPriorityEnterCriticalTask, + "EnterCSLow", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 3, + &( xTaskHandles[ 0 ] ) ); + + TEST_ASSERT_EQUAL_MESSAGE( pdPASS, xTaskCreationResult, "Task creation failed." ); + + /* Create ( configNUMBER_OF_CORES - 1 ) tasks T1-Tn-1 with high priority. */ + for( i = 1; i < configNUMBER_OF_CORES; i++ ) + { + xTaskCreationResult = xTaskCreate( prvEverRunningTask, + "EverRunning", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 2, + &( xTaskHandles[ i ] ) ); + + TEST_ASSERT_EQUAL_MESSAGE( pdPASS, xTaskCreationResult, "Task creation failed." ); + } + + /* Create one task Tn with high priority. */ + xTaskCreationResult = xTaskCreate( prvHighPriorityEnterCriticalTask, + "EnterCSHigh", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 2, + &( xTaskHandles[ configNUMBER_OF_CORES ] ) ); + + TEST_ASSERT_EQUAL_MESSAGE( pdPASS, xTaskCreationResult, "Task creation failed." ); + + vTaskDelay( pdMS_TO_TICKS( TEST_TIMEOUT_MS ) ); + + /* Verify the high priority task entered the critical section. */ + TEST_ASSERT_EQUAL_MESSAGE( pdTRUE, xHighPriorityTaskEnterCriticalSection, "High priority task not enter the critical section." ); + + /* Verify the low priority task relinquishes the core when it is interrupted + * while waiting to enter a critical section. */ + TEST_ASSERT_EQUAL_MESSAGE( pdFALSE, xLowPriorityTaskEnterCriticalSection, "Low priority task should relinquish the core." ); + + /* Suspend the high priority task Tn and block the test runner. The low + * priority task should be able to enter the critical section now due to a + * core being available. */ + vTaskSuspend( xTaskHandles[ configNUMBER_OF_CORES ] ); + vTaskDelay( pdMS_TO_TICKS( TEST_TIMEOUT_MS ) ); + + /* Verify the low priority task was able to enter the critical section. */ + TEST_ASSERT_EQUAL_MESSAGE( pdTRUE, xLowPriorityTaskEnterCriticalSection, "Low priority task should enter the critical section." ); +} +/*-----------------------------------------------------------*/ + +/* Runs before every test, put init calls here. */ +void setUp( void ) +{ + uint32_t i; + + for( i = 0U; i < ( configNUMBER_OF_CORES + 1 ); i++ ) + { + xTaskHandles[ i ] = NULL; + } + + xHighPriorityTaskEnterCriticalSection = pdFALSE; + xLowPriorityTaskEnterCriticalSection = pdFALSE; +} +/*-----------------------------------------------------------*/ + +/* Runs after every test, put clean-up calls here. */ +void tearDown( void ) +{ + uint32_t i; + + /* Delete all the tasks. */ + for( i = 0; i < ( configNUMBER_OF_CORES + 1 ); i++ ) + { + if( xTaskHandles[ i ] != NULL ) + { + vTaskDelete( xTaskHandles[ i ] ); + xTaskHandles[ i ] = NULL; + } + } +} +/*-----------------------------------------------------------*/ + +/** + * @brief Entry point for test runner to run interrupt task wait critical section test. + */ +void vRunInterruptWaitCriticalTest( void ) +{ + UNITY_BEGIN(); + + RUN_TEST( Test_InterruptWaitCritical ); + + UNITY_END(); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Test/Target/tests/smp/interrupt_wait_critical/test_config.h b/FreeRTOS/Test/Target/tests/smp/interrupt_wait_critical/test_config.h new file mode 100644 index 0000000000..150d0f0ba8 --- /dev/null +++ b/FreeRTOS/Test/Target/tests/smp/interrupt_wait_critical/test_config.h @@ -0,0 +1,58 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * https://www.FreeRTOS.org + * https://github.com/FreeRTOS + * + */ + +#ifndef TEST_CONFIG_H +#define TEST_CONFIG_H + +/* This file must be included at the end of the FreeRTOSConfig.h. It contains + * any FreeRTOS specific configurations that the test requires. */ + +#ifdef configRUN_MULTIPLE_PRIORITIES + #undef configRUN_MULTIPLE_PRIORITIES +#endif /* ifdef configRUN_MULTIPLE_PRIORITIES */ + +#ifdef configUSE_TIME_SLICING + #undef configUSE_TIME_SLICING +#endif /* ifdef configUSE_TIME_SLICING */ + +#ifdef configUSE_PREEMPTION + #undef configUSE_PREEMPTION +#endif /* ifdef configUSE_PREEMPTION */ + +#define configRUN_MULTIPLE_PRIORITIES 1 +#define configUSE_TIME_SLICING 1 +#define configUSE_PREEMPTION 1 + +/*-----------------------------------------------------------*/ + +/** + * @brief Entry point for test runner to run interrupt task wait critical section test. + */ +void vRunInterruptWaitCriticalTest( void ); + +/*-----------------------------------------------------------*/ + +#endif /* ifndef TEST_CONFIG_H */