Skip to content

Commit 2adaf84

Browse files
chinglee-iotaggarg
andauthored
Add SMP disable preemption on target test (FreeRTOS#1175)
* Add SMP disable preemption on target test --------- Signed-off-by: Gaurav Aggarwal <[email protected]> Co-authored-by: Gaurav Aggarwal <[email protected]> Co-authored-by: Gaurav-Aggarwal-AWS <[email protected]>
1 parent d9ced6e commit 2adaf84

File tree

4 files changed

+421
-0
lines changed

4 files changed

+421
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
cmake_minimum_required(VERSION 3.13)
2+
3+
project(example C CXX ASM)
4+
set(CMAKE_C_STANDARD 11)
5+
set(CMAKE_CXX_STANDARD 17)
6+
7+
set(TEST_INCLUDE_PATHS ${CMAKE_CURRENT_LIST_DIR}/../../../../../tests/smp/disable_preemption)
8+
set(TEST_SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/../../../../../tests/smp/disable_preemption)
9+
10+
add_library(disable_preemption INTERFACE)
11+
target_sources(disable_preemption INTERFACE
12+
${BOARD_LIBRARY_DIR}/main.c
13+
${CMAKE_CURRENT_LIST_DIR}/disable_preemption_test_runner.c
14+
${TEST_SOURCE_DIR}/disable_preemption.c)
15+
16+
target_include_directories(disable_preemption INTERFACE
17+
${CMAKE_CURRENT_LIST_DIR}/../../..
18+
${TEST_INCLUDE_PATHS}
19+
)
20+
21+
target_link_libraries(disable_preemption INTERFACE
22+
FreeRTOS-Kernel
23+
FreeRTOS-Kernel-Heap4
24+
${BOARD_LINK_LIBRARIES})
25+
26+
add_executable(test_disable_preemption)
27+
enable_board_functions(test_disable_preemption)
28+
target_link_libraries(test_disable_preemption disable_preemption)
29+
target_include_directories(test_disable_preemption PUBLIC
30+
${BOARD_INCLUDE_PATHS})
31+
target_compile_definitions(test_disable_preemption PRIVATE
32+
${BOARD_DEFINES}
33+
)
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*
2+
* FreeRTOS V202212.00
3+
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
* this software and associated documentation files (the "Software"), to deal in
7+
* the Software without restriction, including without limitation the rights to
8+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
* the Software, and to permit persons to whom the Software is furnished to do so,
10+
* subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in all
13+
* copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
*
22+
* https://www.FreeRTOS.org
23+
* https://github.com/FreeRTOS
24+
*
25+
*/
26+
27+
/**
28+
* @file disable_preemption_test_runner.c
29+
* @brief The implementation of main function to start test runner task.
30+
*
31+
* Procedure:
32+
* - Initialize environment
33+
* - Run the test case
34+
*/
35+
36+
/* Kernel includes. */
37+
#include "FreeRTOS.h"
38+
#include "task.h"
39+
40+
/* Unit testing support functions. */
41+
#include "unity.h"
42+
43+
/* Pico includes. */
44+
#include "pico/multicore.h"
45+
#include "pico/stdlib.h"
46+
47+
/*-----------------------------------------------------------*/
48+
49+
static void prvTestRunnerTask( void * pvParameters );
50+
51+
/*-----------------------------------------------------------*/
52+
53+
static void prvTestRunnerTask( void * pvParameters )
54+
{
55+
( void ) pvParameters;
56+
57+
/* Run test case. */
58+
vRunDisablePreemptionTest();
59+
60+
vTaskDelete( NULL );
61+
}
62+
63+
/*-----------------------------------------------------------*/
64+
65+
void vRunTest( void )
66+
{
67+
xTaskCreate( prvTestRunnerTask,
68+
"testRunner",
69+
configMINIMAL_STACK_SIZE,
70+
NULL,
71+
configMAX_PRIORITIES - 1,
72+
NULL );
73+
}
74+
75+
/*-----------------------------------------------------------*/
Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
/*
2+
* FreeRTOS V202212.00
3+
* Copyright (C) 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
6+
* this software and associated documentation files (the "Software"), to deal in
7+
* the Software without restriction, including without limitation the rights to
8+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9+
* the Software, and to permit persons to whom the Software is furnished to do so,
10+
* subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in all
13+
* copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17+
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18+
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19+
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20+
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21+
*
22+
* https://www.FreeRTOS.org
23+
* https://github.com/FreeRTOS
24+
*
25+
*/
26+
27+
/**
28+
* @file disable_preemption.c
29+
* @brief The scheduler shall not preempt a task for which preemption is disabled.
30+
*
31+
* Procedure:
32+
* - Create ( num of cores + 1 ) tasks ( T0~Tn ) with priorities T0 > T1 > ... Tn.
33+
* T0 has the highest priority and Tn has the lowest priority.
34+
* - T0~Tn-1 suspend themselves.
35+
* - Tn disables preemption for itself and then resumes ( T0~Tn-1 ). Test
36+
* runner validates that Tn is still running.
37+
* - Test runner enables preemption of Tn. Test runner validates that Tn is
38+
* no longer running.
39+
* Expected:
40+
* - Tn will not be switched out when it has disabled preemption for itself.
41+
* - Tn will be preempted when the test runner enables preemption for it.
42+
*/
43+
44+
/* Standard includes. */
45+
#include <stdint.h>
46+
47+
/* Kernel includes. */
48+
#include "FreeRTOS.h"
49+
#include "task.h"
50+
51+
/* Unit testing support functions. */
52+
#include "unity.h"
53+
/*-----------------------------------------------------------*/
54+
55+
/**
56+
* @brief Timeout value to stop test.
57+
*/
58+
#define TEST_TIMEOUT_MS ( 1000 )
59+
60+
/**
61+
* @brief Nop operation for busy looping.
62+
*/
63+
#ifndef portNOP
64+
#define TEST_NOP() __asm volatile ( "nop" )
65+
#else
66+
#define TEST_NOP portNOP
67+
#endif
68+
/*-----------------------------------------------------------*/
69+
70+
#if ( configNUMBER_OF_CORES < 2 )
71+
#error This test is for FreeRTOS SMP and therefore, requires at least 2 cores.
72+
#endif /* if configNUMBER_OF_CORES != 2 */
73+
74+
#if ( configUSE_TASK_PREEMPTION_DISABLE != 1 )
75+
#error configUSE_TASK_PREEMPTION_DISABLE must be enabled by including test_config.h in FreeRTOSConfig.h.
76+
#endif /* if configUSE_TASK_PREEMPTION_DISABLE != 1 */
77+
78+
#if ( configMAX_PRIORITIES <= ( configNUMBER_OF_CORES + 2 ) )
79+
#error configMAX_PRIORITIES must be larger than ( configNUMBER_OF_CORES + 2 ) to avoid scheduling idle tasks unexpectedly.
80+
#endif /* if ( configMAX_PRIORITIES <= ( configNUMBER_OF_CORES + 2 ) ) */
81+
/*-----------------------------------------------------------*/
82+
83+
/**
84+
* @brief Test case "Disable Preemption".
85+
*/
86+
void Test_DisablePreemption( void );
87+
88+
/**
89+
* @brief Disable preemption test task.
90+
*/
91+
static void prvTestPreemptionDisableTask( void * pvParameters );
92+
/*-----------------------------------------------------------*/
93+
94+
/**
95+
* @brief Handles of the tasks created in this test.
96+
*/
97+
static TaskHandle_t xTaskHandles[ configNUMBER_OF_CORES + 1 ];
98+
99+
/**
100+
* @brief Indexes of the tasks created in this test.
101+
*/
102+
static uint32_t xTaskIndexes[ configNUMBER_OF_CORES + 1 ];
103+
104+
/**
105+
* @brief Flags to indicate the test result.
106+
*/
107+
static BaseType_t xTestResult = pdFAIL;
108+
/*-----------------------------------------------------------*/
109+
110+
static void prvTestPreemptionDisableTask( void * pvParameters )
111+
{
112+
uint32_t currentTaskIdx = *( ( uint32_t * ) pvParameters );
113+
uint32_t taskIndex;
114+
eTaskState taskState;
115+
BaseType_t xAllHighPriorityTasksSuspended = pdFALSE;
116+
117+
if( currentTaskIdx < configNUMBER_OF_CORES )
118+
{
119+
/* Tasks with smaller index have higher priority. Higher priority tasks
120+
* suspend themselves and are resumed later by the lowest priority task
121+
* after the lower priority task disables preemption for itself. */
122+
vTaskSuspend( NULL );
123+
}
124+
else
125+
{
126+
/* Wait for all the other higher priority tasks to suspend themselves. */
127+
while( xAllHighPriorityTasksSuspended == pdFALSE )
128+
{
129+
for( taskIndex = 0; taskIndex < configNUMBER_OF_CORES; taskIndex++ )
130+
{
131+
taskState = eTaskGetState( xTaskHandles[ taskIndex ] );
132+
133+
if( taskState != eSuspended )
134+
{
135+
break;
136+
}
137+
}
138+
139+
if( taskIndex == configNUMBER_OF_CORES )
140+
{
141+
xAllHighPriorityTasksSuspended = pdTRUE;
142+
}
143+
}
144+
145+
/* Disable preemption and resume all the other higher priority tasks.
146+
* At this point, the number of higher priority ready tasks is equal
147+
* to the number of cores. Still this lower priority must not be
148+
* switched out because it has disabled preemption for itself. */
149+
vTaskPreemptionDisable( NULL );
150+
151+
for( taskIndex = 0; taskIndex < configNUMBER_OF_CORES; taskIndex++ )
152+
{
153+
vTaskResume( xTaskHandles[ taskIndex ] );
154+
}
155+
156+
/* This task must not be switched out for any other higher priority
157+
* ready task because it has disabled preemption for itself. The
158+
* execution of the next line ensures that this task is not switched out
159+
* even though a higher priority ready task is available. This variable
160+
* is checked in the test runner. */
161+
xTestResult = pdPASS;
162+
}
163+
164+
/* Busy looping here to occupy this core. */
165+
for( ; ; )
166+
{
167+
/* Always running, put nop operation here to avoid optimization by compiler. */
168+
TEST_NOP();
169+
}
170+
}
171+
/*-----------------------------------------------------------*/
172+
173+
void Test_DisablePreemption( void )
174+
{
175+
eTaskState taskState;
176+
177+
uint32_t i;
178+
BaseType_t xTaskCreationResult;
179+
180+
/* Create ( configNUMBER_OF_CORES + 1 ) tasks with desending priorities. */
181+
for( i = 0; i < ( configNUMBER_OF_CORES + 1 ); i++ )
182+
{
183+
xTaskCreationResult = xTaskCreate( prvTestPreemptionDisableTask,
184+
"TestPreemptionDisable",
185+
configMINIMAL_STACK_SIZE * 2,
186+
&( xTaskIndexes[ i ] ),
187+
configMAX_PRIORITIES - 2 - i,
188+
&( xTaskHandles[ i ] ) );
189+
190+
TEST_ASSERT_EQUAL_MESSAGE( pdPASS, xTaskCreationResult, "Task creation failed." );
191+
}
192+
193+
/* TEST_TIMEOUT_MS is long enough to run this test. */
194+
vTaskDelay( pdMS_TO_TICKS( TEST_TIMEOUT_MS ) );
195+
196+
/* Verify the lowest priority task runs after resuming all test tasks. */
197+
TEST_ASSERT_EQUAL( pdPASS, xTestResult );
198+
199+
/* Enable preemption of the lowest priority task. The scheduler must switch
200+
* out this task now as there is a higher priority ready task available. */
201+
vTaskPreemptionEnable( xTaskHandles[ configNUMBER_OF_CORES ] );
202+
203+
/* Verify that the lowest priority task is not running anymore. */
204+
taskState = eTaskGetState( xTaskHandles[ configNUMBER_OF_CORES ] );
205+
TEST_ASSERT_EQUAL( eReady, taskState );
206+
}
207+
/*-----------------------------------------------------------*/
208+
209+
/* Runs before every test, put init calls here. */
210+
void setUp( void )
211+
{
212+
uint32_t i;
213+
214+
for( i = 0; i < ( configNUMBER_OF_CORES + 1 ); i++ )
215+
{
216+
xTaskIndexes[ i ] = i;
217+
xTaskHandles[ i ] = NULL;
218+
}
219+
}
220+
/*-----------------------------------------------------------*/
221+
222+
/* Runs after every test, put clean-up calls here. */
223+
void tearDown( void )
224+
{
225+
uint32_t i;
226+
227+
/* Delete all the tasks. */
228+
for( i = 0; i < ( configNUMBER_OF_CORES + 1 ); i++ )
229+
{
230+
if( xTaskHandles[ i ] != NULL )
231+
{
232+
vTaskDelete( xTaskHandles[ i ] );
233+
xTaskHandles[ i ] = NULL;
234+
}
235+
}
236+
}
237+
/*-----------------------------------------------------------*/
238+
239+
/**
240+
* @brief Entry point for test runner to run disable preemption test.
241+
*/
242+
void vRunDisablePreemptionTest( void )
243+
{
244+
UNITY_BEGIN();
245+
246+
RUN_TEST( Test_DisablePreemption );
247+
248+
UNITY_END();
249+
}
250+
/*-----------------------------------------------------------*/

0 commit comments

Comments
 (0)