Revert "Set num_threads to 50 on 32-bit hppa in two libgomp loop tests"
[official-gcc.git] / libgo / go / sync / rwmutex.go
blobf0d4c9771a04907e9bb0c64586a9d49d71871b80
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.
5 package sync
7 import (
8 "internal/race"
9 "sync/atomic"
10 "unsafe"
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
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
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
45 // detector.
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() {
57 if race.Enabled {
58 _ = rw.w.state
59 race.Disable()
61 if atomic.AddInt32(&rw.readerCount, 1) < 0 {
62 // A writer is pending, wait for it.
63 runtime_SemacquireMutex(&rw.readerSem, false, 0)
65 if race.Enabled {
66 race.Enable()
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 {
77 if race.Enabled {
78 _ = rw.w.state
79 race.Disable()
81 for {
82 c := atomic.LoadInt32(&rw.readerCount)
83 if c < 0 {
84 if race.Enabled {
85 race.Enable()
87 return false
89 if atomic.CompareAndSwapInt32(&rw.readerCount, c, c+1) {
90 if race.Enabled {
91 race.Enable()
92 race.Acquire(unsafe.Pointer(&rw.readerSem))
94 return true
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() {
104 if race.Enabled {
105 _ = rw.w.state
106 race.ReleaseMerge(unsafe.Pointer(&rw.writerSem))
107 race.Disable()
109 if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
110 // Outlined slow-path to allow the fast-path to be inlined
111 rw.rUnlockSlow(r)
113 if race.Enabled {
114 race.Enable()
118 func (rw *RWMutex) rUnlockSlow(r int32) {
119 if r+1 == 0 || r+1 == -rwmutexMaxReaders {
120 race.Enable()
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() {
134 if race.Enabled {
135 _ = rw.w.state
136 race.Disable()
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)
146 if race.Enabled {
147 race.Enable()
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 {
159 if race.Enabled {
160 _ = rw.w.state
161 race.Disable()
163 if !rw.w.TryLock() {
164 if race.Enabled {
165 race.Enable()
167 return false
169 if !atomic.CompareAndSwapInt32(&rw.readerCount, 0, -rwmutexMaxReaders) {
170 rw.w.Unlock()
171 if race.Enabled {
172 race.Enable()
174 return false
176 if race.Enabled {
177 race.Enable()
178 race.Acquire(unsafe.Pointer(&rw.readerSem))
179 race.Acquire(unsafe.Pointer(&rw.writerSem))
181 return true
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() {
191 if race.Enabled {
192 _ = rw.w.state
193 race.Release(unsafe.Pointer(&rw.readerSem))
194 race.Disable()
197 // Announce to readers there is no active writer.
198 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
199 if r >= rwmutexMaxReaders {
200 race.Enable()
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.
208 rw.w.Unlock()
209 if race.Enabled {
210 race.Enable()
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)
220 type rlocker RWMutex
222 func (r *rlocker) Lock() { (*RWMutex)(r).RLock() }
223 func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }