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_SemacquireMutex(&rw.readerSem, false, 0) 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 // Outlined slow-path to allow the fast-path to be inlined 70 rw.rUnlockSlow(r) 71 } 72 if race.Enabled { 73 race.Enable() 74 } 75 } 76 77 func (rw *RWMutex) rUnlockSlow(r int32) { 78 if r+1 == 0 || r+1 == -rwmutexMaxReaders { 79 race.Enable() 80 throw("sync: RUnlock of unlocked RWMutex") 81 } 82 // A writer is pending. 83 if atomic.AddInt32(&rw.readerWait, -1) == 0 { 84 // The last reader unblocks the writer. 85 runtime_Semrelease(&rw.writerSem, false, 1) 86 } 87 } 88 89 // Lock locks rw for writing. 90 // If the lock is already locked for reading or writing, 91 // Lock blocks until the lock is available. 92 func (rw *RWMutex) Lock() { 93 if race.Enabled { 94 _ = rw.w.state 95 race.Disable() 96 } 97 // First, resolve competition with other writers. 98 rw.w.Lock() 99 // Announce to readers there is a pending writer. 100 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders 101 // Wait for active readers. 102 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { 103 runtime_SemacquireMutex(&rw.writerSem, false, 0) 104 } 105 if race.Enabled { 106 race.Enable() 107 race.Acquire(unsafe.Pointer(&rw.readerSem)) 108 race.Acquire(unsafe.Pointer(&rw.writerSem)) 109 } 110 } 111 112 // Unlock unlocks rw for writing. It is a run-time error if rw is 113 // not locked for writing on entry to Unlock. 114 // 115 // As with Mutexes, a locked RWMutex is not associated with a particular 116 // goroutine. One goroutine may RLock (Lock) a RWMutex and then 117 // arrange for another goroutine to RUnlock (Unlock) it. 118 func (rw *RWMutex) Unlock() { 119 if race.Enabled { 120 _ = rw.w.state 121 race.Release(unsafe.Pointer(&rw.readerSem)) 122 race.Disable() 123 } 124 125 // Announce to readers there is no active writer. 126 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) 127 if r >= rwmutexMaxReaders { 128 race.Enable() 129 throw("sync: Unlock of unlocked RWMutex") 130 } 131 // Unblock blocked readers, if any. 132 for i := 0; i < int(r); i++ { 133 runtime_Semrelease(&rw.readerSem, false, 0) 134 } 135 // Allow other writers to proceed. 136 rw.w.Unlock() 137 if race.Enabled { 138 race.Enable() 139 } 140 } 141 142 // RLocker returns a Locker interface that implements 143 // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. 144 func (rw *RWMutex) RLocker() Locker { 145 return (*rlocker)(rw) 146 } 147 148 type rlocker RWMutex 149 150 func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } 151 func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() } 152
View as plain text