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