Skip to content

Commit 250eebf

Browse files
committed
feat(websocket): add separate tx lock for send and receive
1 parent 462561b commit 250eebf

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

components/esp_websocket_client/Kconfig

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,17 @@ menu "ESP WebSocket client"
77
Enable this option will reallocated buffer when send or receive data and free them when end of use.
88
This can save about 2 KB memory when no websocket data send and receive.
99

10+
config ESP_WS_CLIENT_SEPARATE_TX_LOCK
11+
bool "Enable separate tx lock for send and receive data"
12+
default n
13+
help
14+
Enable this option will use separate lock for send and receive data.
15+
This can avoid the lock contention when send and receive data at the same time.
16+
17+
config ESP_WS_CLIENT_TX_LOCK_TIMEOUT_MS
18+
int "TX lock timeout in milliseconds"
19+
depends on ESP_WS_CLIENT_SEPARATE_TX_LOCK
20+
default 2000
21+
help
22+
Timeout for acquiring the TX lock when using separate TX lock.
1023
endmenu

components/esp_websocket_client/esp_websocket_client.c

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ static const char *TAG = "websocket_client";
3939
#define WEBSOCKET_KEEP_ALIVE_INTERVAL (5)
4040
#define WEBSOCKET_KEEP_ALIVE_COUNT (3)
4141

42+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
43+
#define WEBSOCKET_TX_LOCK_TIMEOUT_MS (CONFIG_ESP_WS_CLIENT_TX_LOCK_TIMEOUT_MS)
44+
#endif
45+
4246
#define ESP_WS_CLIENT_MEM_CHECK(TAG, a, action) if (!(a)) { \
4347
ESP_LOGE(TAG,"%s(%d): %s", __FUNCTION__, __LINE__, "Memory exhausted"); \
4448
action; \
@@ -131,6 +135,9 @@ struct esp_websocket_client {
131135
bool selected_for_destroying;
132136
EventGroupHandle_t status_bits;
133137
SemaphoreHandle_t lock;
138+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
139+
SemaphoreHandle_t tx_lock;
140+
#endif
134141
size_t errormsg_size;
135142
char *errormsg_buffer;
136143
char *rx_buffer;
@@ -441,6 +448,9 @@ static void destroy_and_free_resources(esp_websocket_client_handle_t client)
441448
esp_transport_list_destroy(client->transport_list);
442449
}
443450
vSemaphoreDelete(client->lock);
451+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
452+
vSemaphoreDelete(client->tx_lock);
453+
#endif
444454
free(client->tx_buffer);
445455
free(client->rx_buffer);
446456
free(client->errormsg_buffer);
@@ -610,10 +620,17 @@ static int esp_websocket_client_send_with_exact_opcode(esp_websocket_client_hand
610620
return -1;
611621
}
612622

623+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
624+
if (xSemaphoreTakeRecursive(client->tx_lock, timeout) != pdPASS) {
625+
ESP_LOGE(TAG, "Could not lock ws-client within %" PRIu32 " timeout", timeout);
626+
return -1;
627+
}
628+
#else
613629
if (xSemaphoreTakeRecursive(client->lock, timeout) != pdPASS) {
614630
ESP_LOGE(TAG, "Could not lock ws-client within %" PRIu32 " timeout", timeout);
615631
return -1;
616632
}
633+
#endif
617634

