Browse Source

lib/sync: Print all lockers, add holder to RWMutex

Audrius Butkevicius 9 years ago
parent
commit
7fba8cf759
3 changed files with 28 additions and 8 deletions
  1. 3 2
      lib/model/model.go
  2. 21 6
      lib/model/util.go
  3. 4 0
      lib/sync/sync.go

+ 3 - 2
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.

+ 21 - 6
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)
 			}

+ 4 - 0
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
 }