2
2
// Use of this source code is governed by a BSD-style
3
3
// license that can be found in the LICENSE file.
4
4
5
- // +build darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
5
+ // +build aix darwin dragonfly freebsd js,wasm linux nacl netbsd openbsd solaris windows
6
6
7
7
package runtime
8
8
@@ -56,9 +56,11 @@ type pollDesc struct {
56
56
lock mutex // protects the following fields
57
57
fd uintptr
58
58
closing bool
59
- seq uintptr // protects from stale timers and ready notifications
59
+ user uint32 // user settable cookie
60
+ rseq uintptr // protects from stale read timers
60
61
rg uintptr // pdReady, pdWait, G waiting for read or nil
61
62
rt timer // read deadline timer (set if rt.f != nil)
63
+ wseq uintptr // protects from stale write timers
62
64
rd int64 // read deadline
63
65
wg uintptr // pdReady, pdWait, G waiting for write or nil
64
66
wt timer // write deadline timer
@@ -92,12 +94,19 @@ func netpollinited() bool {
92
94
return atomic .Load (& netpollInited ) != 0
93
95
}
94
96
95
- //go:linkname poll_runtime_pollServerDescriptor internal/poll.runtime_pollServerDescriptor
97
+ //go:linkname poll_runtime_isPollServerDescriptor internal/poll.runtime_isPollServerDescriptor
96
98
97
- // poll_runtime_pollServerDescriptor returns the descriptor being used,
98
- // or ^uintptr(0) if the system does not use a poll descriptor.
99
- func poll_runtime_pollServerDescriptor () uintptr {
100
- return netpolldescriptor ()
99
+ // poll_runtime_isPollServerDescriptor reports whether fd is a
100
+ // descriptor being used by netpoll.
101
+ func poll_runtime_isPollServerDescriptor (fd uintptr ) bool {
102
+ fds := netpolldescriptor ()
103
+ if GOOS != "aix" {
104
+ return fd == fds
105
+ } else {
106
+ // AIX have a pipe in its netpoll implementation.
107
+ // Therefore, two fd are returned by netpolldescriptor using a mask.
108
+ return fd == fds & 0xFFFF || fd == (fds >> 16 )& 0xFFFF
109
+ }
101
110
}
102
111
103
112
//go:linkname poll_runtime_pollOpen internal/poll.runtime_pollOpen
@@ -112,9 +121,10 @@ func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
112
121
}
113
122
pd .fd = fd
114
123
pd .closing = false
115
- pd .seq ++
124
+ pd .rseq ++
116
125
pd .rg = 0
117
126
pd .rd = 0
127
+ pd .wseq ++
118
128
pd .wg = 0
119
129
pd .wd = 0
120
130
unlock (& pd .lock )
@@ -166,8 +176,8 @@ func poll_runtime_pollWait(pd *pollDesc, mode int) int {
166
176
if err != 0 {
167
177
return err
168
178
}
169
- // As for now only Solaris uses level-triggered IO.
170
- if GOOS == "solaris" {
179
+ // As for now only Solaris and AIX use level-triggered IO.
180
+ if GOOS == "solaris" || GOOS == "aix" {
171
181
netpollarm (pd , mode )
172
182
}
173
183
for ! netpollblock (pd , int32 (mode ), false ) {
@@ -197,59 +207,73 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
197
207
unlock (& pd .lock )
198
208
return
199
209
}
200
- pd .seq ++ // invalidate current timers
201
- // Reset current timers.
202
- if pd .rt .f != nil {
203
- deltimer (& pd .rt )
204
- pd .rt .f = nil
205
- }
206
- if pd .wt .f != nil {
207
- deltimer (& pd .wt )
208
- pd .wt .f = nil
209
- }
210
- // Setup new timers.
211
- if d != 0 && d <= nanotime () {
212
- d = - 1
210
+ rd0 , wd0 := pd .rd , pd .wd
211
+ combo0 := rd0 > 0 && rd0 == wd0
212
+ if d > 0 {
213
+ d += nanotime ()
214
+ if d <= 0 {
215
+ // If the user has a deadline in the future, but the delay calculation
216
+ // overflows, then set the deadline to the maximum possible value.
217
+ d = 1 << 63 - 1
218
+ }
213
219
}
214
220
if mode == 'r' || mode == 'r' + 'w' {
215
221
pd .rd = d
216
222
}
217
223
if mode == 'w' || mode == 'r' + 'w' {
218
224
pd .wd = d
219
225
}
220
- if pd .rd > 0 && pd .rd == pd .wd {
221
- pd .rt .f = netpollDeadline
222
- pd .rt .when = pd .rd
223
- // Copy current seq into the timer arg.
224
- // Timer func will check the seq against current descriptor seq,
225
- // if they differ the descriptor was reused or timers were reset.
226
- pd .rt .arg = pd
227
- pd .rt .seq = pd .seq
228
- addtimer (& pd .rt )
229
- } else {
226
+ combo := pd .rd > 0 && pd .rd == pd .wd
227
+ rtf := netpollReadDeadline
228
+ if combo {
229
+ rtf = netpollDeadline
230
+ }
231
+ if pd .rt .f == nil {
230
232
if pd .rd > 0 {
231
- pd .rt .f = netpollReadDeadline
233
+ pd .rt .f = rtf
232
234
pd .rt .when = pd .rd
235
+ // Copy current seq into the timer arg.
236
+ // Timer func will check the seq against current descriptor seq,
237
+ // if they differ the descriptor was reused or timers were reset.
233
238
pd .rt .arg = pd
234
- pd .rt .seq = pd .seq
239
+ pd .rt .seq = pd .rseq
235
240
addtimer (& pd .rt )
236
241
}
237
- if pd .wd > 0 {
242
+ } else if pd .rd != rd0 || combo != combo0 {
243
+ pd .rseq ++ // invalidate current timers
244
+ if pd .rd > 0 {
245
+ modtimer (& pd .rt , pd .rd , 0 , rtf , pd , pd .rseq )
246
+ } else {
247
+ deltimer (& pd .rt )
248
+ pd .rt .f = nil
249
+ }
250
+ }
251
+ if pd .wt .f == nil {
252
+ if pd .wd > 0 && ! combo {
238
253
pd .wt .f = netpollWriteDeadline
239
254
pd .wt .when = pd .wd
240
255
pd .wt .arg = pd
241
- pd .wt .seq = pd .seq
256
+ pd .wt .seq = pd .wseq
242
257
addtimer (& pd .wt )
243
258
}
259
+ } else if pd .wd != wd0 || combo != combo0 {
260
+ pd .wseq ++ // invalidate current timers
261
+ if pd .wd > 0 && ! combo {
262
+ modtimer (& pd .wt , pd .wd , 0 , netpollWriteDeadline , pd , pd .wseq )
263
+ } else {
264
+ deltimer (& pd .wt )
265
+ pd .wt .f = nil
266
+ }
244
267
}
245
268
// If we set the new deadline in the past, unblock currently pending IO if any.
246
- var rg , wg * g
247
- atomicstorep (unsafe .Pointer (& wg ), nil ) // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
248
- if pd .rd < 0 {
249
- rg = netpollunblock (pd , 'r' , false )
250
- }
251
- if pd .wd < 0 {
252
- wg = netpollunblock (pd , 'w' , false )
269
+ if pd .rd < 0 || pd .wd < 0 {
270
+ atomic .StorepNoWB (noescape (unsafe .Pointer (& wg )), nil ) // full memory barrier between stores to rd/wd and load of rg/wg in netpollunblock
271
+ if pd .rd < 0 {
272
+ rg = netpollunblock (pd , 'r' , false )
273
+ }
274
+ if pd .wd < 0 {
275
+ wg = netpollunblock (pd , 'w' , false )
276
+ }
253
277
}
254
278
unlock (& pd .lock )
255
279
if rg != nil {
@@ -267,9 +291,10 @@ func poll_runtime_pollUnblock(pd *pollDesc) {
267
291
throw ("runtime: unblock on closing polldesc" )
268
292
}
269
293
pd .closing = true
270
- pd .seq ++
294
+ pd .rseq ++
295
+ pd .wseq ++
271
296
var rg , wg * g
272
- atomicstorep ( unsafe .Pointer (& rg ), nil ) // full memory barrier between store to closing and read of rg/wg in netpollunblock
297
+ atomic . StorepNoWB ( noescape ( unsafe .Pointer (& rg ) ), nil ) // full memory barrier between store to closing and read of rg/wg in netpollunblock
273
298
rg = netpollunblock (pd , 'r' , false )
274
299
wg = netpollunblock (pd , 'w' , false )
275
300
if pd .rt .f != nil {
@@ -289,24 +314,22 @@ func poll_runtime_pollUnblock(pd *pollDesc) {
289
314
}
290
315
}
291
316
292
- // make pd ready, newly runnable goroutines (if any) are returned in rg/wg
317
+ // make pd ready, newly runnable goroutines (if any) are added to toRun.
293
318
// May run during STW, so write barriers are not allowed.
294
319
//go:nowritebarrier
295
- func netpollready (gpp * guintptr , pd * pollDesc , mode int32 ) {
296
- var rg , wg guintptr
320
+ func netpollready (toRun * gList , pd * pollDesc , mode int32 ) {
321
+ var rg , wg * g
297
322
if mode == 'r' || mode == 'r' + 'w' {
298
- rg . set ( netpollunblock (pd , 'r' , true ) )
323
+ rg = netpollunblock (pd , 'r' , true )
299
324
}
300
325
if mode == 'w' || mode == 'r' + 'w' {
301
- wg . set ( netpollunblock (pd , 'w' , true ) )
326
+ wg = netpollunblock (pd , 'w' , true )
302
327
}
303
- if rg != 0 {
304
- rg .ptr ().schedlink = * gpp
305
- * gpp = rg
328
+ if rg != nil {
329
+ toRun .push (rg )
306
330
}
307
- if wg != 0 {
308
- wg .ptr ().schedlink = * gpp
309
- * gpp = wg
331
+ if wg != nil {
332
+ toRun .push (wg )
310
333
}
311
334
}
312
335
@@ -406,7 +429,11 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
406
429
lock (& pd .lock )
407
430
// Seq arg is seq when the timer was set.
408
431
// If it's stale, ignore the timer event.
409
- if seq != pd .seq {
432
+ currentSeq := pd .rseq
433
+ if ! read {
434
+ currentSeq = pd .wseq
435
+ }
436
+ if seq != currentSeq {
410
437
// The descriptor was reused or timers were reset.
411
438
unlock (& pd .lock )
412
439
return
@@ -417,7 +444,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
417
444
throw ("runtime: inconsistent read deadline" )
418
445
}
419
446
pd .rd = - 1
420
- atomicstorep (unsafe .Pointer (& pd .rt .f ), nil ) // full memory barrier between store to rd and load of rg in netpollunblock
447
+ atomic . StorepNoWB (unsafe .Pointer (& pd .rt .f ), nil ) // full memory barrier between store to rd and load of rg in netpollunblock
421
448
rg = netpollunblock (pd , 'r' , false )
422
449
}
423
450
var wg * g
@@ -426,7 +453,7 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
426
453
throw ("runtime: inconsistent write deadline" )
427
454
}
428
455
pd .wd = - 1
429
- atomicstorep (unsafe .Pointer (& pd .wt .f ), nil ) // full memory barrier between store to wd and load of wg in netpollunblock
456
+ atomic . StorepNoWB (unsafe .Pointer (& pd .wt .f ), nil ) // full memory barrier between store to wd and load of wg in netpollunblock
430
457
wg = netpollunblock (pd , 'w' , false )
431
458
}
432
459
unlock (& pd .lock )
0 commit comments