github.com/lzhfromustc/gofuzz@v0.0.0-20211116160056-151b3108bbd1/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 "runtime" 10 "sync/atomic" 11 "unsafe" 12 ) 13 14 // There is a modified copy of this file in runtime/rwmutex.go. 15 // If you make any changes here, see if you should make them there. 16 17 // A RWMutex is a reader/writer mutual exclusion lock. 18 // The lock can be held by an arbitrary number of readers or a single writer. 19 // The zero value for a RWMutex is an unlocked mutex. 20 // 21 // A RWMutex must not be copied after first use. 22 // 23 // If a goroutine holds a RWMutex for reading and another goroutine might 24 // call Lock, no goroutine should expect to be able to acquire a read lock 25 // until the initial read lock is released. In particular, this prohibits 26 // recursive read locking. This is to ensure that the lock eventually becomes 27 // available; a blocked Lock call excludes new readers from acquiring the 28 // lock. 29 type RWMutex struct { 30 w Mutex // held if there are pending writers 31 writerSem uint32 // semaphore for writers to wait for completing readers 32 readerSem uint32 // semaphore for readers to wait for completing writers 33 readerCount int32 // number of pending readers 34 readerWait int32 // number of departing readers 35 36 ///MYCODE 37 Record TradRecord 38 Info runtime.RWMuInfo 39 } 40 41 const rwmutexMaxReaders = 1 << 30 42 43 // Happens-before relationships are indicated to the race detector via: 44 // - Unlock -> Lock: readerSem 45 // - Unlock -> RLock: readerSem 46 // - RUnlock -> Lock: writerSem 47 // 48 // The methods below temporarily disable handling of race synchronization 49 // events in order to provide the more precise model above to the race 50 // detector. 51 // 52 // For example, atomic.AddInt32 in RLock should not appear to provide 53 // acquire-release semantics, which would incorrectly synchronize racing 54 // readers, thus potentially missing races. 55 56 // RLock locks rw for reading. 57 // 58 // It should not be used for recursive read locking; a blocked Lock 59 // call excludes new readers from acquiring the lock. See the 60 // documentation on the RWMutex type. 61 func (rw *RWMutex) RLock() { 62 ///MYCODE: 63 blockEntry := runtime.EnqueueBlockEntry([]runtime.PrimInfo{&rw.Info}, runtime.MuLock) 64 defer runtime.DequeueBlockEntry(blockEntry) 65 runtime.Monitor(&rw.Info) 66 67 if runtime.BoolRecordTrad { 68 runtime.RecordTradOp(&rw.Record.PreLoc) 69 } 70 71 if race.Enabled { 72 _ = rw.w.state 73 race.Disable() 74 } 75 if atomic.AddInt32(&rw.readerCount, 1) < 0 { 76 // A writer is pending, wait for it. 77 runtime_SemacquireMutex(&rw.readerSem, false, 0) 78 } 79 if race.Enabled { 80 race.Enable() 81 race.Acquire(unsafe.Pointer(&rw.readerSem)) 82 } 83 } 84 85 // RUnlock undoes a single RLock call; 86 // it does not affect other simultaneous readers. 87 // It is a run-time error if rw is not locked for reading 88 // on entry to RUnlock. 89 func (rw *RWMutex) RUnlock() { 90 ///MYCODE: 91 runtime.Monitor(&rw.Info) 92 if runtime.BoolRecordTrad { 93 runtime.RecordTradOp(&rw.Record.PreLoc) 94 } 95 96 if race.Enabled { 97 _ = rw.w.state 98 race.ReleaseMerge(unsafe.Pointer(&rw.writerSem)) 99 race.Disable() 100 } 101 if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 { 102 // Outlined slow-path to allow the fast-path to be inlined 103 rw.rUnlockSlow(r) 104 } 105 if race.Enabled { 106 race.Enable() 107 } 108 } 109 110 func (rw *RWMutex) rUnlockSlow(r int32) { 111 if r+1 == 0 || r+1 == -rwmutexMaxReaders { 112 race.Enable() 113 throw("sync: RUnlock of unlocked RWMutex") 114 } 115 // A writer is pending. 116 if atomic.AddInt32(&rw.readerWait, -1) == 0 { 117 // The last reader unblocks the writer. 118 runtime_Semrelease(&rw.writerSem, false, 1) 119 } 120 } 121 122 // Lock locks rw for writing. 123 // If the lock is already locked for reading or writing, 124 // Lock blocks until the lock is available. 125 func (rw *RWMutex) Lock() { 126 ///MYCODE: 127 blockEntry := runtime.EnqueueBlockEntry([]runtime.PrimInfo{&rw.Info}, runtime.MuLock) 128 defer runtime.DequeueBlockEntry(blockEntry) 129 runtime.Monitor(&rw.Info) 130 if runtime.BoolRecordTrad { 131 runtime.RecordTradOp(&rw.Record.PreLoc) 132 } 133 134 if race.Enabled { 135 _ = rw.w.state 136 race.Disable() 137 } 138 // First, resolve competition with other writers. 139 rw.w.Lock() 140 // Announce to readers there is a pending writer. 141 r := atomic.AddInt32(&rw.readerCount, -rwmutexMaxReaders) + rwmutexMaxReaders 142 // Wait for active readers. 143 if r != 0 && atomic.AddInt32(&rw.readerWait, r) != 0 { 144 runtime_SemacquireMutex(&rw.writerSem, false, 0) 145 } 146 if race.Enabled { 147 race.Enable() 148 race.Acquire(unsafe.Pointer(&rw.readerSem)) 149 race.Acquire(unsafe.Pointer(&rw.writerSem)) 150 } 151 } 152 153 // Unlock unlocks rw for writing. It is a run-time error if rw is 154 // not locked for writing on entry to Unlock. 155 // 156 // As with Mutexes, a locked RWMutex is not associated with a particular 157 // goroutine. One goroutine may RLock (Lock) a RWMutex and then 158 // arrange for another goroutine to RUnlock (Unlock) it. 159 func (rw *RWMutex) Unlock() { 160 ///MYCODE: 161 runtime.Monitor(&rw.Info) 162 if runtime.BoolRecordTrad { 163 runtime.RecordTradOp(&rw.Record.PreLoc) 164 } 165 166 if race.Enabled { 167 _ = rw.w.state 168 race.Release(unsafe.Pointer(&rw.readerSem)) 169 race.Disable() 170 } 171 172 // Announce to readers there is no active writer. 173 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders) 174 if r >= rwmutexMaxReaders { 175 race.Enable() 176 throw("sync: Unlock of unlocked RWMutex") 177 } 178 // Unblock blocked readers, if any. 179 for i := 0; i < int(r); i++ { 180 runtime_Semrelease(&rw.readerSem, false, 0) 181 } 182 // Allow other writers to proceed. 183 rw.w.Unlock() 184 if race.Enabled { 185 race.Enable() 186 } 187 } 188 189 // RLocker returns a Locker interface that implements 190 // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock. 191 func (rw *RWMutex) RLocker() Locker { 192 return (*rlocker)(rw) 193 } 194 195 type rlocker RWMutex 196 197 func (r *rlocker) Lock() { (*RWMutex)(r).RLock() } 198 func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }