test(freertos): Added miscellaneous stability fixes to unit tests

This commit adds fixes for freertos unit tests for a more deterministic
run and avoid occational failures.
This commit is contained in:
Sudeep Mohanty
2025-11-05 13:42:15 +05:30
parent 53fba0b5a1
commit e2699f8dde
4 changed files with 32 additions and 12 deletions
@@ -140,6 +140,9 @@ TEST_CASE("Task on specific core works", "[freertos][psram]")
TEST_ASSERT_EQUAL((size_t) corenum, corenum_info.recorded_core_num); TEST_ASSERT_EQUAL((size_t) corenum, corenum_info.recorded_core_num);
vTaskDelete(task_handle); vTaskDelete(task_handle);
// Add a short delay to allow the idle task to free any remaining task memory
vTaskDelay(10);
} }
} }
#endif // !CONFIG_FREERTOS_UNICORE #endif // !CONFIG_FREERTOS_UNICORE
@@ -387,6 +387,7 @@ TEST_CASE("Test vTaskSuspendAll allows scheduling on other cores", "[freertos]")
// Cleanup tasks // Cleanup tasks
vTaskDelete(a1_task_hdl); vTaskDelete(a1_task_hdl);
vTaskDelete(b1_task_hdl); vTaskDelete(b1_task_hdl);
vTaskDelay(10);
} }
vSemaphoreDelete(test_unblk_done_sem); vSemaphoreDelete(test_unblk_done_sem);
@@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@@ -34,6 +34,9 @@ static volatile uint32_t count;
// Lock variable to create a blocked task scenario // Lock variable to create a blocked task scenario
static volatile SemaphoreHandle_t task_mutex; static volatile SemaphoreHandle_t task_mutex;
// Semaphore to synchronize yield test tasks
static SemaphoreHandle_t yield_sync_sem;
// This helper macro is used to store the task id atomically // This helper macro is used to store the task id atomically
#define STORE_TASK_ID(task_id) ({ \ #define STORE_TASK_ID(task_id) ({ \
portENTER_CRITICAL(&idx_lock); \ portENTER_CRITICAL(&idx_lock); \
@@ -56,10 +59,11 @@ static void yield_task1(void *arg)
/* Store task_id in the sequence array */ /* Store task_id in the sequence array */
STORE_TASK_ID(task_id); STORE_TASK_ID(task_id);
/* Notify the yield_task2 to run */ /* Give semaphore to unblock yield_task2, making it READY (not just setting a flag).
task_sequence_ready = true; * This ensures task2 is in the ready queue when we yield. */
xSemaphoreGive(yield_sync_sem);
/* Yield */ /* Yield - now task2 is guaranteed to be READY and should run next */
taskYIELD(); taskYIELD();
/* Increment task count to notify unity task */ /* Increment task count to notify unity task */
@@ -73,10 +77,9 @@ static void yield_task2(void *arg)
{ {
uint32_t task_id = (uint32_t)arg; uint32_t task_id = (uint32_t)arg;
/* Wait for the other task to run for the test to begin */ /* Block on semaphore - this ensures task1 runs first and we don't poll.
while (!task_sequence_ready) { * When task1 gives the semaphore, we transition directly to READY state. */
vTaskDelay(10); xSemaphoreTake(yield_sync_sem, portMAX_DELAY);
};
/* Store task_id in the sequence array */ /* Store task_id in the sequence array */
STORE_TASK_ID(task_id); STORE_TASK_ID(task_id);
@@ -108,9 +111,16 @@ TEST_CASE("Task yield must run the next ready task of the same priority", "[free
/* Reset task sequence flag */ /* Reset task sequence flag */
task_sequence_ready = false; task_sequence_ready = false;
/* Create test tasks */ /* Create semaphore for synchronization - start empty so task2 blocks */
xTaskCreatePinnedToCore(yield_task1, "yield_task1", 2048, (void *)1, UNITY_FREERTOS_PRIORITY - 1, NULL, UNITY_FREERTOS_CPU); yield_sync_sem = xSemaphoreCreateBinary();
TEST_ASSERT_NOT_NULL(yield_sync_sem);
/* Create test tasks - order matters!
* Task2 is created first and will immediately block on the semaphore.
* Task1 is created second and will run first since task2 is blocked. */
xTaskCreatePinnedToCore(yield_task2, "yield_task2", 2048, (void *)2, UNITY_FREERTOS_PRIORITY - 1, NULL, UNITY_FREERTOS_CPU); xTaskCreatePinnedToCore(yield_task2, "yield_task2", 2048, (void *)2, UNITY_FREERTOS_PRIORITY - 1, NULL, UNITY_FREERTOS_CPU);
vTaskDelay(1); /* Ensure task2 has blocked on semaphore before creating task1 */
xTaskCreatePinnedToCore(yield_task1, "yield_task1", 2048, (void *)1, UNITY_FREERTOS_PRIORITY - 1, NULL, UNITY_FREERTOS_CPU);
/* Wait for the tasks to finish up */ /* Wait for the tasks to finish up */
while (count != 2) { while (count != 2) {
@@ -122,6 +132,9 @@ TEST_CASE("Task yield must run the next ready task of the same priority", "[free
/* Verify that the yield is successful and the next ready task is run */ /* Verify that the yield is successful and the next ready task is run */
TEST_ASSERT_EQUAL(1, task_yield_sequence[idx++]); TEST_ASSERT_EQUAL(1, task_yield_sequence[idx++]);
TEST_ASSERT_EQUAL(2, task_yield_sequence[idx++]); TEST_ASSERT_EQUAL(2, task_yield_sequence[idx++]);
/* Clean up semaphore */
vSemaphoreDelete(yield_sync_sem);
} }
/* /*
@@ -10,6 +10,7 @@
#include "freertos/semphr.h" #include "freertos/semphr.h"
#include "esp_pm.h" #include "esp_pm.h"
#include "esp_private/esp_clk.h" #include "esp_private/esp_clk.h"
#include "esp_clk_tree.h"
#include "sdkconfig.h" #include "sdkconfig.h"
@@ -66,9 +67,11 @@ static void consumer_task(void *arg)
TEST_CASE("Test semaphore timeout during tickless idle", "[freertos]") TEST_CASE("Test semaphore timeout during tickless idle", "[freertos]")
{ {
// Configure tickless idle // Configure tickless idle
uint32_t xtal_hz = 0;
esp_clk_tree_src_get_freq_hz(SOC_MOD_CLK_XTAL, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_hz);
esp_pm_config_t pm_config = { esp_pm_config_t pm_config = {
.max_freq_mhz = esp_clk_cpu_freq() / MHZ, .max_freq_mhz = CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ,
.min_freq_mhz = esp_clk_cpu_freq() / MHZ, .min_freq_mhz = xtal_hz / MHZ,
.light_sleep_enable = true, .light_sleep_enable = true,
}; };
TEST_ESP_OK(esp_pm_configure(&pm_config)); TEST_ESP_OK(esp_pm_configure(&pm_config));