From: Andrew Gerrand Date: Mon, 25 Feb 2013 22:23:58 +0000 (+1100) Subject: time: handle very large sleep durations X-Git-Tag: go1.1rc2~851 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=89cf67eb20bb863b87f4093e4eade2851dc9c308;p=gostls13.git time: handle very large sleep durations Fixes #4903. R=golang-dev, daniel.morsing, dave, r CC=golang-dev https://golang.org/cl/7388056 --- diff --git a/src/pkg/time/sleep.go b/src/pkg/time/sleep.go index 657b669030..591fa27b09 100644 --- a/src/pkg/time/sleep.go +++ b/src/pkg/time/sleep.go @@ -22,6 +22,21 @@ type runtimeTimer struct { arg interface{} } +// when is a helper function for setting the 'when' field of a runtimeTimer. +// It returns what the time will be, in nanoseconds, Duration d in the future. +// If d is negative, it is ignored. If the returned value would be less than +// zero because of an overflow, MaxInt64 is returned. +func when(d Duration) int64 { + if d <= 0 { + return nano() + } + t := nano() + int64(d) + if t < 0 { + t = 1<<63 - 1 // math.MaxInt64 + } + return t +} + func startTimer(*runtimeTimer) func stopTimer(*runtimeTimer) bool @@ -49,7 +64,7 @@ func NewTimer(d Duration) *Timer { t := &Timer{ C: c, r: runtimeTimer{ - when: nano() + int64(d), + when: when(d), f: sendTime, arg: c, }, @@ -62,9 +77,9 @@ func NewTimer(d Duration) *Timer { // It returns true if the timer had been active, false if the timer had // expired or been stopped. func (t *Timer) Reset(d Duration) bool { - when := nano() + int64(d) + w := when(d) active := stopTimer(&t.r) - t.r.when = when + t.r.when = w startTimer(&t.r) return active } @@ -94,7 +109,7 @@ func After(d Duration) <-chan Time { func AfterFunc(d Duration, f func()) *Timer { t := &Timer{ r: runtimeTimer{ - when: nano() + int64(d), + when: when(d), f: goFunc, arg: f, }, diff --git a/src/pkg/time/sleep_test.go b/src/pkg/time/sleep_test.go index bcdaffc2ac..9908e220f0 100644 --- a/src/pkg/time/sleep_test.go +++ b/src/pkg/time/sleep_test.go @@ -293,3 +293,23 @@ func TestReset(t *testing.T) { } t.Error(err) } + +// Test that sleeping for an interval so large it overflows does not +// result in a short sleep duration. +func TestOverflowSleep(t *testing.T) { + const timeout = 25 * Millisecond + const big = Duration(int64(1<<63 - 1)) + select { + case <-After(big): + t.Fatalf("big timeout fired") + case <-After(timeout): + // OK + } + const neg = Duration(-1 << 63) + select { + case <-After(neg): + // OK + case <-After(timeout): + t.Fatalf("negative timeout didn't fire") + } +}