From 5b4afa044772e344eda597739812987001b9d3c5 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Mon, 29 Jun 2026 09:12:21 +0900 Subject: [PATCH] Avoid holding mutex while waking main loop on wait unblock Sending to serverInputChan while holding t.mutex could deadlock: if the channel fills, the send blocks with the mutex held while the main loop waits on the same mutex and can't drain the channel. Capture the wake-up need under the lock, send after releasing it. --- src/terminal.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/terminal.go b/src/terminal.go index 70d555a9..69243f5c 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -1882,14 +1882,13 @@ func (t *Terminal) UpdateList(result MatchResult) { merger := result.merger t.mutex.Lock() waitWasBlocked := t.waitBlocked + wakeUp := false if result.final() { t.searchInProgress = false // If waiting, unblock so main loop can execute pending actions if t.waitBlocked { t.unblockWait() - if len(t.pendingActions) > 0 { - t.serverInputChan <- []*action{{t: actIgnore}} - } + wakeUp = len(t.pendingActions) > 0 } } prevIndex := minItem.Index() @@ -2060,6 +2059,13 @@ func (t *Terminal) UpdateList(result MatchResult) { updatePrompt := (trackWasBlocked && !t.trackBlocked) || (waitWasBlocked && !t.waitBlocked) t.mutex.Unlock() + // Wake up the main loop to execute pending actions after wait unblocks. + // Send after releasing the mutex to avoid blocking on a full channel + // while holding it. + if wakeUp { + t.serverInputChan <- []*action{{t: actIgnore}} + } + t.reqBox.Set(reqInfo, nil) if updateList { t.reqBox.Set(reqList, nil)