From e5806212e82cc08b0648defcab617f17b2b19c01 Mon Sep 17 00:00:00 2001 From: Bruno Date: Tue, 5 May 2026 22:33:32 -0300 Subject: [PATCH] Improve websocketd_RxPutC semaphore handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The mutex now strictly guards the rxbuf head/tail/data update, matching the pattern already used by streamGetC, streamRxFlush, and websocketd_RxCancel. - enqueue_realtime_command is a function pointer that any plugin can override via streamSetRtHandler (e.g. MPG, keypad, macros, sender shims). rx_mux is created with xSemaphoreCreateMutex() (a non-recursive FreeRTOS mutex). If a custom handler ever calls back into websocketd_RxPutC (directly, or indirectly via stream code), the old version would attempt to take a mutex already held by the same task and block forever. The new version eliminates that hazard entirely. - websocketd_RxPutC runs from the lwIP/TCPIP task context (called from websocket_msg_parse inside websocket_recv). Holding rx_mux across an arbitrary, plugin-supplied callback meant the lwIP task could be blocked behind any work that handler did. The grbl protocol task also takes rx_mux in streamGetC to drain bytes — long handler execution under the lock would directly stall both the network RX path and grbl input. Shrinking the critical section to a few buffer-pointer updates removes that stall window and reduces the chance of a higher-priority task being held off by a lower-priority one. --- websocketd.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/websocketd.c b/websocketd.c index 969d962..bb3e7a3 100644 --- a/websocketd.c +++ b/websocketd.c @@ -311,15 +311,15 @@ bool websocketd_RxPutC (char c) // discard input if MPG has taken over... if((ok = streambuffers.session && streambuffers.session->state == WsState_Connected && hal.stream.type != StreamType_MPG)) { - if(xSemaphoreTake(rx_mux, portMAX_DELAY) == pdTRUE) { - if(!enqueue_realtime_command(c)) { // If not a real time command attempt to buffer it + if(!enqueue_realtime_command(c)) { + if(xSemaphoreTake(rx_mux, portMAX_DELAY) == pdTRUE) { uint_fast16_t next_head = BUFNEXT(streambuffers.rxbuf.head, streambuffers.rxbuf); if((overflow = next_head == streambuffers.rxbuf.tail)) // If buffer full streambuffers.rxbuf.overflow = true; // flag overflow streambuffers.rxbuf.data[streambuffers.rxbuf.head] = c; // add data to buffer streambuffers.rxbuf.head = next_head; // and update pointer + xSemaphoreGive(rx_mux); } - xSemaphoreGive(rx_mux); } }