diff options
author | Robin Jarry <robin@jarry.cc> | 2023-05-17 16:13:43 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2023-05-20 22:09:43 +0200 |
commit | 916bca33ea6cf2530117071fdd9b7b15e00e2f29 (patch) | |
tree | 3d3a523e6af3fd330da17a114d49db148c45c5fc /commands | |
parent | 02099cc6ea29e8595f43abe5b6a475edc92e24e0 (diff) | |
download | aerc-916bca33ea6cf2530117071fdd9b7b15e00e2f29.tar.gz |
ui: fix deadlocks in message channel
There are several ways the ui message channel can fill up leading to
deadlocks.
1) Invalidate() changes the value of uiState to DIRTY. The following
call sequence:
QueueRedraw()
Invalidate()
QueueRedraw()
Leads to multiple nil messages being queued in the message channel
whereas one could assume that the second QueueRedraw() would do
nothing. This is caused by the tri-state nature of uiState.
2) We use the same channel to convey state change, keyboard events and
redraw requests. Since a keyboard event almost always triggers
a redraw, we end up trying to append a redraw message in the same
goroutine that reads from the channel. This triggers a deadlock when
there are more than 50 pending messages.
Solve the issue by using multiple channels, one per type of message that
needs to be sent to the main ui thread.
Remove QueueRedraw() and merge its functionality in Invalidate(). Only
use a DIRTY/CLEAN state to determine if something needs to be queued in
the redraw channel.
Use a channel for quitting instead of an atomic. Restructure some code
functions to have a cleaner API.
Use a for loop in the main thread and select from all channels.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Koni Marti <koni.marti@gmail.com>
Tested-by: Maarten van Gompel <proycon@anaproy.nl>
Diffstat (limited to 'commands')
-rw-r--r-- | commands/term.go | 2 |
1 files changed, 1 insertions, 1 deletions
diff --git a/commands/term.go b/commands/term.go index 64657747..22957635 100644 --- a/commands/term.go +++ b/commands/term.go @@ -43,7 +43,7 @@ func TermCore(aerc *widgets.Aerc, args []string) error { } if tab.Name != title { tab.Name = title - ui.QueueRedraw() + ui.Invalidate() } } term.OnClose = func(err error) { |