]> granicus.if.org Git - esp-idf/commitdiff
driver(interrupt): fix the issue that interrupt might be allocated and freed on diffe...
authorkooho <2229179028@qq.com>
Thu, 20 Sep 2018 04:13:43 +0000 (12:13 +0800)
committerkooho <2229179028@qq.com>
Wed, 26 Sep 2018 02:31:09 +0000 (10:31 +0800)
closes https://github.com/espressif/esp-idf/issues/2211

components/esp32/include/esp_intr_alloc.h
components/esp32/intr_alloc.c
components/esp32/test/test_intr_alloc.c

index b5420f798173f4a9818562775e87d0f17741fd8c..edc4b9f2df33d833b63c16fbb2deecdc8f973c56 100644 (file)
@@ -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);
index 22d97ccc88f316868ed87abf2ed15e6b84fc7ad5..f99149702281dd61c4e423b3806a68a4cb1fcf44 100644 (file)
@@ -29,6 +29,7 @@
 #include "esp_intr.h"
 #include "esp_attr.h"
 #include "esp_intr_alloc.h"
+#include "esp_ipc.h"
 #include <limits.h>
 #include <assert.h>
 
@@ -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) {
index 0112814fa7bb94a1773210214cbe7cf7331cab00..f1313cff4c2b2a03110cddc407d9c7ead286c4b6 100644 (file)
@@ -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