@@ -56,14 +56,15 @@ 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)
62
63
rd int64 // read deadline
64
+ wseq uintptr // protects from stale write timers
63
65
wg uintptr // pdReady, pdWait, G waiting for write or nil
64
66
wt timer // write deadline timer
65
67
wd int64 // write deadline
66
- user uint32 // user settable cookie
67
68
}
68
69
69
70
type pollCache struct {
@@ -112,9 +113,10 @@ func poll_runtime_pollOpen(fd uintptr) (*pollDesc, int) {
112
113
}
113
114
pd .fd = fd
114
115
pd .closing = false
115
- pd .seq ++
116
+ pd .rseq ++
116
117
pd .rg = 0
117
118
pd .rd = 0
119
+ pd .wseq ++
118
120
pd .wg = 0
119
121
pd .wd = 0
120
122
unlock (& pd .lock )
@@ -197,17 +199,8 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
197
199
unlock (& pd .lock )
198
200
return
199
201
}
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.
202
+ rd0 , wd0 := pd .rd , pd .wd
203
+ combo0 := rd0 > 0 && rd0 == wd0
211
204
if d != 0 && d <= nanotime () {
212
205
d = - 1
213
206
}
@@ -217,28 +210,43 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) {
217
210
if mode == 'w' || mode == 'r' + 'w' {
218
211
pd .wd = d
219
212
}
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 )
213
+ combo := pd .rd > 0 && pd .rd == pd .wd
214
+ // Reset current timers if necessary.
215
+ if pd .rt .f != nil && (pd .rd != rd0 || combo != combo0 ) {
216
+ pd .rseq ++ // invalidate current timers
217
+ deltimer (& pd .rt )
218
+ pd .rt .f = nil
219
+ }
220
+ if pd .wt .f != nil && (pd .wd != wd0 || combo != combo0 ) {
221
+ pd .wseq ++ // invalidate current timers
222
+ deltimer (& pd .wt )
223
+ pd .wt .f = nil
224
+ }
225
+ // Setup new timers.
226
+ if combo {
227
+ if pd .rt .f == nil {
228
+ pd .rt .f = netpollDeadline
229
+ pd .rt .when = pd .rd
230
+ // Copy current seq into the timer arg.
231
+ // Timer func will check the seq against current descriptor seq,
232
+ // if they differ the descriptor was reused or timers were reset.
233
+ pd .rt .arg = pd
234
+ pd .rt .seq = pd .rseq
235
+ addtimer (& pd .rt )
236
+ }
229
237
} else {
230
- if pd .rd > 0 {
238
+ if pd .rd > 0 && pd . rt . f == nil {
231
239
pd .rt .f = netpollReadDeadline
232
240
pd .rt .when = pd .rd
233
241
pd .rt .arg = pd
234
- pd .rt .seq = pd .seq
242
+ pd .rt .seq = pd .rseq
235
243
addtimer (& pd .rt )
236
244
}
237
- if pd .wd > 0 {
245
+ if pd .wd > 0 && pd . wt . f == nil {
238
246
pd .wt .f = netpollWriteDeadline
239
247
pd .wt .when = pd .wd
240
248
pd .wt .arg = pd
241
- pd .wt .seq = pd .seq
249
+ pd .wt .seq = pd .wseq
242
250
addtimer (& pd .wt )
243
251
}
244
252
}
@@ -267,7 +275,8 @@ func poll_runtime_pollUnblock(pd *pollDesc) {
267
275
throw ("runtime: unblock on closing polldesc" )
268
276
}
269
277
pd .closing = true
270
- pd .seq ++
278
+ pd .rseq ++
279
+ pd .wseq ++
271
280
var rg , wg * g
272
281
atomicstorep (unsafe .Pointer (& rg ), nil ) // full memory barrier between store to closing and read of rg/wg in netpollunblock
273
282
rg = netpollunblock (pd , 'r' , false )
@@ -404,7 +413,11 @@ func netpolldeadlineimpl(pd *pollDesc, seq uintptr, read, write bool) {
404
413
lock (& pd .lock )
405
414
// Seq arg is seq when the timer was set.
406
415
// If it's stale, ignore the timer event.
407
- if seq != pd .seq {
416
+ currentSeq := pd .rseq
417
+ if ! read {
418
+ currentSeq = pd .wseq
419
+ }
420
+ if seq != currentSeq {
408
421
// The descriptor was reused or timers were reset.
409
422
unlock (& pd .lock )
410
423
return
0 commit comments