diff --git a/sync/lock.go b/sync/lock.go index 9f01024627..3963c6bb58 100644 --- a/sync/lock.go +++ b/sync/lock.go @@ -18,8 +18,7 @@ type RWMutex struct { callDepth int maxLockTime time.Duration - outer sync.Mutex - inner sync.RWMutex + mu sync.RWMutex } // lockInfo contains information about when and how a lock call was made. @@ -67,10 +66,9 @@ func (rwm *RWMutex) threadedDeadlockFinder() { // Undo the deadlock and delete the entry from the map. if info.read { - rwm.inner.RUnlock() + rwm.mu.RUnlock() } else { - rwm.inner.Unlock() - rwm.outer.Unlock() + rwm.mu.Unlock() } delete(rwm.openLocks, id) } @@ -95,10 +93,9 @@ func (rwm *RWMutex) safeLock(read bool) int { // Lock the mutex. if read { - rwm.inner.RLock() + rwm.mu.RLock() } else { - rwm.outer.Lock() - rwm.inner.Lock() + rwm.mu.Lock() } // Safely register that a lock has been triggered. @@ -137,29 +134,13 @@ func (rwm *RWMutex) safeUnlock(read bool, id int) { // Remove the lock and delete the entry from the map. if read { - rwm.inner.RUnlock() + rwm.mu.RUnlock() } else { - rwm.inner.Unlock() - rwm.outer.Unlock() + rwm.mu.Unlock() } delete(rwm.openLocks, id) } -// safeDemote demotes a safelock from a Lock to a RLock. -func (rwm *RWMutex) safeDemote() { - rwm.openLocksMutex.Lock() - defer rwm.openLocksMutex.Unlock() - - // Demote the lock. Ordering is important. First the inner lock is released - // and then regrabbed as a readlock. Then the outer lock is released. - // Because no safelock can grab the inner lock as a writelock until it has - // the outer lock, there is no risk of changes being made during the - // transition. - rwm.inner.Unlock() - rwm.inner.RLock() - rwm.outer.Unlock() -} - // RLock will read lock the RWMutex. The return value must be used as input // when calling RUnlock. func (rwm *RWMutex) RLock() int { @@ -178,12 +159,6 @@ func (rwm *RWMutex) Lock() int { return rwm.safeLock(false) } -// Demote will demote the lock from a writelock to a readlock. Demote should -// only be called on a writelocked safelock. -func (rwm *RWMutex) Demote() { - rwm.safeDemote() -} - // Unlock will unlock the RWMutex. The return value of calling Lock must be // used as input. func (rwm *RWMutex) Unlock(id int) { diff --git a/sync/lock_test.go b/sync/lock_test.go index 2a0cbac2a6..1ad561101f 100644 --- a/sync/lock_test.go +++ b/sync/lock_test.go @@ -147,52 +147,3 @@ func TestLockSafety(t *testing.T) { t.Error("test took too long to complete") } } - -// TestDemote checks that lock demotion works correctly. -func TestDemote(t *testing.T) { - if testing.Short() { - t.SkipNow() - } - - startTime := time.Now().Unix() - value := 0 - safeLock := New(time.Second, 1) - _ = safeLock.Lock() - - readThreads := 100 - var wg sync.WaitGroup - wg.Add(readThreads) - for i := 0; i < readThreads; i++ { - go func() { - readID := safeLock.RLock() - defer safeLock.RUnlock(readID) - - if value != 1 { - t.Error("reading is not happening correctly") - } - - // Sleep 250 milliseconds after grabbing the readlock. Because - // there are a bunch of threads, if the readlocks are not grabbing - // the lock in parallel the test will take a long time. - time.Sleep(time.Millisecond * 250) - wg.Done() - }() - } - value = 1 - - // A combination of sleep and gosched to give priority to the other - // threads. - time.Sleep(time.Millisecond * 100) - runtime.Gosched() - time.Sleep(time.Millisecond * 100) - safeLock.Demote() - - // Wait for all of the threads to finish sleeping. - wg.Wait() - // Check that the whole test took under 3 seconds. If the readlocks were - // efficiently being grabbed in parallel, the test should be subtantially - // less than 3 seconds. - if time.Now().Unix()-startTime > 3 { - t.Error("test took too long to complete") - } -}