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