diff --git a/FreeRTOS/Test/Target/boards/pico/tests/smp/only_one_task_enter_critical/CMakeLists.txt b/FreeRTOS/Test/Target/boards/pico/tests/smp/only_one_task_enter_critical/CMakeLists.txt new file mode 100644 index 000000000..e55e3f262 --- /dev/null +++ b/FreeRTOS/Test/Target/boards/pico/tests/smp/only_one_task_enter_critical/CMakeLists.txt @@ -0,0 +1,33 @@ +cmake_minimum_required(VERSION 3.13) + +project(example C CXX ASM) +set(CMAKE_C_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) + +set(TEST_INCLUDE_PATHS ${CMAKE_CURRENT_LIST_DIR}/../../../../../tests/smp/only_one_task_enter_critical) +set(TEST_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../../tests/smp/only_one_task_enter_critical) + +add_library(only_one_task_enter_critical INTERFACE) +target_sources(only_one_task_enter_critical INTERFACE + ${BOARD_LIBRARY_DIR}/main.c + ${CMAKE_CURRENT_LIST_DIR}/only_one_task_enter_critical_test_runner.c + ${TEST_SOURCE_DIR}/only_one_task_enter_critical.c) + +target_include_directories(only_one_task_enter_critical INTERFACE + ${CMAKE_CURRENT_LIST_DIR}/../../.. + ${TEST_INCLUDE_PATHS} + ) + +target_link_libraries(only_one_task_enter_critical INTERFACE + FreeRTOS-Kernel + FreeRTOS-Kernel-Heap4 + ${BOARD_LINK_LIBRARIES}) + +add_executable(test_only_one_task_enter_critical) +enable_board_functions(test_only_one_task_enter_critical) +target_link_libraries(test_only_one_task_enter_critical only_one_task_enter_critical) +target_include_directories(test_only_one_task_enter_critical PUBLIC + ${BOARD_INCLUDE_PATHS}) +target_compile_definitions(test_only_one_task_enter_critical PRIVATE + ${BOARD_DEFINES} +) diff --git a/FreeRTOS/Test/Target/boards/pico/tests/smp/only_one_task_enter_critical/only_one_task_enter_critical_test_runner.c b/FreeRTOS/Test/Target/boards/pico/tests/smp/only_one_task_enter_critical/only_one_task_enter_critical_test_runner.c new file mode 100644 index 000000000..32ba84980 --- /dev/null +++ b/FreeRTOS/Test/Target/boards/pico/tests/smp/only_one_task_enter_critical/only_one_task_enter_critical_test_runner.c @@ -0,0 +1,73 @@ +/* + * 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 ); + +/*-----------------------------------------------------------*/ + +static void prvTestRunnerTask( void * pvParameters ) +{ + ( void ) pvParameters; + + /* Run test case. */ + vRunOnlyOneTaskEnterCriticalTest(); + + vTaskDelete( NULL ); +} +/*-----------------------------------------------------------*/ + +void vRunTest( void ) +{ + xTaskCreate( prvTestRunnerTask, + "testRunner", + configMINIMAL_STACK_SIZE, + NULL, + configMAX_PRIORITIES - 1, + NULL ); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Test/Target/tests/smp/only_one_task_enter_critical/only_one_task_enter_critical.c b/FreeRTOS/Test/Target/tests/smp/only_one_task_enter_critical/only_one_task_enter_critical.c new file mode 100644 index 000000000..f789312ae --- /dev/null +++ b/FreeRTOS/Test/Target/tests/smp/only_one_task_enter_critical/only_one_task_enter_critical.c @@ -0,0 +1,244 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 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.c + * @brief Only one task/ISR shall be able to enter critical section at a time. + * + * Procedure: + * - Create ( num of cores ) tasks. + * - All tasks increase the counter for TASK_INCREASE_COUNTER_TIMES times in + * critical section. + * Expected: + * - All tasks have correct value of counter after increasing. + */ + +/* Standard includes. */ +#include + +/* Kernel includes. */ +#include "FreeRTOS.h" +#include "task.h" + +/* Unit testing support functions. */ +#include "unity.h" +/*-----------------------------------------------------------*/ + +/** + * @brief As time of loop for task to increase counter. + */ +#define TASK_INCREASE_COUNTER_TIMES ( 1000000 ) + +/** + * @brief Timeout value to stop test. + */ +#define TEST_TIMEOUT_MS ( 1000 ) +/*-----------------------------------------------------------*/ + +/** + * @brief Test case "Only One Task Enter Critical". + */ +void Test_OnlyOneTaskEnterCritical( void ); + +/** + * @brief Task function to increase counter then keep delaying. + */ +static void prvTaskIncCounter( void * pvParameters ); +/*-----------------------------------------------------------*/ + +#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 ( configMAX_PRIORITIES <= 2 ) + #error configMAX_PRIORITIES must be larger than 2 to avoid scheduling idle tasks unexpectedly. +#endif /* if ( configMAX_PRIORITIES <= 2 ) */ +/*-----------------------------------------------------------*/ + +/** + * @brief Handles of the tasks created in this test. + */ +static TaskHandle_t xTaskHandles[ configNUMBER_OF_CORES ]; + +/** + * @brief Indexes of the tasks created in this test. + */ +static uint32_t xTaskIndexes[ configNUMBER_OF_CORES ]; + +/** + * @brief Flags to indicate if task T0 ~ T(n - 1) finish or not. + */ +static BaseType_t xTaskTestResults[ configNUMBER_OF_CORES ]; + +/** + * @brief Variables to indicate task is ready for testing. + */ +static volatile BaseType_t xTaskReady[ configNUMBER_OF_CORES ]; + +/** + * @brief Counter for all tasks to increase. + */ +static volatile uint32_t xTaskCounter; +/*-----------------------------------------------------------*/ + +static void prvTaskIncCounter( void * pvParameters ) +{ + uint32_t currentTaskIdx = *( ( uint32_t * ) pvParameters ); + BaseType_t xAllTaskReady = pdFALSE; + BaseType_t xTestResult = pdPASS; + uint32_t xTempTaskCounter = 0; + uint32_t i; + + /* Ensure all test tasks are running in the task function. */ + xTaskReady[ currentTaskIdx ] = pdTRUE; + + while( xAllTaskReady == pdFALSE ) + { + xAllTaskReady = pdTRUE; + + for( i = 0; i < configNUMBER_OF_CORES; i++ ) + { + if( xTaskReady[ i ] != pdTRUE ) + { + xAllTaskReady = pdFALSE; + break; + } + } + } + + /* Increase the test counter in the loop. The test expects only one task + * can increase the shared variable xTaskCounter protected by the critical + * section at the same time. */ + taskENTER_CRITICAL(); + { + xTempTaskCounter = xTaskCounter; + + for( i = 0; i < TASK_INCREASE_COUNTER_TIMES; i++ ) + { + /* Increase the local variable xTempTaskCounter and shared variable + * xTaskCounter. They must have the same value in the critical + * section. */ + xTaskCounter++; + xTempTaskCounter++; + + /* If multiple tasks enter the critical section, the shared variable + * xTaskCounter will be increased by multiple tasks.As a result, the + * local variable xTempTaskCounter won't be equal to the shared + * variable xTaskCounter. */ + if( xTaskCounter != xTempTaskCounter ) + { + xTestResult = pdFAIL; + break; + } + } + } + taskEXIT_CRITICAL(); + + xTaskTestResults[ currentTaskIdx ] = xTestResult; + + /* Blocking the test task. */ + vTaskDelay( portMAX_DELAY ); +} +/*-----------------------------------------------------------*/ + +void Test_OnlyOneTaskEnterCritical( void ) +{ + uint32_t i; + BaseType_t xTaskCreationResult; + + /* Create configNUMBER_OF_CORES low priority tasks. */ + for( i = 0; i < configNUMBER_OF_CORES; i++ ) + { + xTaskCreationResult = xTaskCreate( prvTaskIncCounter, + "IncCounter", + configMINIMAL_STACK_SIZE, + &( xTaskIndexes[ i ] ), + configMAX_PRIORITIES - 2, + &( xTaskHandles[ i ] ) ); + + TEST_ASSERT_EQUAL_MESSAGE( pdPASS, xTaskCreationResult, "Task creation failed." ); + } + + /* Delay for other cores to run tasks. */ + vTaskDelay( pdMS_TO_TICKS( TEST_TIMEOUT_MS ) ); + + /* Verify each test task result. */ + for( i = 0; i < configNUMBER_OF_CORES; i++ ) + { + TEST_ASSERT_EQUAL_MESSAGE( pdPASS, xTaskTestResults[ i ], "Critical section test task failed." ); + } + + /* Verify the shared variable counter value. */ + TEST_ASSERT_EQUAL_UINT32( configNUMBER_OF_CORES * TASK_INCREASE_COUNTER_TIMES, xTaskCounter ); +} +/*-----------------------------------------------------------*/ + +/* Runs before every test, put init calls here. */ +void setUp( void ) +{ + uint32_t i; + + xTaskCounter = 0; + + for( i = 0; i < configNUMBER_OF_CORES; i++ ) + { + xTaskIndexes[ i ] = i; + xTaskHandles[ i ] = NULL; + xTaskTestResults[ i ] = pdFALSE; + xTaskReady[ i ] = 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; i++ ) + { + if( xTaskHandles[ i ] != NULL ) + { + vTaskDelete( xTaskHandles[ i ] ); + xTaskHandles[ i ] = NULL; + } + } +} +/*-----------------------------------------------------------*/ + +/** + * @brief Entry point for test runner to run critical section test. + */ +void vRunOnlyOneTaskEnterCriticalTest( void ) +{ + UNITY_BEGIN(); + + RUN_TEST( Test_OnlyOneTaskEnterCritical ); + + UNITY_END(); +} +/*-----------------------------------------------------------*/ diff --git a/FreeRTOS/Test/Target/tests/smp/only_one_task_enter_critical/test_config.h b/FreeRTOS/Test/Target/tests/smp/only_one_task_enter_critical/test_config.h new file mode 100644 index 000000000..c35b26e51 --- /dev/null +++ b/FreeRTOS/Test/Target/tests/smp/only_one_task_enter_critical/test_config.h @@ -0,0 +1,58 @@ +/* + * FreeRTOS V202212.00 + * Copyright (C) 2020 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 critical section test. + */ +void vRunOnlyOneTaskEnterCriticalTest( void ); + +/*-----------------------------------------------------------*/ + +#endif /* ifndef TEST_CONFIG_H */