From bbca0e46ed6ad2f0936533bd5ea5cfab10a0ddd4 Mon Sep 17 00:00:00 2001 From: kooho <2229179028@qq.com> Date: Thu, 20 Sep 2018 12:13:43 +0800 Subject: [PATCH] driver(interrupt): fix the issue that interrupt might be allocated and freed on different cores closes https://github.com/espressif/esp-idf/issues/2211 --- components/esp32/include/esp_intr_alloc.h | 11 ++++--- components/esp32/intr_alloc.c | 9 ++++-- components/esp32/test/test_intr_alloc.c | 38 +++++++++++++++++++++++ 3 files changed, 50 insertions(+), 8 deletions(-) diff --git a/components/esp32/include/esp_intr_alloc.h b/components/esp32/include/esp_intr_alloc.h index b5420f798..edc4b9f2d 100644 --- a/components/esp32/include/esp_intr_alloc.h +++ b/components/esp32/include/esp_intr_alloc.h @@ -194,18 +194,19 @@ esp_err_t esp_intr_alloc_intrstatus(int source, int flags, uint32_t intrstatusre /** * @brief Disable and free an interrupt. * - * Use an interrupt handle to disable the interrupt and release the resources - * associated with it. + * Use an interrupt handle to disable the interrupt and release the resources associated with it. + * If the current core is not the core that registered this interrupt, this routine will be assigned to + * the core that allocated this interrupt, blocking and waiting until the resource is successfully released. * * @note * When the handler shares its source with other handlers, the interrupt status * bits it's responsible for should be managed properly before freeing it. see - * ``esp_intr_disable`` for more details. + * ``esp_intr_disable`` for more details. Please do not call this function in ``esp_ipc_call_blocking``. * * @param handle The handle, as obtained by esp_intr_alloc or esp_intr_alloc_intrstatus * - * @return ESP_ERR_INVALID_ARG if handle is invalid, or esp_intr_free runs on another core than - * where the interrupt is allocated on. + * @return ESP_ERR_INVALID_ARG the handle is NULL + * ESP_FAIL failed to release this handle * ESP_OK otherwise */ esp_err_t esp_intr_free(intr_handle_t handle); diff --git a/components/esp32/intr_alloc.c b/components/esp32/intr_alloc.c index 22d97ccc8..f99149702 100644 --- a/components/esp32/intr_alloc.c +++ b/components/esp32/intr_alloc.c @@ -29,6 +29,7 @@ #include "esp_intr.h" #include "esp_attr.h" #include "esp_intr_alloc.h" +#include "esp_ipc.h" #include #include @@ -709,9 +710,11 @@ esp_err_t esp_intr_free(intr_handle_t handle) { bool free_shared_vector=false; if (!handle) return ESP_ERR_INVALID_ARG; - //This routine should be called from the interrupt the task is scheduled on. - if (handle->vector_desc->cpu!=xPortGetCoreID()) return ESP_ERR_INVALID_ARG; - + //Assign this routine to the core where this interrupt is allocated on. + if (handle->vector_desc->cpu!=xPortGetCoreID()) { + esp_err_t ret = esp_ipc_call_blocking(handle->vector_desc->cpu, (esp_ipc_func_t)&esp_intr_free, (void *)handle); + return ret == ESP_OK ? ESP_OK : ESP_FAIL; + } portENTER_CRITICAL(&spinlock); esp_intr_disable(handle); if (handle->vector_desc->flags&VECDESC_FL_SHARED) { diff --git a/components/esp32/test/test_intr_alloc.c b/components/esp32/test/test_intr_alloc.c index 0112814fa..f1313cff4 100644 --- a/components/esp32/test/test_intr_alloc.c +++ b/components/esp32/test/test_intr_alloc.c @@ -297,3 +297,41 @@ TEST_CASE("allocate 2 handlers for a same source and remove the later one","[esp TEST_ASSERT( ctx.flag3 && !ctx.flag4 ); printf("test passed.\n"); } + +#ifndef CONFIG_FREERTOS_UNICORE + +void isr_free_task(void *param) +{ + esp_err_t ret = ESP_FAIL; + intr_handle_t *test_handle = (intr_handle_t *)param; + if(*test_handle != NULL) { + ret = esp_intr_free(*test_handle); + if(ret == ESP_OK) { + *test_handle = NULL; + } + } + vTaskDelete(NULL); +} + +void isr_alloc_free_test(void) +{ + intr_handle_t test_handle = NULL; + esp_err_t ret = esp_intr_alloc(ETS_SPI2_INTR_SOURCE, 0, int_handler1, NULL, &test_handle); + if(ret != ESP_OK) { + printf("alloc isr handle fail\n"); + } else { + printf("alloc isr handle on core %d\n",esp_intr_get_cpu(test_handle)); + } + TEST_ASSERT(ret == ESP_OK); + xTaskCreatePinnedToCore(isr_free_task, "isr_free_task", 1024*2, (void *)&test_handle, 10, NULL, !xPortGetCoreID()); + vTaskDelay(1000/portTICK_RATE_MS); + TEST_ASSERT(test_handle == NULL); + printf("test passed\n"); +} + +TEST_CASE("alloc and free isr handle on different core", "[esp32]") +{ + isr_alloc_free_test(); +} + +#endif \ No newline at end of file