Explorar el Código

Websocket client: avoid deadlock if stop called from event handler

Marius Vikhammer hace 5 años
padre
commit
c2bb0762bb

+ 18 - 1
components/esp_websocket_client/esp_websocket_client.c

@@ -87,6 +87,7 @@ typedef enum {
 
 struct esp_websocket_client {
     esp_event_loop_handle_t     event_handle;
+    TaskHandle_t                task_handle;
     esp_transport_list_handle_t transport_list;
     esp_transport_handle_t      transport;
     websocket_config_storage_t *config;
@@ -660,7 +661,7 @@ esp_err_t esp_websocket_client_start(esp_websocket_client_handle_t client)
         ESP_LOGE(TAG, "The client has started");
         return ESP_FAIL;
     }
-    if (xTaskCreate(esp_websocket_client_task, "websocket_task", client->config->task_stack, client, client->config->task_prio, NULL) != pdTRUE) {
+    if (xTaskCreate(esp_websocket_client_task, "websocket_task", client->config->task_stack, client, client->config->task_prio, &client->task_handle) != pdTRUE) {
         ESP_LOGE(TAG, "Error create websocket task");
         return ESP_FAIL;
     }
@@ -677,6 +678,15 @@ esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client)
         ESP_LOGW(TAG, "Client was not started");
         return ESP_FAIL;
     }
+
+    /* A running client cannot be stopped from the websocket task/event handler */
+    TaskHandle_t running_task = xTaskGetCurrentTaskHandle();
+    if (running_task == client->task_handle) {
+        ESP_LOGE(TAG, "Client cannot be stopped from websocket task");
+        return ESP_FAIL;
+    }
+
+
     client->run = false;
     xEventGroupWaitBits(client->status_bits, STOPPED_BIT, false, true, portMAX_DELAY);
     client->state = WEBSOCKET_STATE_UNKNOW;
@@ -711,6 +721,13 @@ static esp_err_t esp_websocket_client_close_with_optional_body(esp_websocket_cli
         return ESP_FAIL;
     }
 
+    /* A running client cannot be stopped from the websocket task/event handler */
+    TaskHandle_t running_task = xTaskGetCurrentTaskHandle();
+    if (running_task == client->task_handle) {
+        ESP_LOGE(TAG, "Client cannot be stopped from websocket task");
+        return ESP_FAIL;
+    }
+
     if (send_body) {
         esp_websocket_client_send_close(client, code, data, len + 2, portMAX_DELAY); // len + 2 -> always sending the code
     } else {

+ 12 - 0
components/esp_websocket_client/include/esp_websocket_client.h

@@ -132,6 +132,9 @@ esp_err_t esp_websocket_client_start(esp_websocket_client_handle_t client);
  * close frames. It is a good practice to close the connection in a clean way
  * using esp_websocket_client_close().
  *
+ *  Notes:
+ *  - Cannot be called from the websocket event handler 
+ *
  * @param[in]  client  The client
  *
  * @return     esp_err_t
@@ -144,6 +147,9 @@ esp_err_t esp_websocket_client_stop(esp_websocket_client_handle_t client);
  *             It is the opposite of the esp_websocket_client_init function and must be called with the same handle as input that a esp_websocket_client_init call returned.
  *             This might close all connections this handle has used.
  *
+ *  Notes:
+ *  - Cannot be called from the websocket event handler
+ * 
  * @param[in]  client  The client
  *
  * @return     esp_err_t
@@ -201,6 +207,9 @@ int esp_websocket_client_send_text(esp_websocket_client_handle_t client, const c
  * * Client waits until server closes the connection
  * * Client is stopped the same way as by the `esp_websocket_client_stop()`
  *
+ *  Notes:
+ *  - Cannot be called from the websocket event handler 
+ *
  * @param[in]  client  The client
  * @param[in]  timeout Timeout in RTOS ticks for waiting
  *
@@ -212,6 +221,9 @@ esp_err_t esp_websocket_client_close(esp_websocket_client_handle_t client, TickT
  * @brief      Close the WebSocket connection in a clean way with custom code/data
  *             Closing sequence is the same as for esp_websocket_client_close()
  *
+ *  Notes:
+ *  - Cannot be called from the websocket event handler 
+ *
  * @param[in]  client  The client
  * @param[in]  code    Close status code as defined in RFC6455 section-7.4
  * @param[in]  data    Additional data to closing message