diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go index 00701665f1..34e7c902eb 100644 --- a/src/runtime/netpoll.go +++ b/src/runtime/netpoll.go @@ -211,21 +211,13 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { pd.wd = d } combo := pd.rd > 0 && pd.rd == pd.wd - // Reset current timers if necessary. - if pd.rt.f != nil && (pd.rd != rd0 || combo != combo0) { - pd.rseq++ // invalidate current timers - deltimer(&pd.rt) - pd.rt.f = nil - } - if pd.wt.f != nil && (pd.wd != wd0 || combo != combo0) { - pd.wseq++ // invalidate current timers - deltimer(&pd.wt) - pd.wt.f = nil - } - // Setup new timers. + rtf := netpollReadDeadline if combo { - if pd.rt.f == nil { - pd.rt.f = netpollDeadline + rtf = netpollDeadline + } + if pd.rt.f == nil { + if pd.rd > 0 { + pd.rt.f = rtf pd.rt.when = pd.rd // Copy current seq into the timer arg. // Timer func will check the seq against current descriptor seq, @@ -234,21 +226,31 @@ func poll_runtime_pollSetDeadline(pd *pollDesc, d int64, mode int) { pd.rt.seq = pd.rseq addtimer(&pd.rt) } - } else { - if pd.rd > 0 && pd.rt.f == nil { - pd.rt.f = netpollReadDeadline - pd.rt.when = pd.rd - pd.rt.arg = pd - pd.rt.seq = pd.rseq - addtimer(&pd.rt) + } else if pd.rd != rd0 || combo != combo0 { + pd.rseq++ // invalidate current timers + if pd.rd > 0 { + modtimer(&pd.rt, pd.rd, 0, rtf, pd, pd.rseq) + } else { + deltimer(&pd.rt) + pd.rt.f = nil } - if pd.wd > 0 && pd.wt.f == nil { + } + if pd.wt.f == nil { + if pd.wd > 0 && !combo { pd.wt.f = netpollWriteDeadline pd.wt.when = pd.wd pd.wt.arg = pd pd.wt.seq = pd.wseq addtimer(&pd.wt) } + } else if pd.wd != wd0 || combo != combo0 { + pd.wseq++ // invalidate current timers + if pd.wd > 0 && !combo { + modtimer(&pd.wt, pd.wd, 0, netpollWriteDeadline, pd, pd.wseq) + } else { + deltimer(&pd.wt) + pd.wt.f = nil + } } // If we set the new deadline in the past, unblock currently pending IO if any. var rg, wg *g diff --git a/src/runtime/time.go b/src/runtime/time.go index 5e1a925dee..88fd319a90 100644 --- a/src/runtime/time.go +++ b/src/runtime/time.go @@ -187,14 +187,22 @@ func deltimer(t *timer) bool { tb := t.tb lock(&tb.lock) + removed, ok := tb.deltimerLocked(t) + unlock(&tb.lock) + if !ok { + badTimer() + } + return removed +} + +func (tb *timersBucket) deltimerLocked(t *timer) (removed, ok bool) { // t may not be registered anymore and may have // a bogus i (typically 0, if generated by Go). // Verify it before proceeding. i := t.i last := len(tb.t) - 1 if i < 0 || i > last || tb.t[i] != t { - unlock(&tb.lock) - return false + return false, true } if i != last { tb.t[i] = tb.t[last] @@ -202,7 +210,7 @@ func deltimer(t *timer) bool { } tb.t[last] = nil tb.t = tb.t[:last] - ok := true + ok = true if i != last { if !siftupTimer(tb.t, i) { ok = false @@ -211,11 +219,26 @@ func deltimer(t *timer) bool { ok = false } } + return true, ok +} + +func modtimer(t *timer, when, period int64, f func(interface{}, uintptr), arg interface{}, seq uintptr) { + tb := t.tb + + lock(&tb.lock) + _, ok := tb.deltimerLocked(t) + if ok { + t.when = when + t.period = period + t.f = f + t.arg = arg + t.seq = seq + ok = tb.addtimerLocked(t) + } unlock(&tb.lock) if !ok { badTimer() } - return true } // Timerproc runs the time-driven events.