mirror of
https://github.com/espressif/esp-idf.git
synced 2025-11-18 10:31:09 +00:00
freertos: Migrate misc tests to test app
This commit migrates the "misc" tests to the test app as a component.
This commit is contained in:
@@ -6,6 +6,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
# type is treated as separate component
|
||||
set(test_types
|
||||
"kernel"
|
||||
"misc"
|
||||
"performance"
|
||||
"port")
|
||||
|
||||
|
||||
10
components/freertos/test_apps/freertos/misc/CMakeLists.txt
Normal file
10
components/freertos/test_apps/freertos/misc/CMakeLists.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
# Register all of the "misc" tests as a component
|
||||
|
||||
# In order for the cases defined by `TEST_CASE` in "misc" to be linked into
|
||||
# the final elf, the component can be registered as WHOLE_ARCHIVE
|
||||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_REQUIRES test_utils
|
||||
WHOLE_ARCHIVE)
|
||||
|
||||
# Todo: Fix no-format errors
|
||||
target_compile_options(${COMPONENT_LIB} PRIVATE "-Wno-format")
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Test features that are backported from version FreeRTOS 9.0.0.
|
||||
*
|
||||
* 1) Test backported timer functions
|
||||
* - xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
|
||||
* 2) Test backported queue/semaphore functions
|
||||
* - xQueueCreateStatic()
|
||||
* - xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic(), uxSemaphoreGetCount()
|
||||
* - xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic()
|
||||
* 3) Test static allocation of tasks
|
||||
* - xTaskCreateStaticPinnedToCore()
|
||||
* 4) Test static allocation of event group
|
||||
* - xEventGroupCreateStatic()
|
||||
* 5) Test Thread Local Storage Pointers and Deletion Callbacks
|
||||
* - vTaskSetThreadLocalStoragePointerAndDelCallback()
|
||||
* - pvTaskGetThreadLocalStoragePointer()
|
||||
*
|
||||
* Note: The *pcQueueGetName() function is also backported, but is not tested in
|
||||
* the following test cases (see Queue Registry test cases instead)
|
||||
* For more details please refer the the ESP-IDF FreeRTOS changes documentation
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/timers.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
/* ---------------------Test 1: Backported Timer functions-----------------------
|
||||
* Test xTimerCreateStatic(), vTimerSetTimerId(), xTimerGetPeriod(), xTimerGetExpiryTime()
|
||||
*
|
||||
* This test creates a one-shot static timer, sets/checks the timer's id and period. Then ensures
|
||||
* the timer cb is executed in a timely fashion.
|
||||
*/
|
||||
#define TMR_PERIOD_TICKS 10
|
||||
#define TIMER_ID 0xFF
|
||||
#define TICK_DELTA 5
|
||||
|
||||
static StaticTimer_t timer_buffer;
|
||||
static TickType_t tmr_ideal_exp;
|
||||
|
||||
static void tmr_cb(TimerHandle_t xtimer)
|
||||
{
|
||||
//Check cb is called in timely fashion
|
||||
TEST_ASSERT_UINT32_WITHIN(TICK_DELTA, tmr_ideal_exp, xTaskGetTickCount());
|
||||
}
|
||||
|
||||
//No need for smp test as Timer Task always runs on core 0
|
||||
TEST_CASE("Test FreeRTOS backported timer functions", "[freertos]")
|
||||
{
|
||||
//Create one shot static timer with period TMR_PERIOD_TICKS
|
||||
TimerHandle_t tmr_handle = xTimerCreateStatic("static_tmr", TMR_PERIOD_TICKS, pdFALSE, NULL, tmr_cb, &timer_buffer);
|
||||
TEST_ASSERT_EQUAL(TMR_PERIOD_TICKS, xTimerGetPeriod(tmr_handle)); //Test xTimerGetPeriod()
|
||||
|
||||
vTimerSetTimerID(tmr_handle, (void *)TIMER_ID);
|
||||
TEST_ASSERT_EQUAL(TIMER_ID, (uint32_t)pvTimerGetTimerID(tmr_handle)); //Test vTimerSetTimerID()
|
||||
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xTimerStart(tmr_handle, 1)); //Start Timer
|
||||
tmr_ideal_exp = xTaskGetTickCount() + TMR_PERIOD_TICKS; //Calculate ideal expiration time
|
||||
vTaskDelay(2); //Need to yield to allow daemon task to process start command, or else expiration time will be NULL
|
||||
|
||||
TEST_ASSERT_UINT32_WITHIN(TICK_DELTA, tmr_ideal_exp, xTimerGetExpiryTime(tmr_handle)); //Test xTimerGetExpiryTime()
|
||||
|
||||
vTaskDelay(2*TMR_PERIOD_TICKS); //Delay until one shot timer has triggered
|
||||
TEST_ASSERT_EQUAL(pdPASS, xTimerDelete(tmr_handle, portMAX_DELAY)); //Clean up
|
||||
|
||||
}
|
||||
|
||||
/* ---------------Test backported queue/semaphore functions-------------------
|
||||
* xQueueCreateStatic()
|
||||
* xSemaphoreCreateBinaryStatic(), xSemaphoreCreateCountingStatic()
|
||||
* xSemaphoreCreateMutexStatic(), xSemaphoreCreateRecursiveMutexStatic()
|
||||
* uxSemaphoreGetCount() is also tested on the static counting semaphore
|
||||
*
|
||||
* This test creates various static queue/semphrs listed above and tests them by
|
||||
* doing a simple send/give and rec/take.
|
||||
*/
|
||||
|
||||
#define ITEM_SIZE 3
|
||||
#define NO_OF_ITEMS 3
|
||||
#define DELAY_TICKS 2
|
||||
|
||||
static StaticQueue_t queue_buffer; //Queues, Semaphores, and Mutex use the same queue structure
|
||||
static uint8_t queue_storage_area[(ITEM_SIZE*NO_OF_ITEMS)]; //Queue storage provided in separate buffer to queue struct
|
||||
|
||||
TEST_CASE("Test FreeRTOS backported Queue and Semphr functions", "[freertos]")
|
||||
{
|
||||
//Test static queue
|
||||
uint8_t queue_item_to_send[ITEM_SIZE];
|
||||
uint8_t queue_item_received[ITEM_SIZE];
|
||||
for(int i = 0; i < ITEM_SIZE; i++){
|
||||
queue_item_to_send[i] = (0xF << i);
|
||||
}
|
||||
QueueHandle_t handle = xQueueCreateStatic(NO_OF_ITEMS, ITEM_SIZE,(uint8_t*) &queue_storage_area, &queue_buffer);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xQueueSendToBack(handle, &queue_item_to_send, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xQueueReceive(handle, queue_item_received, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
for(int i = 0; i < ITEM_SIZE; i++){
|
||||
TEST_ASSERT_EQUAL(queue_item_to_send[i], queue_item_received[i]); //Check received contents are correct
|
||||
}
|
||||
vQueueDelete(handle); //Technically not needed as deleting static queue/semphr doesn't clear static memory
|
||||
|
||||
//Test static binary semaphore
|
||||
handle = xSemaphoreCreateBinaryStatic(&queue_buffer); //Queue and Semphr handles are the same
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static counting semaphore and uxSemaphoreGetCount()
|
||||
handle = xSemaphoreCreateCountingStatic(NO_OF_ITEMS, 0, &queue_buffer);
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(NO_OF_ITEMS, uxSemaphoreGetCount(handle)); //Test uxSemaphoreGetCount()
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL(0, uxSemaphoreGetCount(handle));
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static mutex
|
||||
handle = xSemaphoreCreateMutexStatic(&queue_buffer);
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTake(handle, DELAY_TICKS));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR((void *)xTaskGetCurrentTaskHandle(), xSemaphoreGetMutexHolder(handle)); //Current task should now hold mutex
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGive(handle));
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, xSemaphoreGetMutexHolder(handle)); //Mutex should have been released
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
//Test static mutex recursive
|
||||
handle = xSemaphoreCreateRecursiveMutexStatic(&queue_buffer);
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreTakeRecursive(handle, DELAY_TICKS));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR((void *)xTaskGetCurrentTaskHandle(), xSemaphoreGetMutexHolder(handle)); //Current task should hold mutex
|
||||
for(int i = 0; i < NO_OF_ITEMS; i++){
|
||||
TEST_ASSERT_EQUAL(pdTRUE, xSemaphoreGiveRecursive(handle));
|
||||
}
|
||||
vTaskDelay(1);
|
||||
TEST_ASSERT_EQUAL_PTR(NULL, xSemaphoreGetMutexHolder(handle)); //Mutex should have been released
|
||||
vSemaphoreDelete(handle);
|
||||
|
||||
}
|
||||
|
||||
/* -----------------Test backported static task allocation -------------------
|
||||
* Test xTaskCreateStaticPinnedToCore() but creating static task on each core
|
||||
* and checking the task cb has run successfully.
|
||||
*/
|
||||
|
||||
#define STACK_SIZE 2048 //Task stack size
|
||||
|
||||
static StackType_t task_stack[STACK_SIZE]; //Static buffer for task stack
|
||||
static StaticTask_t task_buffer; //Static buffer for TCB
|
||||
static bool has_run[portNUM_PROCESSORS];
|
||||
|
||||
static void task(void *arg)
|
||||
{
|
||||
has_run[xPortGetCoreID()] = true; //Signify static task cb has run
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test FreeRTOS static task allocation", "[freertos]")
|
||||
{
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
has_run[core] = false; //Clear has_run flag
|
||||
TaskHandle_t handle = xTaskCreateStaticPinnedToCore(task, "static task", STACK_SIZE, NULL,
|
||||
UNITY_FREERTOS_PRIORITY + 1, (StackType_t *)&task_stack,
|
||||
(StaticTask_t *)&task_buffer, core);
|
||||
vTaskDelay(5); //Allow for static task to run, delete, and idle to clean up
|
||||
TEST_ASSERT_NOT_EQUAL(NULL, handle); //Check static task was successfully allocated
|
||||
TEST_ASSERT_TRUE(has_run[core]) //Check static task has run
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------- Test backported static event group allocation -------------------
|
||||
* Test xEventGroupCreateStatic() but creating static event group then waiting
|
||||
* for an event.
|
||||
*/
|
||||
|
||||
#define WAIT_BITS 0x01 //Wait for first bit
|
||||
|
||||
static StaticEventGroup_t event_group;
|
||||
static EventGroupHandle_t eg_handle;
|
||||
|
||||
TEST_CASE("Test FreeRTOS backported eventgroup functions", "[freertos]")
|
||||
{
|
||||
eg_handle = xEventGroupCreateStatic((StaticEventGroup_t *)&event_group);
|
||||
xEventGroupSetBits(eg_handle, WAIT_BITS);
|
||||
TEST_ASSERT_EQUAL(WAIT_BITS, xEventGroupWaitBits(eg_handle, WAIT_BITS, pdTRUE, pdTRUE, portMAX_DELAY));
|
||||
//Cleanup static event
|
||||
vEventGroupDelete(eg_handle);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
/* If assertions aren't set to fail this code still crashes, but not with an abort... */
|
||||
#if CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER && !CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE
|
||||
|
||||
static void mutex_release_task(void* arg)
|
||||
{
|
||||
SemaphoreHandle_t mutex = (SemaphoreHandle_t) arg;
|
||||
xSemaphoreGive(mutex);
|
||||
TEST_FAIL_MESSAGE("should not be reached");
|
||||
}
|
||||
|
||||
TEST_CASE("mutex released not by owner causes an assert", "[freertos][reset=assert,SW_CPU_RESET]")
|
||||
{
|
||||
SemaphoreHandle_t mutex = xSemaphoreCreateMutex();
|
||||
xSemaphoreTake(mutex, portMAX_DELAY);
|
||||
xTaskCreate(&mutex_release_task, "mutex_release", 2048, mutex, UNITY_FREERTOS_PRIORITY + 1, NULL);
|
||||
vTaskDelay(1);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Test FreeRTOS trace facility functions. These following functions are enabled
|
||||
* when configUSE_TRACE_FACILITY is defined 1 in FreeRTOS.
|
||||
* Tasks: uxTaskGetTaskNumber(), uxTaskSetTaskNumber()
|
||||
* Queues: ucQueueGetQueueType(), vQueueSetQueueNumber(), uxQueueGetQueueNumber()
|
||||
* Event Groups: xEventGroupSetBitsFromISR(), xEventGroupClearBitsFromISR(), uxEventGroupGetNumber()
|
||||
*
|
||||
* Note: uxTaskGetSystemState() is tested in a separate unit test
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
#ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY
|
||||
#define TSK_PRIORITY (UNITY_FREERTOS_PRIORITY + 1)
|
||||
|
||||
#define NO_OF_CORES portNUM_PROCESSORS
|
||||
#define BIN_SEM_QUEUE_TYPE queueQUEUE_TYPE_BINARY_SEMAPHORE //Expected Queue Type
|
||||
|
||||
static QueueHandle_t test_queues[NO_OF_CORES];
|
||||
static TaskHandle_t task_handles[NO_OF_CORES];
|
||||
|
||||
void task_test_trace_utilities(void *arg)
|
||||
{
|
||||
int core = xPortGetCoreID();
|
||||
TaskHandle_t handle = xTaskGetCurrentTaskHandle();
|
||||
uint32_t id = (uint32_t)arg;
|
||||
|
||||
vTaskSetTaskNumber(handle, (UBaseType_t)id); //cast and store id as task number
|
||||
vQueueSetQueueNumber(test_queues[core], id); //store id as queue number
|
||||
|
||||
//Wait to start
|
||||
xSemaphoreTake(test_queues[core], portMAX_DELAY);
|
||||
|
||||
//Tests on this core
|
||||
TEST_ASSERT(uxTaskGetTaskNumber(task_handles[core]) == (0x0F << (core)));
|
||||
TEST_ASSERT(uxQueueGetQueueNumber(test_queues[core]) == (0x0F << (core)));
|
||||
TEST_ASSERT(ucQueueGetQueueType(test_queues[core]) == BIN_SEM_QUEUE_TYPE)
|
||||
|
||||
//Test on other core
|
||||
#ifndef CONFIG_FREERTOS_UNICORE
|
||||
TEST_ASSERT(uxTaskGetTaskNumber(task_handles[!core]) == (0x0F << (!core)));
|
||||
TEST_ASSERT(uxQueueGetQueueNumber(test_queues[!core]) == (0x0F << (!core)));
|
||||
TEST_ASSERT(ucQueueGetQueueType(test_queues[!core]) == BIN_SEM_QUEUE_TYPE)
|
||||
#endif
|
||||
|
||||
xSemaphoreGive(test_queues[core]); //Signal done
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test freertos trace facility functions", "[freertos]")
|
||||
{
|
||||
for(int i = 0; i < NO_OF_CORES; i++){
|
||||
test_queues[i] = xSemaphoreCreateBinary(); //Create a queue as binary semaphore for each core
|
||||
xTaskCreatePinnedToCore(task_test_trace_utilities, "Test Task", 4096, (void *)(0x0F << i), TSK_PRIORITY, &task_handles[i], i);
|
||||
}
|
||||
|
||||
vTaskDelay(10);
|
||||
|
||||
//Start the tasks
|
||||
for(int i = NO_OF_CORES - 1; i >= 0; i--){
|
||||
xSemaphoreGive(test_queues[i]);
|
||||
}
|
||||
|
||||
vTaskDelay(10); //Small delay to ensure semaphores are taken
|
||||
|
||||
//Wait for done
|
||||
for(int i = 0; i < NO_OF_CORES; i++){
|
||||
xSemaphoreTake(test_queues[i], portMAX_DELAY);
|
||||
vSemaphoreDelete(test_queues[i]);
|
||||
}
|
||||
|
||||
vTaskDelay(10); //Give time for idle task to clean up
|
||||
}
|
||||
|
||||
|
||||
#define MAX_TASKS 15
|
||||
#define TASKS_TO_CREATE 5
|
||||
|
||||
static TaskHandle_t created_handles[TASKS_TO_CREATE];
|
||||
static TaskStatus_t *tsk_status_array;
|
||||
|
||||
void created_task(void* arg)
|
||||
{
|
||||
while(1){
|
||||
vTaskDelay(100);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Test freertos uxTaskGetSystemState", "[freertos]")
|
||||
{
|
||||
tsk_status_array = calloc(MAX_TASKS, sizeof(TaskStatus_t));
|
||||
for(int i = 0; i < TASKS_TO_CREATE; i++){
|
||||
xTaskCreatePinnedToCore(created_task, "Created Task", 1024, NULL, TSK_PRIORITY, &created_handles[i], 0);
|
||||
}
|
||||
|
||||
//Get System states
|
||||
int no_of_tasks = uxTaskGetSystemState(tsk_status_array, MAX_TASKS, NULL);
|
||||
TEST_ASSERT((no_of_tasks > 0) && (no_of_tasks <= MAX_TASKS));
|
||||
|
||||
//Check if get system state has got all created tasks
|
||||
bool not_found = false;
|
||||
for(int i = 0; i < TASKS_TO_CREATE; i++){
|
||||
bool found = false;
|
||||
for(int j = 0; j < MAX_TASKS; j++){
|
||||
if(tsk_status_array[j].xHandle == created_handles[i]){
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
not_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_ASSERT(not_found == false);
|
||||
|
||||
//Cleanup
|
||||
for(int i = 0; i < TASKS_TO_CREATE; i++){
|
||||
vTaskDelete(created_handles[i]);
|
||||
}
|
||||
free(tsk_status_array);
|
||||
vTaskDelay(10);
|
||||
}
|
||||
|
||||
#endif //CONFIG_FREERTOS_USE_TRACE_FACILITY
|
||||
25
components/freertos/test_apps/freertos/misc/test_panic.c
Normal file
25
components/freertos/test_apps/freertos/misc/test_panic.c
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
Test for multicore FreeRTOS. This test spins up threads, fiddles with queues etc.
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "unity.h"
|
||||
|
||||
TEST_CASE("Panic handler", "[freertos][ignore]")
|
||||
{
|
||||
volatile int *i;
|
||||
i = (volatile int *)0x0;
|
||||
*i = 1;
|
||||
}
|
||||
124
components/freertos/test_apps/freertos/misc/test_preemption.c
Normal file
124
components/freertos/test_apps/freertos/misc/test_preemption.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
Unit tests for FreeRTOS preemption
|
||||
*/
|
||||
|
||||
#include <esp_types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "unity.h"
|
||||
#include "esp_cpu.h"
|
||||
#include "test_utils.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
static volatile bool trigger;
|
||||
static volatile bool flag;
|
||||
|
||||
#ifndef CONFIG_FREERTOS_SMP
|
||||
#define MAX_YIELD_COUNT 10000
|
||||
#else
|
||||
//TODO: IDF-5081
|
||||
#define MAX_YIELD_COUNT 17000
|
||||
#endif // CONFIG_FREERTOS_SMP
|
||||
|
||||
|
||||
/* Task:
|
||||
- Waits for 'trigger' variable to be set
|
||||
- Reads the cycle count on this CPU
|
||||
- Pushes it into a queue supplied as a param
|
||||
- Busy-waits until the main task terminates it
|
||||
*/
|
||||
static void task_send_to_queue(void *param)
|
||||
{
|
||||
QueueHandle_t queue = (QueueHandle_t) param;
|
||||
uint32_t ccount;
|
||||
|
||||
while(!trigger) {}
|
||||
|
||||
ccount = esp_cpu_get_cycle_count();
|
||||
flag = true;
|
||||
xQueueSendToBack(queue, &ccount, 0);
|
||||
/* This is to ensure that higher priority task
|
||||
won't wake anyhow, due to this task terminating.
|
||||
|
||||
The task runs until terminated by the main task.
|
||||
*/
|
||||
while(1) {}
|
||||
}
|
||||
|
||||
TEST_CASE("Yield from lower priority task, same CPU", "[freertos]")
|
||||
{
|
||||
/* Do this 3 times, mostly for the benchmark value - the first
|
||||
run includes a cache miss so uses more cycles than it should. */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
TaskHandle_t sender_task;
|
||||
QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
|
||||
flag = false;
|
||||
trigger = false;
|
||||
|
||||
/* "yield" task sits on our CPU, lower priority to us */
|
||||
xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1, &sender_task, UNITY_FREERTOS_CPU);
|
||||
|
||||
vTaskDelay(1); /* make sure everything is set up */
|
||||
trigger = true;
|
||||
|
||||
uint32_t yield_ccount, now_ccount, delta;
|
||||
TEST_ASSERT( xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS) );
|
||||
now_ccount = esp_cpu_get_cycle_count();
|
||||
TEST_ASSERT( flag );
|
||||
|
||||
delta = now_ccount - yield_ccount;
|
||||
printf("Yielding from lower priority task took %u cycles\n", delta);
|
||||
TEST_ASSERT(delta < MAX_YIELD_COUNT);
|
||||
|
||||
vTaskDelete(sender_task);
|
||||
vQueueDelete(queue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if (portNUM_PROCESSORS == 2) && !CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH
|
||||
TEST_CASE("Yield from lower priority task, other CPU", "[freertos]")
|
||||
{
|
||||
uint32_t trigger_ccount, yield_ccount, now_ccount, delta;
|
||||
|
||||
/* Do this 3 times, mostly for the benchmark value - the first
|
||||
run includes a cache miss so uses more cycles than it should. */
|
||||
for (int i = 0; i < 3; i++) {
|
||||
TaskHandle_t sender_task;
|
||||
QueueHandle_t queue = xQueueCreate(1, sizeof(uint32_t));
|
||||
trigger = false;
|
||||
flag = false;
|
||||
|
||||
/* "send_to_queue" task sits on the other CPU, lower priority to us */
|
||||
xTaskCreatePinnedToCore(task_send_to_queue, "YIELD", 2048, (void *)queue, UNITY_FREERTOS_PRIORITY - 1,
|
||||
&sender_task, !UNITY_FREERTOS_CPU);
|
||||
|
||||
vTaskDelay(2); /* make sure everything is set up */
|
||||
trigger = true;
|
||||
trigger_ccount = esp_cpu_get_cycle_count();
|
||||
|
||||
// yield_ccount is not useful in this test as it's the other core's CCOUNT
|
||||
// so we use trigger_ccount instead
|
||||
TEST_ASSERT( xQueueReceive(queue, &yield_ccount, 100 / portTICK_PERIOD_MS) );
|
||||
now_ccount = esp_cpu_get_cycle_count();
|
||||
TEST_ASSERT( flag );
|
||||
|
||||
delta = now_ccount - trigger_ccount;
|
||||
printf("Yielding from task on other core took %u cycles\n", delta);
|
||||
TEST_ASSERT(delta < MAX_YIELD_COUNT);
|
||||
|
||||
vQueueDelete(queue);
|
||||
vTaskDelete(sender_task);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
164
components/freertos/test_apps/freertos/misc/test_tlsp_del_cb.c
Normal file
164
components/freertos/test_apps/freertos/misc/test_tlsp_del_cb.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2022 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#if CONFIG_FREERTOS_SMP
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
/*
|
||||
Test TLSP Deletion Callbacks
|
||||
|
||||
Purpose:
|
||||
- Test that TLSP Deletion Callbacks can be registered
|
||||
- Test that TLSP Deletion Callbacks are called when a task is deleted
|
||||
|
||||
Procedure:
|
||||
- Create a task on each core along with an array of integers to act as TLSP data
|
||||
- Each task should initialize their integers to a particular value (i.e., the index value)
|
||||
- Each task should register those integers as TLSPs along with a deletion callback
|
||||
- Each task should self delete to trigger the TLSP deletion callback
|
||||
- The TLSP deletion callback should indicate that it has run by negating the integer values
|
||||
|
||||
Expected:
|
||||
- The TLSP deletion callback should check that the correct TLSP is provided by checking the TLSPs initialization
|
||||
value (i.e., should be set to the index value)
|
||||
- After deletion, the integer values should be negated to indicate deletion callback execution
|
||||
*/
|
||||
|
||||
#define NUM_TLSP CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS
|
||||
|
||||
static void tlsp_del_cb(int index, void *tlsp)
|
||||
{
|
||||
int *val = (int *)tlsp;
|
||||
|
||||
// Check that the TLSP's initialization value is correct
|
||||
TEST_ASSERT_EQUAL(index, *val);
|
||||
// Set the TLSP's value again to a negative value to indicate that the del cb has ran
|
||||
*val = -*val;
|
||||
}
|
||||
|
||||
static void tlsp_task(void *arg)
|
||||
{
|
||||
int *tlsps = (int *)arg;
|
||||
|
||||
for (int index = 0; index < NUM_TLSP; index++) {
|
||||
// Initialize the TLSPs to a positive value
|
||||
tlsps[index] = index;
|
||||
// Set TLSPs and deletion callbacks
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, index, &tlsps[index], tlsp_del_cb);
|
||||
}
|
||||
|
||||
// Self delete to trigger TLSP del cb
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
TEST_CASE("Test TLSP deletion callbacks", "[freertos]")
|
||||
{
|
||||
TaskHandle_t tasks[portNUM_PROCESSORS];
|
||||
int tlsps[portNUM_PROCESSORS][NUM_TLSP];
|
||||
|
||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
TEST_ASSERT_EQUAL(pdPASS, xTaskCreatePinnedToCore(tlsp_task, "tlsp_tsk", configMINIMAL_STACK_SIZE * 2, (void *)&tlsps[i], UNITY_FREERTOS_PRIORITY - 1, &tasks[i], i));
|
||||
}
|
||||
// Significant delay to let tasks run and delete themselves
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
|
||||
// Check the values of the TLSPs to see if the del cb have ran
|
||||
for (int i = 0; i < portNUM_PROCESSORS; i++) {
|
||||
for (int index = 0; index < NUM_TLSP; index++) {
|
||||
// Del cb should have set the TLSP to a negative value
|
||||
TEST_ASSERT_EQUAL(-index, tlsps[i][index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else // CONFIG_FREERTOS_SMP
|
||||
|
||||
// Todo: Remove IDF FreeRTOS Test Case
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "unity.h"
|
||||
#include "test_utils.h"
|
||||
|
||||
/* --------Test backported thread local storage pointer and deletion cb feature----------
|
||||
* vTaskSetThreadLocalStoragePointerAndDelCallback()
|
||||
* pvTaskGetThreadLocalStoragePointer(),
|
||||
*
|
||||
* This test creates a task and set's the task's TLSPs. The task is then deleted
|
||||
* which should trigger the deletion cb.
|
||||
*/
|
||||
|
||||
#define NO_OF_TLSP configNUM_THREAD_LOCAL_STORAGE_POINTERS
|
||||
#define TLSP_SET_BASE 0x0F //0b1111 to be bit shifted by index
|
||||
#define TLSP_DEL_BASE 0x05 //0b0101 to be bit shifted by index
|
||||
|
||||
//The variables pointed to by Thread Local Storage Pointer
|
||||
static uint32_t task_storage[portNUM_PROCESSORS][NO_OF_TLSP] = {0};
|
||||
|
||||
/* If static task cleanup is defined, can't set index 0 even if the calling task is not a pthread,
|
||||
as the cleanup is called for every task.
|
||||
*/
|
||||
#if defined(CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP)
|
||||
static const int skip_index = 0; /*PTHREAD_TLS_INDEX*/
|
||||
#else
|
||||
static const int skip_index = -1;
|
||||
#endif
|
||||
|
||||
static void del_cb(int index, void *ptr)
|
||||
{
|
||||
*((uint32_t *)ptr) = (TLSP_DEL_BASE << index); //Indicate deletion by setting task storage element to a unique value
|
||||
}
|
||||
|
||||
static void task_cb(void *arg)
|
||||
{
|
||||
int core = xPortGetCoreID();
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
if (i == skip_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
task_storage[core][i] = (TLSP_SET_BASE << i); //Give each element of task_storage a unique number
|
||||
vTaskSetThreadLocalStoragePointerAndDelCallback(NULL, i, (void *)&task_storage[core][i], del_cb); //Set each TLSP to point to a task storage element
|
||||
}
|
||||
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
if (i == skip_index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t * tlsp = (uint32_t *)pvTaskGetThreadLocalStoragePointer(NULL, i);
|
||||
TEST_ASSERT_EQUAL(*tlsp, (TLSP_SET_BASE << i)); //Check if TLSP points to the correct task storage element by checking unique value
|
||||
}
|
||||
|
||||
vTaskDelete(NULL); //Delete Task to Trigger TSLP deletion callback
|
||||
}
|
||||
|
||||
TEST_CASE("Test FreeRTOS thread local storage pointers and del cb", "[freertos]")
|
||||
{
|
||||
//Create Task
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
xTaskCreatePinnedToCore(task_cb, "task", 1024, NULL, UNITY_FREERTOS_PRIORITY+1, NULL, core);
|
||||
}
|
||||
vTaskDelay(10); //Delay long enough for tasks to run to completion
|
||||
|
||||
for(int core = 0; core < portNUM_PROCESSORS; core++){
|
||||
for(int i = 0; i < NO_OF_TLSP; i++){
|
||||
if (i == skip_index) {
|
||||
continue;
|
||||
}
|
||||
TEST_ASSERT_EQUAL((TLSP_DEL_BASE << i), task_storage[core][i]); //Check del_cb ran by checking task storage for unique value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIG_FREERTOS_SMP
|
||||
Reference in New Issue
Block a user