@@ -7,131 +7,96 @@ import (
77
88type Mutex = task.Mutex
99
10- type RWMutex struct {
11- // waitingWriters are all of the tasks waiting for write locks.
12- waitingWriters task.Stack
13-
14- // waitingReaders are all of the tasks waiting for a read lock.
15- waitingReaders task.Stack
10+ //go:linkname runtimePanic runtime.runtimePanic
11+ func runtimePanic (msg string )
1612
17- // state is the current state of the RWMutex.
18- // Iff the mutex is completely unlocked, it contains rwMutexStateUnlocked (aka 0).
19- // Iff the mutex is write-locked, it contains rwMutexStateWLocked.
20- // While the mutex is read-locked, it contains the current number of readers.
21- state uint32
13+ type RWMutex struct {
14+ // Reader count, with the number of readers that currently have read-locked
15+ // this mutex.
16+ // The value can be in two states: one where 0 means no readers and another
17+ // where -rwMutexMaxReaders means no readers. A base of 0 is normal
18+ // uncontended operation, a base of -rwMutexMaxReaders means a writer has
19+ // the lock or is trying to get the lock. In the second case, readers should
20+ // wait until the reader count becomes non-negative again to give the writer
21+ // a chance to obtain the lock.
22+ readers task.Futex
23+
24+ // Writer futex, normally 0. If there is a writer waiting until all readers
25+ // have unlocked, this value is 1. It will be changed to a 2 (and get a
26+ // wake) when the last reader unlocks.
27+ writer task.Futex
28+
29+ // Writer lock. Held between Lock() and Unlock().
30+ writerLock Mutex
2231}
2332
24- const (
25- rwMutexStateUnlocked = uint32 (0 )
26- rwMutexStateWLocked = ^ uint32 (0 )
27- rwMutexMaxReaders = rwMutexStateWLocked - 1
28- )
33+ const rwMutexMaxReaders = 1 << 30
2934
3035func (rw * RWMutex ) Lock () {
31- if rw .state == 0 {
32- // The mutex is completely unlocked.
33- // Lock without waiting.
34- rw .state = rwMutexStateWLocked
36+ // Exclusive lock for writers.
37+ rw .writerLock .Lock ()
38+
39+ // Flag that we need to be awakened after the last read-lock unlocks.
40+ rw .writer .Store (1 )
41+
42+ // Signal to readers that they can't lock this mutex anymore.
43+ n := uint32 (rwMutexMaxReaders )
44+ waiting := rw .readers .Add (- n )
45+ if int32 (waiting ) == - rwMutexMaxReaders {
46+ // All readers were already unlocked, so we don't need to wait for them.
47+ rw .writer .Store (0 )
3548 return
3649 }
3750
38- // Wait for the lock to be released.
39- rw .waitingWriters .Push (task .Current ())
40- task .Pause ()
51+ // There is at least one reader.
52+ // Wait until all readers are unlocked. The last reader to unlock will set
53+ // rw.writer to 2 and awaken us.
54+ for rw .writer .Load () == 1 {
55+ rw .writer .Wait (1 )
56+ }
57+ rw .writer .Store (0 )
4158}
4259
4360func (rw * RWMutex ) Unlock () {
44- switch rw .state {
45- case rwMutexStateWLocked :
46- // This is correct.
47-
48- case rwMutexStateUnlocked :
49- // The mutex is already unlocked.
50- panic ("sync: unlock of unlocked RWMutex" )
51-
52- default :
53- // The mutex is read-locked instead of write-locked.
54- panic ("sync: write-unlock of read-locked RWMutex" )
61+ // Signal that new readers can lock this mutex.
62+ waiting := rw .readers .Add (rwMutexMaxReaders )
63+ if waiting != 0 {
64+ // Awaken all waiting readers.
65+ rw .readers .WakeAll ()
5566 }
5667
57- switch {
58- case rw .maybeUnblockReaders ():
59- // Switched over to read mode.
60-
61- case rw .maybeUnblockWriter ():
62- // Transferred to another writer.
63-
64- default :
65- // Nothing is waiting for the lock.
66- rw .state = rwMutexStateUnlocked
67- }
68+ // Done with this lock (next writer can try to get a lock).
69+ rw .writerLock .Unlock ()
6870}
6971
7072func (rw * RWMutex ) RLock () {
71- if rw .state == rwMutexStateWLocked {
72- // Wait for the write lock to be released.
73- rw .waitingReaders .Push (task .Current ())
74- task .Pause ()
75- return
76- }
73+ // Add us as a reader.
74+ newVal := rw .readers .Add (1 )
7775
78- if rw .state == rwMutexMaxReaders {
79- panic ("sync: too many readers on RWMutex" )
76+ // Wait until the RWMutex is available for readers.
77+ for int32 (newVal ) <= 0 {
78+ rw .readers .Wait (newVal )
79+ newVal = rw .readers .Load ()
8080 }
81-
82- // Increase the reader count.
83- rw .state ++
8481}
8582
8683func (rw * RWMutex ) RUnlock () {
87- switch rw .state {
88- case rwMutexStateUnlocked :
89- // The mutex is already unlocked.
90- panic ("sync: unlock of unlocked RWMutex" )
91-
92- case rwMutexStateWLocked :
93- // The mutex is write-locked instead of read-locked.
94- panic ("sync: read-unlock of write-locked RWMutex" )
95- }
96-
97- rw .state --
84+ // Remove us as a reader.
85+ one := uint32 (1 )
86+ readers := int32 (rw .readers .Add (- one ))
9887
99- if rw .state == rwMutexStateUnlocked {
100- // This was the last reader.
101- // Try to unblock a writer.
102- rw .maybeUnblockWriter ()
88+ // Check whether RUnlock was called too often.
89+ if readers == - 1 || readers == (- rwMutexMaxReaders )- 1 {
90+ runtimePanic ("sync: RUnlock of unlocked RWMutex" )
10391 }
104- }
10592
106- func (rw * RWMutex ) maybeUnblockReaders () bool {
107- var n uint32
108- for {
109- t := rw .waitingReaders .Pop ()
110- if t == nil {
111- break
93+ if readers == - rwMutexMaxReaders {
94+ // This was the last read lock. Check whether we need to wake up a write
95+ // lock.
96+ if rw .writer .CompareAndSwap (1 , 2 ) {
97+ rw .writer .Wake ()
11298 }
113-
114- n ++
115- scheduleTask (t )
116- }
117- if n == 0 {
118- return false
11999 }
120-
121- rw .state = n
122- return true
123- }
124-
125- func (rw * RWMutex ) maybeUnblockWriter () bool {
126- t := rw .waitingWriters .Pop ()
127- if t == nil {
128- return false
129- }
130-
131- rw .state = rwMutexStateWLocked
132- scheduleTask (t )
133-
134- return true
135100}
136101
137102type Locker interface {
0 commit comments