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.
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.
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.
20 // A RWMutex must not be copied after first use.
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
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
36 const rwmutexMaxReaders
= 1 << 30
38 // Happens-before relationships are indicated to the race detector via:
39 // - Unlock -> Lock: readerSem
40 // - Unlock -> RLock: readerSem
41 // - RUnlock -> Lock: writerSem
43 // The methods below temporarily disable handling of race synchronization
44 // events in order to provide the more precise model above to the race
47 // For example, atomic.AddInt32 in RLock should not appear to provide
48 // acquire-release semantics, which would incorrectly synchronize racing
49 // readers, thus potentially missing races.
51 // RLock locks rw for reading.
53 // It should not be used for recursive read locking; a blocked Lock
54 // call excludes new readers from acquiring the lock. See the
55 // documentation on the RWMutex type.
56 func (rw
*RWMutex
) RLock() {
61 if atomic
.AddInt32(&rw
.readerCount
, 1) < 0 {
62 // A writer is pending, wait for it.
63 runtime_SemacquireMutex(&rw
.readerSem
, false, 0)
67 race
.Acquire(unsafe
.Pointer(&rw
.readerSem
))
71 // TryRLock tries to lock rw for reading and reports whether it succeeded.
73 // Note that while correct uses of TryRLock do exist, they are rare,
74 // and use of TryRLock is often a sign of a deeper problem
75 // in a particular use of mutexes.
76 func (rw
*RWMutex
) TryRLock() bool {
82 c
:= atomic
.LoadInt32(&rw
.readerCount
)
89 if atomic
.CompareAndSwapInt32(&rw
.readerCount
, c
, c
+1) {
92 race
.Acquire(unsafe
.Pointer(&rw
.readerSem
))
99 // RUnlock undoes a single RLock call;
100 // it does not affect other simultaneous readers.
101 // It is a run-time error if rw is not locked for reading
102 // on entry to RUnlock.
103 func (rw
*RWMutex
) RUnlock() {
106 race
.ReleaseMerge(unsafe
.Pointer(&rw
.writerSem
))
109 if r
:= atomic
.AddInt32(&rw
.readerCount
, -1); r
< 0 {
110 // Outlined slow-path to allow the fast-path to be inlined
118 func (rw
*RWMutex
) rUnlockSlow(r
int32) {
119 if r
+1 == 0 || r
+1 == -rwmutexMaxReaders
{
121 throw("sync: RUnlock of unlocked RWMutex")
123 // A writer is pending.
124 if atomic
.AddInt32(&rw
.readerWait
, -1) == 0 {
125 // The last reader unblocks the writer.
126 runtime_Semrelease(&rw
.writerSem
, false, 1)
130 // Lock locks rw for writing.
131 // If the lock is already locked for reading or writing,
132 // Lock blocks until the lock is available.
133 func (rw
*RWMutex
) Lock() {
138 // First, resolve competition with other writers.
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)
148 race
.Acquire(unsafe
.Pointer(&rw
.readerSem
))
149 race
.Acquire(unsafe
.Pointer(&rw
.writerSem
))
153 // TryLock tries to lock rw for writing and reports whether it succeeded.
155 // Note that while correct uses of TryLock do exist, they are rare,
156 // and use of TryLock is often a sign of a deeper problem
157 // in a particular use of mutexes.
158 func (rw
*RWMutex
) TryLock() bool {
169 if !atomic
.CompareAndSwapInt32(&rw
.readerCount
, 0, -rwmutexMaxReaders
) {
178 race
.Acquire(unsafe
.Pointer(&rw
.readerSem
))
179 race
.Acquire(unsafe
.Pointer(&rw
.writerSem
))
184 // Unlock unlocks rw for writing. It is a run-time error if rw is
185 // not locked for writing on entry to Unlock.
187 // As with Mutexes, a locked RWMutex is not associated with a particular
188 // goroutine. One goroutine may RLock (Lock) a RWMutex and then
189 // arrange for another goroutine to RUnlock (Unlock) it.
190 func (rw
*RWMutex
) Unlock() {
193 race
.Release(unsafe
.Pointer(&rw
.readerSem
))
197 // Announce to readers there is no active writer.
198 r
:= atomic
.AddInt32(&rw
.readerCount
, rwmutexMaxReaders
)
199 if r
>= rwmutexMaxReaders
{
201 throw("sync: Unlock of unlocked RWMutex")
203 // Unblock blocked readers, if any.
204 for i
:= 0; i
< int(r
); i
++ {
205 runtime_Semrelease(&rw
.readerSem
, false, 0)
207 // Allow other writers to proceed.
214 // RLocker returns a Locker interface that implements
215 // the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
216 func (rw
*RWMutex
) RLocker() Locker
{
217 return (*rlocker
)(rw
)
222 func (r
*rlocker
) Lock() { (*RWMutex
)(r
).RLock() }
223 func (r
*rlocker
) Unlock() { (*RWMutex
)(r
).RUnlock() }