...
1
2
3
4
5 package poll
6
7 import "sync/atomic"
8
9
10
11
12 type fdMutex struct {
13 state uint64
14 rsema uint32
15 wsema uint32
16 }
17
18
19
20
21
22
23
24
25 const (
26 mutexClosed = 1 << 0
27 mutexRLock = 1 << 1
28 mutexWLock = 1 << 2
29 mutexRef = 1 << 3
30 mutexRefMask = (1<<20 - 1) << 3
31 mutexRWait = 1 << 23
32 mutexRMask = (1<<20 - 1) << 23
33 mutexWWait = 1 << 43
34 mutexWMask = (1<<20 - 1) << 43
35 )
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 func (mu *fdMutex) incref() bool {
52 for {
53 old := atomic.LoadUint64(&mu.state)
54 if old&mutexClosed != 0 {
55 return false
56 }
57 new := old + mutexRef
58 if new&mutexRefMask == 0 {
59 panic("inconsistent poll.fdMutex")
60 }
61 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
62 return true
63 }
64 }
65 }
66
67
68
69 func (mu *fdMutex) increfAndClose() bool {
70 for {
71 old := atomic.LoadUint64(&mu.state)
72 if old&mutexClosed != 0 {
73 return false
74 }
75
76 new := (old | mutexClosed) + mutexRef
77 if new&mutexRefMask == 0 {
78 panic("inconsistent poll.fdMutex")
79 }
80
81 new &^= mutexRMask | mutexWMask
82 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
83
84
85 for old&mutexRMask != 0 {
86 old -= mutexRWait
87 runtime_Semrelease(&mu.rsema)
88 }
89 for old&mutexWMask != 0 {
90 old -= mutexWWait
91 runtime_Semrelease(&mu.wsema)
92 }
93 return true
94 }
95 }
96 }
97
98
99
100 func (mu *fdMutex) decref() bool {
101 for {
102 old := atomic.LoadUint64(&mu.state)
103 if old&mutexRefMask == 0 {
104 panic("inconsistent poll.fdMutex")
105 }
106 new := old - mutexRef
107 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
108 return new&(mutexClosed|mutexRefMask) == mutexClosed
109 }
110 }
111 }
112
113
114
115 func (mu *fdMutex) rwlock(read bool) bool {
116 var mutexBit, mutexWait, mutexMask uint64
117 var mutexSema *uint32
118 if read {
119 mutexBit = mutexRLock
120 mutexWait = mutexRWait
121 mutexMask = mutexRMask
122 mutexSema = &mu.rsema
123 } else {
124 mutexBit = mutexWLock
125 mutexWait = mutexWWait
126 mutexMask = mutexWMask
127 mutexSema = &mu.wsema
128 }
129 for {
130 old := atomic.LoadUint64(&mu.state)
131 if old&mutexClosed != 0 {
132 return false
133 }
134 var new uint64
135 if old&mutexBit == 0 {
136
137 new = (old | mutexBit) + mutexRef
138 if new&mutexRefMask == 0 {
139 panic("inconsistent poll.fdMutex")
140 }
141 } else {
142
143 new = old + mutexWait
144 if new&mutexMask == 0 {
145 panic("inconsistent poll.fdMutex")
146 }
147 }
148 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
149 if old&mutexBit == 0 {
150 return true
151 }
152 runtime_Semacquire(mutexSema)
153
154 }
155 }
156 }
157
158
159
160 func (mu *fdMutex) rwunlock(read bool) bool {
161 var mutexBit, mutexWait, mutexMask uint64
162 var mutexSema *uint32
163 if read {
164 mutexBit = mutexRLock
165 mutexWait = mutexRWait
166 mutexMask = mutexRMask
167 mutexSema = &mu.rsema
168 } else {
169 mutexBit = mutexWLock
170 mutexWait = mutexWWait
171 mutexMask = mutexWMask
172 mutexSema = &mu.wsema
173 }
174 for {
175 old := atomic.LoadUint64(&mu.state)
176 if old&mutexBit == 0 || old&mutexRefMask == 0 {
177 panic("inconsistent poll.fdMutex")
178 }
179
180 new := (old &^ mutexBit) - mutexRef
181 if old&mutexMask != 0 {
182 new -= mutexWait
183 }
184 if atomic.CompareAndSwapUint64(&mu.state, old, new) {
185 if old&mutexMask != 0 {
186 runtime_Semrelease(mutexSema)
187 }
188 return new&(mutexClosed|mutexRefMask) == mutexClosed
189 }
190 }
191 }
192
193
194 func runtime_Semacquire(sema *uint32)
195 func runtime_Semrelease(sema *uint32)
196
197
198
199 func (fd *FD) incref() error {
200 if !fd.fdmu.incref() {
201 return errClosing(fd.isFile)
202 }
203 return nil
204 }
205
206
207
208
209 func (fd *FD) decref() error {
210 if fd.fdmu.decref() {
211 return fd.destroy()
212 }
213 return nil
214 }
215
216
217
218 func (fd *FD) readLock() error {
219 if !fd.fdmu.rwlock(true) {
220 return errClosing(fd.isFile)
221 }
222 return nil
223 }
224
225
226
227
228 func (fd *FD) readUnlock() {
229 if fd.fdmu.rwunlock(true) {
230 fd.destroy()
231 }
232 }
233
234
235
236 func (fd *FD) writeLock() error {
237 if !fd.fdmu.rwlock(false) {
238 return errClosing(fd.isFile)
239 }
240 return nil
241 }
242
243
244
245
246 func (fd *FD) writeUnlock() {
247 if fd.fdmu.rwunlock(false) {
248 fd.destroy()
249 }
250 }
251
View as plain text