freertos: Add unit test for deleting task which may be blocking

pull/6882/head
Angus Gratton 2020-12-19 08:45:57 +11:00 zatwierdzone przez bot
rodzic a5faf86934
commit db7d272873
1 zmienionych plików z 71 dodań i 3 usunięć

Wyświetl plik

@ -2,9 +2,8 @@
* Test backported deletion behavior by creating tasks of various affinities and * Test backported deletion behavior by creating tasks of various affinities and
* check if the task memory is freed immediately under the correct conditions. * check if the task memory is freed immediately under the correct conditions.
* *
* The behavior of vTaskDelete() has been backported form FreeRTOS v9.0.0. This * The behavior of vTaskDelete() results in the immediate freeing of task memory
* results in the immediate freeing of task memory and the immediate execution * and the immediate execution of deletion callbacks under the following conditions...
* of deletion callbacks under the following conditions...
* - When deleting a task that is not currently running on either core * - When deleting a task that is not currently running on either core
* - When deleting a task that is pinned to the same core (with respect to * - When deleting a task that is pinned to the same core (with respect to
* the core that calls vTaskDelete() * the core that calls vTaskDelete()
@ -16,6 +15,7 @@
#include "freertos/FreeRTOS.h" #include "freertos/FreeRTOS.h"
#include "freertos/task.h" #include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_heap_caps.h" #include "esp_heap_caps.h"
#include "unity.h" #include "unity.h"
@ -84,3 +84,71 @@ TEST_CASE("FreeRTOS Delete Tasks", "[freertos]")
} }
} }
typedef struct {
SemaphoreHandle_t sem;
volatile bool deleted; // Check the deleted task doesn't keep running after being deleted
} tsk_blocks_param_t;
/* Task blocks as often as possible
(two or more of these can share the same semaphore and "juggle" it around)
*/
static void tsk_blocks_frequently(void *param)
{
tsk_blocks_param_t *p = (tsk_blocks_param_t *)param;
SemaphoreHandle_t sem = p->sem;
srand(xTaskGetTickCount() ^ (int)xTaskGetCurrentTaskHandle());
while (1) {
assert(!p->deleted);
esp_rom_delay_us(rand() % 10);
assert(!p->deleted);
xSemaphoreTake(sem, portMAX_DELAY);
assert(!p->deleted);
esp_rom_delay_us(rand() % 10);
assert(!p->deleted);
xSemaphoreGive(sem);
}
}
TEST_CASE("FreeRTOS Delete Blocked Tasks", "[freertos]")
{
TaskHandle_t blocking_tasks[portNUM_PROCESSORS + 1]; // one per CPU, plus one unpinned task
tsk_blocks_param_t params[portNUM_PROCESSORS + 1] = { 0 };
unsigned before = heap_caps_get_free_size(MALLOC_CAP_8BIT);
printf("Free memory at start %u\n", before);
/* Any bugs will depend on relative timing of destroying the tasks, so create & delete many times.
Stop early if it looks like some resources have not been properly cleaned up.
(1000 iterations takes about 9 seconds on ESP32 dual core)
*/
for(unsigned iter = 0; iter < 1000; iter++) {
// Create everything
SemaphoreHandle_t sem = xSemaphoreCreateMutex();
for(unsigned i = 0; i < portNUM_PROCESSORS + 1; i++) {
params[i].deleted = false;
params[i].sem = sem;
TEST_ASSERT_EQUAL(pdTRUE,
xTaskCreatePinnedToCore(tsk_blocks_frequently, "tsk_block", 4096, &params[i],
UNITY_FREERTOS_PRIORITY - 1, &blocking_tasks[i],
i < portNUM_PROCESSORS ? i : tskNO_AFFINITY));
}
vTaskDelay(5); // Let the tasks juggle the mutex for a bit
for(unsigned i = 0; i < portNUM_PROCESSORS + 1; i++) {
vTaskDelete(blocking_tasks[i]);
params[i].deleted = true;
}
vTaskDelay(4); // Yield to the idle task for cleanup
vSemaphoreDelete(sem);
// Check we haven't leaked resources yet
TEST_ASSERT_GREATER_OR_EQUAL(before - 256, heap_caps_get_free_size(MALLOC_CAP_8BIT));
}
}