esp_wifi: fix occasional test failure due to memory leak indications

Ensure that newly spawned task stack (dynamic) is getting freed up before
test completion and thus preventing false memory leak indication failure.

unit-test-app: add an API test_utils_task_delete

This API ensures that dynamic memory of deleted task gets freed up
before return. This helps for preventing false memory leak detections
in test failures.
This commit is contained in:
Mahavir Jain 2020-02-29 15:02:53 +05:30
parent e8ca5e6f21
commit 8ae05e6547
3 changed files with 82 additions and 9 deletions

View file

@ -96,24 +96,27 @@ static void wifi_driver_can_start_on_APP_CPU_task(void* arg)
TEST_ESP_OK(event_deinit());
ESP_LOGI(TAG, EMPH_STR("nvs_flash_deinit..."));
TEST_ESP_OK(nvs_flash_deinit());
xSemaphoreGive(*sema);
ESP_LOGI(TAG, "exit task...");
vTaskDelete(NULL);
xSemaphoreGive(*sema);
vTaskSuspend(NULL);
}
TEST_CASE("wifi driver can start on APP CPU", "[wifi_init]")
{
TaskHandle_t th;
TaskHandle_t th = NULL;
SemaphoreHandle_t sema = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(sema);
printf("Creating tasks\n");
#ifndef CONFIG_FREERTOS_UNICORE
xTaskCreatePinnedToCore(wifi_driver_can_start_on_APP_CPU_task, "wifi_driver_can_start_on_APP_CPU_task", 2048*2, &sema, 3, &th, 1);
#else
xTaskCreate(wifi_driver_can_start_on_APP_CPU_task, "wifi_driver_can_start_on_APP_CPU_task", 2048*2, &sema, 3, &th);
#endif
TEST_ASSERT_NOT_NULL(th);
xSemaphoreTake(sema, portMAX_DELAY);
vSemaphoreDelete(sema);
sema = NULL;
test_utils_task_delete(th);
}
static void wifi_start_stop_task(void* arg)
@ -148,22 +151,25 @@ static void wifi_start_stop_task(void* arg)
nvs_flash_deinit();
ESP_LOGI(TAG, "test passed...");
xSemaphoreGive(*sema);
vTaskDelete(NULL);
vTaskSuspend(NULL);
}
TEST_CASE("Calling esp_wifi_stop() with start", "[wifi_init]")
{
TaskHandle_t th;
TaskHandle_t th = NULL;
SemaphoreHandle_t sema = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(sema);
printf("Creating tasks\n");
#ifndef CONFIG_FREERTOS_UNICORE
xTaskCreatePinnedToCore(wifi_start_stop_task, "wifi_start_stop_task", 2048*2, &sema, 3, &th, 0);
#else
xTaskCreate(wifi_start_stop_task, "wifi_start_stop_task", 2048*2, &sema, 3, &th);
#endif
TEST_ASSERT_NOT_NULL(th);
xSemaphoreTake(sema, portMAX_DELAY);
vSemaphoreDelete(sema);
sema = NULL;
test_utils_task_delete(th);
}
static void wifi_stop_task(void* arg)
@ -194,20 +200,23 @@ static void wifi_stop_task(void* arg)
nvs_flash_deinit();
ESP_LOGI(TAG, "test passed...");
xSemaphoreGive(*sema);
vTaskDelete(NULL);
vTaskSuspend(NULL);
}
TEST_CASE("Calling esp_wifi_stop() without start", "[wifi_init]")
{
TaskHandle_t th;
TaskHandle_t th = NULL;
SemaphoreHandle_t sema = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(sema);
printf("Creating tasks\n");
#ifndef CONFIG_FREERTOS_UNICORE
xTaskCreatePinnedToCore(wifi_stop_task, "wifi_stop_task", 2048*2, &sema, 3, &th, 0);
#else
xTaskCreate(wifi_stop_task, "wifi_stop_task", 2048*2, &sema, 3, &th);
#endif
TEST_ASSERT_NOT_NULL(th);
xSemaphoreTake(sema, portMAX_DELAY);
vSemaphoreDelete(sema);
sema = NULL;
test_utils_task_delete(th);
}

