aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Culverhouse <tim@timculverhouse.com>2022-09-16 14:41:05 -0500
committerRobin Jarry <robin@jarry.cc>2022-09-20 00:03:36 +0200
commitf4d6ade429850aa30b5f6a8aefc3ef5a00c2e584 (patch)
tree0d2b97ffe799f9a5afee2b9a94eb0b0a4f2e0724
parente808b96d63ecab9990cbb295e786010be66243be (diff)
downloadaerc-f4d6ade429850aa30b5f6a8aefc3ef5a00c2e584.tar.gz
imap: prevent deadlock from posting actions to self
The IMAP worker has a few methods that post a new Action to itself. This can create a deadlock when the worker.Actions channel is full: The worker can't accept a new Action because it's trying to post an action. This is most noticeable when cached headers are enabled and the message list is scrolled fast. Use a goroutine to post actions to the worker when posting from within the worker. Fixes: https://todo.sr.ht/~rjarry/aerc/45 Fixes: 7aa71d334b27 ("imap: add option to cache headers") Signed-off-by: Tim Culverhouse <tim@timculverhouse.com> Acked-by: Robin Jarry <robin@jarry.cc>
-rw-r--r--worker/imap/cache.go3
-rw-r--r--worker/imap/flags.go6
-rw-r--r--worker/types/worker.go4
3 files changed, 10 insertions, 3 deletions
diff --git a/worker/imap/cache.go b/worker/imap/cache.go
index 62d450e6..3c807c50 100644
--- a/worker/imap/cache.go
+++ b/worker/imap/cache.go
@@ -126,7 +126,8 @@ func (w *IMAPWorker) getCachedHeaders(msg *types.FetchMessageHeaders) []uint32 {
}, nil)
}
if len(found) > 0 {
- w.worker.PostAction(&types.FetchMessageFlags{
+ // Post in a separate goroutine to prevent deadlocking
+ go w.worker.PostAction(&types.FetchMessageFlags{
Uids: found,
}, nil)
}
diff --git a/worker/imap/flags.go b/worker/imap/flags.go
index bda47e9d..0cd0bb78 100644
--- a/worker/imap/flags.go
+++ b/worker/imap/flags.go
@@ -48,7 +48,8 @@ func (imapw *IMAPWorker) handleAnsweredMessages(msg *types.AnsweredMessages) {
emitErr(err)
return
}
- imapw.worker.PostAction(&types.FetchMessageHeaders{
+ // Post in a separate goroutine to prevent deadlocking
+ go imapw.worker.PostAction(&types.FetchMessageHeaders{
Uids: msg.Uids,
}, func(_msg types.WorkerMessage) {
switch m := _msg.(type) {
@@ -79,7 +80,8 @@ func (imapw *IMAPWorker) handleFlagMessages(msg *types.FlagMessages) {
emitErr(err)
return
}
- imapw.worker.PostAction(&types.FetchMessageHeaders{
+ // Post in a separate goroutine to prevent deadlocking
+ go imapw.worker.PostAction(&types.FetchMessageHeaders{
Uids: msg.Uids,
}, func(_msg types.WorkerMessage) {
switch m := _msg.(type) {
diff --git a/worker/types/worker.go b/worker/types/worker.go
index 9e247982..ba396aa3 100644
--- a/worker/types/worker.go
+++ b/worker/types/worker.go
@@ -35,6 +35,8 @@ func (worker *Worker) setId(msg WorkerMessage) {
msg.setId(id)
}
+// PostAction posts an action to the worker. This method should not be called
+// from the same goroutine that the worker runs in or deadlocks may occur
func (worker *Worker) PostAction(msg WorkerMessage, cb func(msg WorkerMessage)) {
worker.setId(msg)
@@ -50,6 +52,8 @@ func (worker *Worker) PostAction(msg WorkerMessage, cb func(msg WorkerMessage))
}
}
+// PostMessage posts an message to the UI. This method should not be called
+// from the same goroutine that the UI runs in or deadlocks may occur
func (worker *Worker) PostMessage(msg WorkerMessage,
cb func(msg WorkerMessage),
) {