618635
if (esp_websocket_new_buf(client, true) != ESP_OK) {
619636
ESP_LOGE(TAG, "Failed to setup tx buffer");
@@ -653,7 +670,11 @@ static int esp_websocket_client_send_with_exact_opcode(esp_websocket_client_hand
653670
ret = widx;
654671

655672
unlock_and_return:
673+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
674+
xSemaphoreGiveRecursive(client->tx_lock);
675+
#else
656676
xSemaphoreGiveRecursive(client->lock);
677+
#endif
657678
return ret;
658679
}
659680

@@ -689,6 +710,11 @@ esp_websocket_client_handle_t esp_websocket_client_init(const esp_websocket_clie
689710
client->lock = xSemaphoreCreateRecursiveMutex();
690711
ESP_WS_CLIENT_MEM_CHECK(TAG, client->lock, goto _websocket_init_fail);
691712

713+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
714+
client->tx_lock = xSemaphoreCreateRecursiveMutex();
715+
ESP_WS_CLIENT_MEM_CHECK(TAG, client->tx_lock, goto _websocket_init_fail);
716+
#endif
717+
692718
client->config = calloc(1, sizeof(websocket_config_storage_t));
693719
ESP_WS_CLIENT_MEM_CHECK(TAG, client->config, goto _websocket_init_fail);
694720

@@ -967,8 +993,17 @@ static esp_err_t esp_websocket_client_recv(esp_websocket_client_handle_t client)
967993
if (client->last_opcode == WS_TRANSPORT_OPCODES_PING) {
968994
const char *data = (client->payload_len == 0) ? NULL : client->rx_buffer;
969995
ESP_LOGD(TAG, "Sending PONG with payload len=%d", client->payload_len);
996+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
997+
if (xSemaphoreTakeRecursive(client->tx_lock, WEBSOCKET_TX_LOCK_TIMEOUT_MS) != pdPASS) {
998+
ESP_LOGE(TAG, "Could not lock ws-client within %d timeout", WEBSOCKET_TX_LOCK_TIMEOUT_MS);
999+
return ESP_FAIL;
1000+
}
1001+
#endif
9701002
esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PONG | WS_TRANSPORT_OPCODES_FIN, data, client->payload_len,
9711003
client->config->network_timeout_ms);
1004+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
1005+
xSemaphoreGiveRecursive(client->tx_lock);
1006+
#endif
9721007
} else if (client->last_opcode == WS_TRANSPORT_OPCODES_PONG) {
9731008
client->wait_for_pong_resp = false;
9741009
} else if (client->last_opcode == WS_TRANSPORT_OPCODES_CLOSE) {
@@ -1050,8 +1085,16 @@ static void esp_websocket_client_task(void *pv)
10501085
if (_tick_get_ms() - client->ping_tick_ms > client->config->ping_interval_sec * 1000) {
10511086
client->ping_tick_ms = _tick_get_ms();
10521087
ESP_LOGD(TAG, "Sending PING...");
1088+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
1089+
if (xSemaphoreTakeRecursive(client->tx_lock, WEBSOCKET_TX_LOCK_TIMEOUT_MS) != pdPASS) {
1090+
ESP_LOGE(TAG, "Could not lock ws-client within %d timeout", WEBSOCKET_TX_LOCK_TIMEOUT_MS);
1091+
break;
1092+
}
1093+
#endif
10531094
esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_PING | WS_TRANSPORT_OPCODES_FIN, NULL, 0, client->config->network_timeout_ms);
1054-
1095+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
1096+
xSemaphoreGiveRecursive(client->tx_lock);
1097+
#endif
10551098
if (!client->wait_for_pong_resp && client->config->pingpong_timeout_sec) {
10561099
client->pingpong_tick_ms = _tick_get_ms();
10571100
client->wait_for_pong_resp = true;
@@ -1086,7 +1129,16 @@ static void esp_websocket_client_task(void *pv)
10861129
// if closing not initiated by the client echo the close message back
10871130
if ((CLOSE_FRAME_SENT_BIT & xEventGroupGetBits(client->status_bits)) == 0) {
10881131
ESP_LOGD(TAG, "Closing initiated by the server, sending close frame");
1132+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
1133+
if (xSemaphoreTakeRecursive(client->tx_lock, WEBSOCKET_TX_LOCK_TIMEOUT_MS) != pdPASS) {
1134+
ESP_LOGE(TAG, "Could not lock ws-client within %d timeout", WEBSOCKET_TX_LOCK_TIMEOUT_MS);
1135+
break;
1136+
}
1137+
#endif
10891138
esp_transport_ws_send_raw(client->transport, WS_TRANSPORT_OPCODES_CLOSE | WS_TRANSPORT_OPCODES_FIN, NULL, 0, client->config->network_timeout_ms);
1139+
#ifdef CONFIG_ESP_WS_CLIENT_SEPARATE_TX_LOCK
1140+
xSemaphoreGiveRecursive(client->tx_lock);
1141+
#endif
10901142
xEventGroupSetBits(client->status_bits, CLOSE_FRAME_SENT_BIT);
10911143
}
10921144
break;

0 commit comments

Comments
 (0)