github.com/gitbookio/syncgroup@v0.0.0-20181003125046-3e73b2e6a972/mutex/rwmutex.go (about) 1 // Originally copied from https://golang.org/src/sync/rwmutex.go on Jan 5th 2017 2 // 3 // Key changes: 4 // - strip "race" checks 5 // - return number of active holders 6 7 // Copyright 2009 The Go Authors. All rights reserved. 8 // Use of this source code is governed by a BSD-style 9 // license that can be found in the LICENSE file. 10 11 package mutex 12 13 import ( 14 "sync/atomic" 15 "unsafe" 16 ) 17 18 // An RWMutex is a reader/writer mutual exclusion lock. 19 // The lock can be held by an arbitrary number of readers or a single writer. 20 // RWMutexes can be created as part of other structures; 21 // the zero value for a RWMutex is an unlocked mutex. 22 // 23 // An RWMutex must not be copied after first use. 24 // 25 // If a goroutine holds a RWMutex for reading, it must not expect this or any 26 // other goroutine to be able to also take the read lock until the first read 27 // lock is released. In particular, this prohibits recursive read locking. 28 // This is to ensure that the lock eventually becomes available; 29 // a blocked Lock call excludes new readers from acquiring the lock. 30 type RWMutex struct { 31 w Mutex // held if there are pending writers 32 writerSem uint32 // semaphore for writers to wait for completing readers 33 readerSem uint32 // semaphore for readers to wait for completing writers 34 readerCount int32 // number of pending readers 35 readerWait int32 // number of departing readers 36 } 37 38 const rwmutexMaxReaders = 1 << 30 39 40 // RLock locks rw for reading. 41 func (rw *RWMutex) RLock() { 42 if race_Enabled { 43 _ = rw.w.state 44 race_Disable() 45 } 46 if atomic.AddInt32(&rw.readerCount, 1) < 0 { 47 // A writer is pending, wait for it. 48 runtime_Semacquire(&rw.readerSem) 49 } 50 if race_Enabled { 51 race_Enable() 52 race_Acquire(unsafe.Pointer(&rw.readerSem)) 53 } 54 } 55 56 // RUnlock undoes a single RLock call; 57 // it does not affect other simultaneous readers. 58 // It is a run-time error if rw is not locked for reading 59 // on entry to RUnlock. 60 func (rw *RWMutex) RUnlock() { 61 if race_Enabled { 62 _ = rw.w.state 63 race_ReleaseMerge(unsafe.Pointer(&rw.writerSem)) 64 race_Disable() 65 } 66 if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { 67 if r+1 == 0 || r+1 == -rwmutexMaxReaders { 68 race_Enable() 69 panic("sync: RUnlock of unlocked RWMutex") 70 } 71 // A writer is pending. 72 if atomic.AddInt32(&rw.readerWait, -1) == 0 { 73 // The last reader unblocks the writer. 74 runtime_Semrelease(&rw.writerSem) 75 } 76 } 77 if race_Enabled { 78 race_Enable() 79 } 80 } 81 82 // Lock locks rw for writing. 83 // If the lock is already locked for reading or writing, 84 // Lock blocks until the lock is available. 85 func (rw *RWMutex) Lock() { 86 if race_Enabled { 87 _ = rw.w.state 88 race_Disable() 89 } 90 // First, resolve competition with other writers. 91 rw.w.Lock() 92 // Announce to readers there is a pending writer. 93 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders 94 // Wait for active readers. 95 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { 96 runtime_Semacquire(&rw.writerSem) 97 } 98 if race_Enabled { 99 race_Enable() 100 race_Acquire(unsafe.Pointer(&rw.readerSem)) 101 race_Acquire(unsafe.Pointer(&rw.writerSem)) 102 } 103 } 104 105 // Unlock unlocks rw for writing. It is a run-time error if rw is 106 // not locked for writing on entry to Unlock. 107 // 108 // As with Mutexes, a locked RWMutex is not associated with a particular 109 // goroutine. One goroutine may RLock (Lock) an RWMutex and then 110 // arrange for another goroutine to RUnlock (Unlock) it. 111 func (rw *RWMutex) Unlock() { 112 if race_Enabled { 113 _ = rw.w.state 114 race_Release(unsafe.Pointer(&rw.readerSem)) 115 race_Release(unsafe.Pointer(&rw.writerSem)) 116 race_Disable() 117 } 118 119 // Announce to readers there is no active writer. 120 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) 121 if r >= rwmutexMaxReaders { 122 race_Enable() 123 panic("sync: Unlock of unlocked RWMutex") 124 } 125 // Unblock blocked readers, if any. 126 for i := 0; i < int(r); i++ { 127 runtime_Semrelease(&rw.readerSem) 128 } 129 // Allow other writers to proceed. 130 rw.w.Unlock() 131 if race_Enabled { 132 race_Enable() 133 } 134 } 135 136 // RLocker returns a Locker interface that implements 137 // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. 138 func (rw *RWMutex) RLocker() Locker { 139 return (*rlocker)(rw) 140 } 141 142 type rlocker RWMutex 143 144 func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } 145 func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }