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 // An 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 // An 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 // RLock locks rw for reading.
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() {
48 if atomic
.AddInt32(&rw
.readerCount
, 1) < 0 {
49 // A writer is pending, wait for it.
50 runtime_Semacquire(&rw
.readerSem
)
54 race
.Acquire(unsafe
.Pointer(&rw
.readerSem
))
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() {
65 race
.ReleaseMerge(unsafe
.Pointer(&rw
.writerSem
))
68 if r
:= atomic
.AddInt32(&rw
.readerCount
, -1); r
< 0 {
69 if r
+1 == 0 || r
+1 == -rwmutexMaxReaders
{
71 throw("sync: RUnlock of unlocked RWMutex")
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)
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() {
92 // First, resolve competition with other writers.
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
)
102 race
.Acquire(unsafe
.Pointer(&rw
.readerSem
))
103 race
.Acquire(unsafe
.Pointer(&rw
.writerSem
))
107 // Unlock unlocks rw for writing. It is a run-time error if rw is
108 // not locked for writing on entry to Unlock.
110 // As with Mutexes, a locked RWMutex is not associated with a particular
111 // goroutine. One goroutine may RLock (Lock) an RWMutex and then
112 // arrange for another goroutine to RUnlock (Unlock) it.
113 func (rw
*RWMutex
) Unlock() {
116 race
.Release(unsafe
.Pointer(&rw
.readerSem
))
117 race
.Release(unsafe
.Pointer(&rw
.writerSem
))
121 // Announce to readers there is no active writer.
122 r
:= atomic
.AddInt32(&rw
.readerCount
, rwmutexMaxReaders
)
123 if r
>= rwmutexMaxReaders
{
125 throw("sync: Unlock of unlocked RWMutex")
127 // Unblock blocked readers, if any.
128 for i
:= 0; i
< int(r
); i
++ {
129 runtime_Semrelease(&rw
.readerSem
, false)
131 // Allow other writers to proceed.
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
)
146 func (r
*rlocker
) Lock() { (*RWMutex
)(r
).RLock() }
147 func (r
*rlocker
) Unlock() { (*RWMutex
)(r
).RUnlock() }