From 47378485c62214f8471152d23dc8292c5eaa70a9 Mon Sep 17 00:00:00 2001 From: Meet Patel Date: Tue, 25 Aug 2026 10:48:11 +0530 Subject: [PATCH 1/2] test(freertos): cover xTaskCreatePinnedToCore pinning semantics Existing cases used pinned create only as setup for utility queries. Assert that dynamic and static create keep the task on the requested core across yields, and that tskNO_AFFINITY stays unpinned. --- .../freertos/misc/test_idf_additions.c | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) diff --git a/components/freertos/test_apps/freertos/misc/test_idf_additions.c b/components/freertos/test_apps/freertos/misc/test_idf_additions.c index ea9fb734d89..8794f3a5ed1 100644 --- a/components/freertos/test_apps/freertos/misc/test_idf_additions.c +++ b/components/freertos/test_apps/freertos/misc/test_idf_additions.c @@ -25,6 +25,7 @@ /* Test ESP-IDF FreeRTOS API additions from idf_additions.h: - ...Create...WithCaps() / ...DeleteWithCaps() memory capability helpers + - xTaskCreatePinnedToCore() / xTaskCreateStaticPinnedToCore() pinning semantics - Task utility helpers (xTaskGetCoreID, xTaskGetStackStart, per-core handle queries, etc.) Run only these cases from the Unity menu with the [idf_additions] tag filter. @@ -633,3 +634,160 @@ TEST_CASE("IDF additions: ulTaskGetIdleRunTimeCounterForCore", "[freertos][idf_a } #endif /* CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS && !CONFIG_FREERTOS_SMP */ + +/* --------------------------------------------------------------------------------------------------------------------- + * xTaskCreatePinnedToCore / xTaskCreateStaticPinnedToCore pinning semantics + * --------------------------------------------------------------------------------------------------------------------- */ + +#define PIN_SEMANTICS_SAMPLES 5 +#define PIN_SEMANTICS_STACK_BYTES 2048 + +typedef struct { + TaskHandle_t parent; + BaseType_t requested_core; + BaseType_t samples[PIN_SEMANTICS_SAMPLES]; + TaskHandle_t self_handle; +} pin_semantics_ctx_t; + +static void drain_task_notifications(void) +{ + while (ulTaskNotifyTake(pdFALSE, 0) != 0) { + ; + } +} + +static void pin_semantics_task(void *arg) +{ + pin_semantics_ctx_t *ctx = (pin_semantics_ctx_t *)arg; + + ctx->self_handle = xTaskGetCurrentTaskHandle(); + for (int i = 0; i < PIN_SEMANTICS_SAMPLES; i++) { + ctx->samples[i] = xPortGetCoreID(); + if (ctx->requested_core != tskNO_AFFINITY) { + TEST_ASSERT_EQUAL(ctx->requested_core, ctx->samples[i]); + } else { + TEST_ASSERT_GREATER_OR_EQUAL(0, ctx->samples[i]); + TEST_ASSERT_LESS_THAN(CONFIG_FREERTOS_NUMBER_OF_CORES, ctx->samples[i]); + } + /* Yield and sleep so a wrongly pinned task would have a chance to migrate. */ + taskYIELD(); + vTaskDelay(1); + } + + xTaskNotifyGive(ctx->parent); + vTaskSuspend(NULL); +} + +static void verify_pin_samples(const pin_semantics_ctx_t *ctx) +{ + for (int i = 0; i < PIN_SEMANTICS_SAMPLES; i++) { + if (ctx->requested_core == tskNO_AFFINITY) { + TEST_ASSERT_GREATER_OR_EQUAL(0, ctx->samples[i]); + TEST_ASSERT_LESS_THAN(CONFIG_FREERTOS_NUMBER_OF_CORES, ctx->samples[i]); + } else { + TEST_ASSERT_EQUAL(ctx->requested_core, ctx->samples[i]); + } + } +} + +TEST_CASE("IDF additions: xTaskCreatePinnedToCore pinning semantics", "[freertos][idf_additions]") +{ + const TaskHandle_t parent = xTaskGetCurrentTaskHandle(); + + for (int core = 0; core < CONFIG_FREERTOS_NUMBER_OF_CORES; core++) { + pin_semantics_ctx_t ctx = { + .parent = parent, + .requested_core = core, + .self_handle = NULL, + }; + TaskHandle_t created = NULL; + + drain_task_notifications(); + + TEST_ASSERT_EQUAL(pdPASS, xTaskCreatePinnedToCore(pin_semantics_task, + "pin_dyn", + PIN_SEMANTICS_STACK_BYTES, + &ctx, + UNITY_FREERTOS_PRIORITY + 1, + &created, + core)); + TEST_ASSERT_NOT_NULL(created); + TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000))); + TEST_ASSERT_EQUAL_PTR(created, ctx.self_handle); + TEST_ASSERT_EQUAL(core, xTaskGetCoreID(created)); + verify_pin_samples(&ctx); + + vTaskDelete(created); + vTaskDelay(1); + } +} + +TEST_CASE("IDF additions: xTaskCreateStaticPinnedToCore pinning semantics", "[freertos][idf_additions]") +{ + static StackType_t pin_static_stack[PIN_SEMANTICS_STACK_BYTES / sizeof(StackType_t)]; + static StaticTask_t pin_static_tcb; + const TaskHandle_t parent = xTaskGetCurrentTaskHandle(); + + for (int core = 0; core < CONFIG_FREERTOS_NUMBER_OF_CORES; core++) { + pin_semantics_ctx_t ctx = { + .parent = parent, + .requested_core = core, + .self_handle = NULL, + }; + + memset(&pin_static_tcb, 0, sizeof(pin_static_tcb)); + drain_task_notifications(); + + TaskHandle_t created = xTaskCreateStaticPinnedToCore(pin_semantics_task, + "pin_static", + PIN_SEMANTICS_STACK_BYTES, + &ctx, + UNITY_FREERTOS_PRIORITY + 1, + pin_static_stack, + &pin_static_tcb, + core); + TEST_ASSERT_NOT_NULL(created); + TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000))); + TEST_ASSERT_EQUAL_PTR(created, ctx.self_handle); + TEST_ASSERT_EQUAL(core, xTaskGetCoreID(created)); + verify_pin_samples(&ctx); + + vTaskDelete(created); + vTaskDelay(1); + } +} + +TEST_CASE("IDF additions: xTaskCreatePinnedToCore tskNO_AFFINITY", "[freertos][idf_additions]") +{ + pin_semantics_ctx_t ctx = { + .parent = xTaskGetCurrentTaskHandle(), + .requested_core = tskNO_AFFINITY, + .self_handle = NULL, + }; + TaskHandle_t created = NULL; + + drain_task_notifications(); + + TEST_ASSERT_EQUAL(pdPASS, xTaskCreatePinnedToCore(pin_semantics_task, + "pin_any", + PIN_SEMANTICS_STACK_BYTES, + &ctx, + UNITY_FREERTOS_PRIORITY + 1, + &created, + tskNO_AFFINITY)); + TEST_ASSERT_NOT_NULL(created); + TEST_ASSERT_NOT_EQUAL(0, ulTaskNotifyTake(pdFALSE, pdMS_TO_TICKS(1000))); + TEST_ASSERT_EQUAL_PTR(created, ctx.self_handle); + verify_pin_samples(&ctx); + +#if CONFIG_FREERTOS_NUMBER_OF_CORES > 1 + TEST_ASSERT_EQUAL(tskNO_AFFINITY, xTaskGetCoreID(created)); +#else + /* Unicore treats tskNO_AFFINITY as core 0. */ + TEST_ASSERT_EQUAL(0, xTaskGetCoreID(created)); + TEST_ASSERT_EQUAL(0, ctx.samples[0]); +#endif + + vTaskDelete(created); + vTaskDelay(1); +} From 81155fe014f0f45e2a53ef44b6a995feec5eab80 Mon Sep 17 00:00:00 2001 From: Meet Patel Date: Thu, 27 Aug 2026 15:38:04 +0530 Subject: [PATCH 2/2] test(freertos): give pinned-create tests more stack 2048 bytes is tight once Unity asserts and yields run on the created task. --- .../freertos/test_apps/freertos/misc/test_idf_additions.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/components/freertos/test_apps/freertos/misc/test_idf_additions.c b/components/freertos/test_apps/freertos/misc/test_idf_additions.c index 8794f3a5ed1..24e16686281 100644 --- a/components/freertos/test_apps/freertos/misc/test_idf_additions.c +++ b/components/freertos/test_apps/freertos/misc/test_idf_additions.c @@ -640,7 +640,7 @@ TEST_CASE("IDF additions: ulTaskGetIdleRunTimeCounterForCore", "[freertos][idf_a * --------------------------------------------------------------------------------------------------------------------- */ #define PIN_SEMANTICS_SAMPLES 5 -#define PIN_SEMANTICS_STACK_BYTES 2048 +#define PIN_SEMANTICS_STACK_BYTES 4096 typedef struct { TaskHandle_t parent; @@ -757,6 +757,8 @@ TEST_CASE("IDF additions: xTaskCreateStaticPinnedToCore pinning semantics", "[fr } } +/* Create with tskNO_AFFINITY must succeed and run. Multicore stores no pin + * (xTaskGetCoreID == tskNO_AFFINITY); unicore treats it as core 0. */ TEST_CASE("IDF additions: xTaskCreatePinnedToCore tskNO_AFFINITY", "[freertos][idf_additions]") { pin_semantics_ctx_t ctx = {