threads: fix race warnings for client-side debouncing

Client-side thread debouncing happens in a different goroutine. Any
function or variable that is called or accessed by this goroutine should
be protected from a concurrent access.

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Koni Marti 2022-07-26 15:41:14 +02:00 committed by Robin Jarry
parent 54a0a377e0
commit 866867c616
2 changed files with 19 additions and 5 deletions

View file

@ -2,6 +2,7 @@ package lib
import ( import (
"io" "io"
"sync"
"time" "time"
"git.sr.ht/~rjarry/aerc/lib/sort" "git.sr.ht/~rjarry/aerc/lib/sort"
@ -19,7 +20,7 @@ type MessageStore struct {
// Ordered list of known UIDs // Ordered list of known UIDs
uids []uint32 uids []uint32
Threads []*types.Thread threads []*types.Thread
selectedUid uint32 selectedUid uint32
reselect *models.MessageInfo reselect *models.MessageInfo
@ -56,6 +57,8 @@ type MessageStore struct {
threadBuilderDebounce *time.Timer threadBuilderDebounce *time.Timer
threadBuilderDelay time.Duration threadBuilderDelay time.Duration
threadsMutex sync.Mutex
} }
const MagicUid = 0xFFFFFFFF const MagicUid = 0xFFFFFFFF
@ -238,7 +241,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
store.Messages = newMap store.Messages = newMap
store.uids = uids store.uids = uids
store.checkMark() store.checkMark()
store.Threads = msg.Threads store.threads = msg.Threads
update = true update = true
case *types.MessageInfo: case *types.MessageInfo:
if existing, ok := store.Messages[msg.Info.Uid]; ok && existing != nil { if existing, ok := store.Messages[msg.Info.Uid]; ok && existing != nil {
@ -313,7 +316,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
} }
store.results = newResults store.results = newResults
for _, thread := range store.Threads { for _, thread := range store.Threads() {
thread.Walk(func(t *types.Thread, _ int, _ error) error { thread.Walk(func(t *types.Thread, _ int, _ error) error {
if _, deleted := toDelete[t.Uid]; deleted { if _, deleted := toDelete[t.Uid]; deleted {
t.Deleted = true t.Deleted = true
@ -369,6 +372,12 @@ func (store *MessageStore) SetThreadedView(thread bool) {
store.Sort(store.sortCriteria, nil) store.Sort(store.sortCriteria, nil)
} }
func (store *MessageStore) Threads() []*types.Thread {
store.threadsMutex.Lock()
defer store.threadsMutex.Unlock()
return store.threads
}
func (store *MessageStore) ThreadedView() bool { func (store *MessageStore) ThreadedView() bool {
return store.threadedView return store.threadedView
} }
@ -390,7 +399,12 @@ func (store *MessageStore) runThreadBuilder() {
} }
} }
store.threadBuilderDebounce = time.AfterFunc(store.threadBuilderDelay, func() { store.threadBuilderDebounce = time.AfterFunc(store.threadBuilderDelay, func() {
store.Threads = store.builder.Threads(store.uids) th := store.builder.Threads(store.uids)
store.threadsMutex.Lock()
store.threads = th
store.threadsMutex.Unlock()
if store.onUpdate != nil { if store.onUpdate != nil {
store.onUpdate(store) store.onUpdate(store)
} }

View file

@ -88,7 +88,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
) )
if store.ThreadedView() { if store.ThreadedView() {
threads := store.Threads threads := store.Threads()
counter := len(store.Uids()) counter := len(store.Uids())
for i := len(threads) - 1; i >= 0; i-- { for i := len(threads) - 1; i >= 0; i-- {