Jelajahi Sumber

Merge branch 'bugfix/handler_unregister_itself' into 'master'

esp_event: fix handler unregistering itself

See merge request espressif/esp-idf!6274
Angus Gratton 6 tahun lalu
induk
melakukan
fbbcade397
2 mengubah file dengan 76 tambahan dan 10 penghapusan
  1. 10 10
      components/esp_event/esp_event.c
  2. 66 0
      components/esp_event/test/esp32/test_event.c

+ 10 - 10
components/esp_event/esp_event.c

@@ -526,30 +526,30 @@ esp_err_t esp_event_loop_run(esp_event_loop_handle_t event_loop, TickType_t tick
 
 
         bool exec = false;
         bool exec = false;
 
 
-        esp_event_handler_instance_t *handler;
-        esp_event_loop_node_t *loop_node;
-        esp_event_base_node_t *base_node;
-        esp_event_id_node_t *id_node;
+        esp_event_handler_instance_t *handler, *temp_handler;
+        esp_event_loop_node_t *loop_node, *temp_node;
+        esp_event_base_node_t *base_node, *temp_base;
+        esp_event_id_node_t *id_node, *temp_id_node;
 
 
-        SLIST_FOREACH(loop_node, &(loop->loop_nodes), next) {
+        SLIST_FOREACH_SAFE(loop_node, &(loop->loop_nodes), next, temp_node) {
             // Execute loop level handlers
             // Execute loop level handlers
-            SLIST_FOREACH(handler, &(loop_node->handlers), next) {
+            SLIST_FOREACH_SAFE(handler, &(loop_node->handlers), next, temp_handler) {
                 handler_execute(loop, handler, post);
                 handler_execute(loop, handler, post);
                 exec |= true;
                 exec |= true;
             }
             }
 
 
-            SLIST_FOREACH(base_node, &(loop_node->base_nodes), next) {
+            SLIST_FOREACH_SAFE(base_node, &(loop_node->base_nodes), next, temp_base) {
                 if (base_node->base == post.base) {
                 if (base_node->base == post.base) {
                     // Execute base level handlers
                     // Execute base level handlers
-                    SLIST_FOREACH(handler, &(base_node->handlers), next) {
+                    SLIST_FOREACH_SAFE(handler, &(base_node->handlers), next, temp_handler) {
                         handler_execute(loop, handler, post);
                         handler_execute(loop, handler, post);
                         exec |= true;
                         exec |= true;
                     }
                     }
 
 
-                    SLIST_FOREACH(id_node, &(base_node->id_nodes), next) {
+                    SLIST_FOREACH_SAFE(id_node, &(base_node->id_nodes), next, temp_id_node) {
                         if (id_node->id == post.id) {
                         if (id_node->id == post.id) {
                             // Execute id level handlers
                             // Execute id level handlers
-                            SLIST_FOREACH(handler, &(id_node->handlers), next) {
+                            SLIST_FOREACH_SAFE(handler, &(id_node->handlers), next, temp_handler) {
                                 handler_execute(loop, handler, post);
                                 handler_execute(loop, handler, post);
                                 exec |= true;
                                 exec |= true;
                             }
                             }

+ 66 - 0
components/esp_event/test/esp32/test_event.c

@@ -254,6 +254,17 @@ static void test_handler_post_wo_task(void* event_handler_arg, esp_event_base_t
     }
     }
 }
 }
 
 
+static void test_handler_unregister_itself(void* event_handler_arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
+{
+    esp_event_loop_handle_t* loop = (esp_event_loop_handle_t*) event_data;
+    int* unregistered = (int*) event_handler_arg;
+
+    (*unregistered) += (event_base == s_test_base1 ? 0 : 10) + event_id + 1;
+
+    // Unregister this handler for this event
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_unregister_with(*loop, event_base, event_id, test_handler_unregister_itself));
+}
+
 static void test_post_from_handler_loop_task(void* args)
 static void test_post_from_handler_loop_task(void* args)
 {
 {
     esp_event_loop_handle_t event_loop = (esp_event_loop_handle_t) args;
     esp_event_loop_handle_t event_loop = (esp_event_loop_handle_t) args;
@@ -434,6 +445,61 @@ TEST_CASE("can unregister handler", "[event]")
     TEST_TEARDOWN();
     TEST_TEARDOWN();
 }
 }
 
 
+TEST_CASE("handler can unregister itself", "[event]")
+{
+    /* this test aims to verify that handlers can unregister themselves */
+
+    TEST_SETUP();
+
+    esp_event_loop_handle_t loop;
+    esp_event_loop_args_t loop_args = test_event_get_default_loop_args();
+
+    loop_args.task_name = NULL;
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_create(&loop_args, &loop));
+
+    int unregistered = 0;
+
+    /*
+     * s_test_base1, ev1 = 1
+     * s_test_base1, ev2 = 2 
+     * s_test_base2, ev1 = 11 
+     * s_test_base2, ev2 = 12
+     */
+    int expected_unregistered = 0;
+
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV1, test_handler_unregister_itself, &unregistered));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base1, TEST_EVENT_BASE1_EV2, test_handler_unregister_itself, &unregistered));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE2_EV1, test_handler_unregister_itself, &unregistered));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_handler_register_with(loop, s_test_base2, TEST_EVENT_BASE2_EV2, test_handler_unregister_itself, &unregistered));
+
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV2, &loop, sizeof(loop), portMAX_DELAY));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
+    expected_unregistered =  2;  // base1, ev2
+    TEST_ASSERT_EQUAL(expected_unregistered, unregistered);
+
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, &loop, sizeof(loop), portMAX_DELAY));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE2_EV1, &loop, sizeof(loop), portMAX_DELAY));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
+    expected_unregistered +=  1 + 11; // base1, ev1 +  base2, ev1
+    TEST_ASSERT_EQUAL(expected_unregistered, unregistered);
+
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE2_EV2, &loop, sizeof(loop), portMAX_DELAY));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
+    expected_unregistered += 12; //  base2, ev2
+    TEST_ASSERT_EQUAL(expected_unregistered, unregistered);
+
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV1, &loop, sizeof(loop), portMAX_DELAY));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base1, TEST_EVENT_BASE1_EV2, &loop, sizeof(loop), portMAX_DELAY));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE2_EV1, &loop, sizeof(loop), portMAX_DELAY));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_post_to(loop, s_test_base2, TEST_EVENT_BASE2_EV2, &loop, sizeof(loop), portMAX_DELAY));
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_run(loop, pdMS_TO_TICKS(10)));
+    TEST_ASSERT_EQUAL(expected_unregistered, unregistered); // all handlers unregistered
+
+    TEST_ASSERT_EQUAL(ESP_OK, esp_event_loop_delete(loop));
+
+    TEST_TEARDOWN();
+}
+
 TEST_CASE("can exit running loop at approximately the set amount of time", "[event]")
 TEST_CASE("can exit running loop at approximately the set amount of time", "[event]")
 {
 {
     /* this test aims to verify that running loop does not block indefinitely in cases where
     /* this test aims to verify that running loop does not block indefinitely in cases where