diff --git a/lib/model/model.go b/lib/model/model.go index 690c494c..dfb43754 100644 --- a/lib/model/model.go +++ b/lib/model/model.go @@ -172,8 +172,9 @@ func NewModel(cfg *config.Wrapper, id protocol.DeviceID, deviceName, clientName, // period. func (m *Model) StartDeadlockDetector(timeout time.Duration) { l.Infof("Starting deadlock detector with %v timeout", timeout) - deadlockDetect(m.fmut, timeout, "fmut") - deadlockDetect(m.pmut, timeout, "pmut") + detector := newDeadlockDetector(timeout) + detector.Watch("fmut", m.fmut) + detector.Watch("pmut", m.pmut) } // StartFolder constructs the folder service and starts it. diff --git a/lib/model/util.go b/lib/model/util.go index 46386ae0..6f943860 100644 --- a/lib/model/util.go +++ b/lib/model/util.go @@ -16,10 +16,23 @@ type Holder interface { Holder() (string, int) } -func deadlockDetect(mut sync.Locker, timeout time.Duration, name string) { +func newDeadlockDetector(timeout time.Duration) *deadlockDetector { + return &deadlockDetector{ + timeout: timeout, + lockers: make(map[string]sync.Locker), + } +} + +type deadlockDetector struct { + timeout time.Duration + lockers map[string]sync.Locker +} + +func (d *deadlockDetector) Watch(name string, mut sync.Locker) { + d.lockers[name] = mut go func() { for { - time.Sleep(timeout / 4) + time.Sleep(d.timeout / 4) ok := make(chan bool, 2) go func() { @@ -29,15 +42,17 @@ func deadlockDetect(mut sync.Locker, timeout time.Duration, name string) { }() go func() { - time.Sleep(timeout) + time.Sleep(d.timeout) ok <- false }() if r := <-ok; !r { msg := fmt.Sprintf("deadlock detected at %s", name) - if hmut, ok := mut.(Holder); ok { - holder, goid := hmut.Holder() - msg = fmt.Sprintf("deadlock detected at %s, current holder: %s at routine %d", name, holder, goid) + for otherName, otherMut := range d.lockers { + if otherHolder, ok := otherMut.(Holder); ok { + holder, goid := otherHolder.Holder() + msg += fmt.Sprintf("\n %s = current holder: %s at routine %d", otherName, holder, goid) + } } panic(msg) } diff --git a/lib/sync/sync.go b/lib/sync/sync.go index 89a042bd..b04b3d00 100644 --- a/lib/sync/sync.go +++ b/lib/sync/sync.go @@ -130,6 +130,10 @@ func (m *loggedRWMutex) RUnlock() { m.RWMutex.RUnlock() } +func (m *loggedRWMutex) Holder() (string, int) { + return m.lockedAt, m.goid +} + type loggedWaitGroup struct { sync.WaitGroup }