2018-01-29 Richard Biener <rguenther@suse.de>
[official-gcc.git] / libgo / go / sync / rwmutex.go
blob4e9e8197c145590201d0df65c304332d76011a6e
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 // 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() {
44 if race.Enabled {
45 _ = rw.w.state
46 race.Disable()
48 if atomic.AddInt32(&rw.readerCount, 1) < 0 {
49 // A writer is pending, wait for it.
50 runtime_Semacquire(&rw.readerSem)
52 if race.Enabled {
53 race.Enable()
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() {
63 if race.Enabled {
64 _ = rw.w.state
65 race.ReleaseMerge(unsafe.Pointer(&rw.writerSem))
66 race.Disable()
68 if r := atomic.AddInt32(&rw.readerCount, -1); r < 0 {
69 if r+1 == 0 || r+1 == -rwmutexMaxReaders {
70 race.Enable()
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)
79 if race.Enabled {
80 race.Enable()
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() {
88 if race.Enabled {
89 _ = rw.w.state
90 race.Disable()
92 // First, resolve competition with other writers.
93 rw.w.Lock()
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)
100 if race.Enabled {
101 race.Enable()
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) a RWMutex and then
112 // arrange for another goroutine to RUnlock (Unlock) it.
113 func (rw *RWMutex) Unlock() {
114 if race.Enabled {
115 _ = rw.w.state
116 race.Release(unsafe.Pointer(&rw.readerSem))
117 race.Release(unsafe.Pointer(&rw.writerSem))
118 race.Disable()
121 // Announce to readers there is no active writer.
122 r := atomic.AddInt32(&rw.readerCount, rwmutexMaxReaders)
123 if r >= rwmutexMaxReaders {
124 race.Enable()
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.
132 rw.w.Unlock()
133 if race.Enabled {
134 race.Enable()
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)
144 type rlocker RWMutex
146 func (r *rlocker) Lock() { (*RWMutex)(r).RLock() }
147 func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }