From d7c58ebc7ceacd556d18688160b449ddb1e354af Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 24 Dec 2013 13:40:48 -0800 Subject: [PATCH] syncutil: in RWMutexTracker, log.Fatal instead of panic on double-RLock Change-Id: Ifc34b29fb8264f96e2e9516948d9c0b4bfff984a --- pkg/syncutil/lock.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/pkg/syncutil/lock.go b/pkg/syncutil/lock.go index a208c4389..52de8e48c 100644 --- a/pkg/syncutil/lock.go +++ b/pkg/syncutil/lock.go @@ -115,12 +115,12 @@ func (m *RWMutexTracker) Lock() { atomic.AddInt32(&m.nhavew, 1) m.hmu.Lock() + defer m.hmu.Unlock() if len(m.holder) == 0 { m.holder = make([]byte, stackBufSize) } m.holder = m.holder[:runtime.Stack(m.holder[:stackBufSize], false)] log.Printf("Lock at %s", string(m.holder)) - m.hmu.Unlock() } func (m *RWMutexTracker) Unlock() { @@ -135,20 +135,34 @@ func (m *RWMutexTracker) Unlock() { func (m *RWMutexTracker) RLock() { m.logOnce.Do(m.startLogger) atomic.AddInt32(&m.nwaitr, 1) + + // Catch read-write-read lock. See if somebody (us? via + // another goroutine?) already has a read lock, and then + // somebody else is waiting to write, meaning our second read + // will deadlock. + if atomic.LoadInt32(&m.nhaver) > 0 && atomic.LoadInt32(&m.nwaitw) > 0 { + buf := getBuf() + buf = buf[:runtime.Stack(buf, false)] + log.Printf("Potential R-W-R deadlock at: %s", buf) + putBuf(buf) + } + m.mu.RLock() atomic.AddInt32(&m.nwaitr, -1) atomic.AddInt32(&m.nhaver, 1) gid := GoroutineID() m.hmu.Lock() + defer m.hmu.Unlock() if m.holdr == nil { m.holdr = make(map[int64]bool) } if m.holdr[gid] { - panic("Recursive call to RLock") + buf := getBuf() + buf = buf[:runtime.Stack(buf, false)] + log.Fatalf("Recursive call to RLock: %s", buf) } m.holdr[gid] = true - m.hmu.Unlock() } func stack() []byte {