From 01a01de5947d3a72b7c3602e8564f8e6c88440d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Barna=C5=9B?= Date: Tue, 21 Sep 2021 14:19:11 +0200 Subject: [PATCH] shell: fix polling TXDONE signal by multiple threads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch fixes the issue that can cause a deadlock in shell. When two threads simultaneously poll the TXDONE signal, only one of them will receive it, leaving second one stalled. The problem was that shell's context contains k_poll_event objects that were polled by multiple threads. Polling it overwrites the poller field that was set by previous thread. Instead, the k_poll_event object must be created on the stack by every thread that wants to poll the TXDONE signal. This makes sure that no thread will be left waiting for this signal forever. Signed-off-by: Michał Barnaś --- include/shell/shell.h | 4 ++++ subsys/shell/shell_ops.c | 8 +++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/include/shell/shell.h b/include/shell/shell.h index 0af25a3ee77..04b07b83d50 100644 --- a/include/shell/shell.h +++ b/include/shell/shell.h @@ -698,6 +698,10 @@ struct shell_ctx { volatile union shell_internal internal; /*!< Internal shell data.*/ struct k_poll_signal signals[SHELL_SIGNALS]; + + /*!< Events that should be used only internally by shell thread. + * Event for SHELL_SIGNAL_TXDONE is initialized but unused. + */ struct k_poll_event events[SHELL_SIGNALS]; struct k_mutex wr_mtx; diff --git a/subsys/shell/shell_ops.c b/subsys/shell/shell_ops.c index d2a2a4048c8..b35b262fdd8 100644 --- a/subsys/shell/shell_ops.c +++ b/subsys/shell/shell_ops.c @@ -369,7 +369,13 @@ static void shell_pend_on_txdone(const struct shell *shell) { if (IS_ENABLED(CONFIG_MULTITHREADING) && (shell->ctx->state < SHELL_STATE_PANIC_MODE_ACTIVE)) { - k_poll(&shell->ctx->events[SHELL_SIGNAL_TXDONE], 1, K_FOREVER); + struct k_poll_event event; + + k_poll_event_init(&event, + K_POLL_TYPE_SIGNAL, + K_POLL_MODE_NOTIFY_ONLY, + &shell->ctx->signals[SHELL_SIGNAL_TXDONE]); + k_poll(&event, 1, K_FOREVER); k_poll_signal_reset(&shell->ctx->signals[SHELL_SIGNAL_TXDONE]); } else { /* Blocking wait in case of bare metal. */