lib: Consistently unsubscribe from config-wrapper (fixes #6133) (#6205)

This commit is contained in:
Simon Frei
2019-12-04 07:15:00 +01:00
committed by Jakob Borg
parent a9e490adfa
commit 6fd5e78740
5 changed files with 27 additions and 5 deletions

View File

@@ -94,6 +94,7 @@ type wrapper struct {
path string
evLogger events.Logger
waiter Waiter // Latest ongoing config change
deviceMap map[protocol.DeviceID]DeviceConfiguration
folderMap map[string]FolderConfiguration
subs []Committer
@@ -109,6 +110,7 @@ func Wrap(path string, cfg Configuration, evLogger events.Logger) Wrapper {
cfg: cfg,
path: path,
evLogger: evLogger,
waiter: noopWaiter{}, // Noop until first config change
mut: sync.NewMutex(),
}
return w
@@ -144,7 +146,8 @@ func (w *wrapper) Subscribe(c Committer) {
}
// Unsubscribe de-registers the given handler from any future calls to
// configuration changes
// configuration changes and only returns after a potential ongoing config
// change is done.
func (w *wrapper) Unsubscribe(c Committer) {
w.mut.Lock()
for i := range w.subs {
@@ -155,7 +158,11 @@ func (w *wrapper) Unsubscribe(c Committer) {
break
}
}
waiter := w.waiter
w.mut.Unlock()
// Waiting mustn't be done under lock, as the goroutines in notifyListener
// may dead-lock when trying to access lock on config read operations.
waiter.Wait()
}
// RawCopy returns a copy of the currently wrapped Configuration object.
@@ -191,7 +198,9 @@ func (w *wrapper) replaceLocked(to Configuration) (Waiter, error) {
w.deviceMap = nil
w.folderMap = nil
return w.notifyListeners(from.Copy(), to.Copy()), nil
w.waiter = w.notifyListeners(from.Copy(), to.Copy())
return w.waiter, nil
}
func (w *wrapper) notifyListeners(from, to Configuration) Waiter {