@@ -6,131 +6,96 @@ import (
6
6
7
7
type Mutex = task.Mutex
8
8
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 )
15
11
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
21
30
}
22
31
23
- const (
24
- rwMutexStateUnlocked = uint32 (0 )
25
- rwMutexStateWLocked = ^ uint32 (0 )
26
- rwMutexMaxReaders = rwMutexStateWLocked - 1
27
- )
32
+ const rwMutexMaxReaders = 1 << 30
28
33
29
34
func (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 )
34
47
return
35
48
}
36
49
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 )
40
57
}
41
58
42
59
func (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 ()
54
65
}
55
66
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 ()
67
69
}
68
70
69
71
func (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 )
76
74
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 ()
79
79
}
80
-
81
- // Increase the reader count.
82
- rw .state ++
83
80
}
84
81
85
82
func (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 ))
97
86
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" )
102
90
}
103
- }
104
91
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 ()
111
97
}
112
-
113
- n ++
114
- scheduleTask (t )
115
- }
116
- if n == 0 {
117
- return false
118
98
}
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
134
99
}
135
100
136
101
type Locker interface {
0 commit comments