From e5d55fe1b1ee8ddd67d7274282fb18ee24490da0 Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Wed, 16 Mar 2022 19:11:43 +0800 Subject: [PATCH] esp_ipc: Fix a case when ipc_task() can wake up blocking task early Closes https://github.com/espressif/esp-idf/issues/8559 --- components/esp_ipc/src/esp_ipc.c | 8 +++++--- components/esp_ipc/test/test_ipc.c | 26 ++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/components/esp_ipc/src/esp_ipc.c b/components/esp_ipc/src/esp_ipc.c index 68a8dd0d3d..a7583c7277 100644 --- a/components/esp_ipc/src/esp_ipc.c +++ b/components/esp_ipc/src/esp_ipc.c @@ -65,14 +65,17 @@ static void IRAM_ATTR ipc_task(void* arg) } #endif if (s_func[cpuid]) { + // we need to cache s_func, s_func_arg and s_ipc_wait variables locally because they can be changed by a subsequent IPC call. esp_ipc_func_t func = s_func[cpuid]; + s_func[cpuid] = NULL; void* arg = s_func_arg[cpuid]; + esp_ipc_wait_t ipc_wait = s_ipc_wait[cpuid]; - if (s_ipc_wait[cpuid] == IPC_WAIT_FOR_START) { + if (ipc_wait == IPC_WAIT_FOR_START) { xSemaphoreGive(s_ipc_ack[cpuid]); } (*func)(arg); - if (s_ipc_wait[cpuid] == IPC_WAIT_FOR_END) { + if (ipc_wait == IPC_WAIT_FOR_END) { xSemaphoreGive(s_ipc_ack[cpuid]); } } @@ -142,7 +145,6 @@ static esp_err_t esp_ipc_call_and_wait(uint32_t cpu_id, esp_ipc_func_t func, voi s_ipc_wait[cpu_id] = wait_for; xSemaphoreGive(s_ipc_sem[cpu_id]); xSemaphoreTake(s_ipc_ack[cpu_id], portMAX_DELAY); - s_func[cpu_id] = NULL; #ifdef CONFIG_ESP_IPC_USES_CALLERS_PRIORITY xSemaphoreGive(s_ipc_mutex[cpu_id]); #else diff --git a/components/esp_ipc/test/test_ipc.c b/components/esp_ipc/test/test_ipc.c index 9369b2524d..de19814b82 100644 --- a/components/esp_ipc/test/test_ipc.c +++ b/components/esp_ipc/test/test_ipc.c @@ -125,4 +125,30 @@ TEST_CASE("Test multiple ipc_calls", "[ipc]") } #endif /* CONFIG_ESP_IPC_USE_CALLERS_PRIORITY */ +static void test_func_ipc_cb2(void *arg) +{ + vTaskDelay(100 / portTICK_PERIOD_MS); + int *val = (int *)arg; + *val = *val + 1; +} + +static void test_func_ipc_cb3(void *arg) +{ + vTaskDelay(500 / portTICK_PERIOD_MS); + int *val = (int *)arg; + *val = *val + 1; +} + +TEST_CASE("Test ipc_task can not wake up blocking task early", "[ipc]") +{ + int val1 = 20; + esp_ipc_call(1, test_func_ipc_cb2, &val1); + TEST_ASSERT_EQUAL(20, val1); + + int val2 = 30; + esp_ipc_call_blocking(1, test_func_ipc_cb3, &val2); + TEST_ASSERT_EQUAL(21, val1); + TEST_ASSERT_EQUAL(31, val2); +} + #endif /* !CONFIG_FREERTOS_UNICORE */