View file

@ -18,6 +18,8 @@
#include <stdint.h>
#include <esp_partition.h>
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
/* include performance pass standards header file */
#include "idf_performance.h"
@ -259,7 +261,6 @@ esp_err_t test_utils_set_leak_level(size_t leak_level, esp_type_leak_t type, esp
size_t test_utils_get_leak_level(esp_type_leak_t type, esp_comp_leak_t component);
typedef struct test_utils_exhaust_memory_record_s *test_utils_exhaust_memory_rec;
/**
@ -285,3 +286,9 @@ test_utils_exhaust_memory_rec test_utils_exhaust_memory(uint32_t caps, size_t li
void test_utils_free_exhausted_memory(test_utils_exhaust_memory_rec rec);
/**
* @brief Delete task ensuring dynamic memory (for stack, tcb etc.) gets freed up immediately
*
* @param[in] thandle Handle of task to be deleted (should not be NULL or self handle)
*/
void test_utils_task_delete(TaskHandle_t thandle);

View file

@ -19,6 +19,11 @@
#include "freertos/task.h"
#include "esp_netif.h"
#include "lwip/sockets.h"
#include "sdkconfig.h"
#if !CONFIG_FREERTOS_UNICORE
#include "esp_ipc.h"
#include "esp_freertos_hooks.h"
#endif
const esp_partition_t *get_test_data_partition(void)
{
@ -142,7 +147,6 @@ size_t test_utils_get_leak_level(esp_type_leak_t type_of_leak, esp_comp_leak_t c
return leak_level;
}
#define EXHAUST_MEMORY_ENTRIES 100
struct test_utils_exhaust_memory_record_s {
@ -179,3 +183,56 @@ void test_utils_free_exhausted_memory(test_utils_exhaust_memory_rec rec)
free(rec);
}
#if !CONFIG_FREERTOS_UNICORE
static SemaphoreHandle_t test_sem;
static bool test_idle_hook_func(void)
{
if (test_sem) {
xSemaphoreGive(test_sem);
}
return true;
}
static void test_task_delete_func(void *arg)
{
vTaskDelete(arg);
}
#endif // !CONFIG_FREERTOS_UNICORE
void test_utils_task_delete(TaskHandle_t thandle)
{
/* Self deletion can not free up associated task dynamic memory immediately,
* hence not recommended for test scenarios */
TEST_ASSERT_NOT_NULL_MESSAGE(thandle, "test_utils_task_delete: handle is NULL");
TEST_ASSERT_NOT_EQUAL_MESSAGE(thandle, xTaskGetCurrentTaskHandle(), "test_utils_task_delete: handle is of currently executing task");
#if CONFIG_FREERTOS_UNICORE
vTaskDelete(thandle);
#else // CONFIG_FREERTOS_UNICORE
const BaseType_t tsk_affinity = xTaskGetAffinity(thandle);
const uint32_t core_id = xPortGetCoreID();
printf("Task_affinity: 0x%x, current_core: %d\n", tsk_affinity, core_id);
if (tsk_affinity == tskNO_AFFINITY) {
/* For no affinity case, we wait for idle hook to trigger on different core */
esp_err_t ret = esp_register_freertos_idle_hook_for_cpu(test_idle_hook_func, !core_id);
TEST_ASSERT_EQUAL_MESSAGE(ret, ESP_OK, "test_utils_task_delete: failed to register idle hook");
vTaskDelete(thandle);
test_sem = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL_MESSAGE(test_sem, "test_utils_task_delete: failed to create semaphore");
xSemaphoreTake(test_sem, portMAX_DELAY);
esp_deregister_freertos_idle_hook_for_cpu(test_idle_hook_func, !core_id);
vSemaphoreDelete(test_sem);
test_sem = NULL;
} else if (tsk_affinity != core_id) {
/* Task affinity and current core are differnt, schedule IPC call (to delete task)
* on core where task is pinned to */
esp_ipc_call_blocking(tsk_affinity, test_task_delete_func, thandle);
} else {
/* Task affinity and current core are same, so we can safely proceed for deletion */
vTaskDelete(thandle);
}
#endif // !CONFIG_FREERTOS_UNICORE
}