]> Cypherpunks repositories - gostls13.git/commitdiff
time: handle very large sleep durations
authorAndrew Gerrand <adg@golang.org>
Mon, 25 Feb 2013 22:23:58 +0000 (09:23 +1100)
committerAndrew Gerrand <adg@golang.org>
Mon, 25 Feb 2013 22:23:58 +0000 (09:23 +1100)
Fixes #4903.

R=golang-dev, daniel.morsing, dave, r
CC=golang-dev
https://golang.org/cl/7388056

src/pkg/time/sleep.go
src/pkg/time/sleep_test.go

index 657b669030e5e3bb6770c04717d352d57eb7dff5..591fa27b090a2ffd3b0b719123d51ca9efddcf3c 100644 (file)
@@ -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,
                },
index bcdaffc2ac47c3da0e147bfb4b165860d6185ce4..9908e220f041817e640eab099d1f5a79789b8709 100644 (file)
@@ -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")
+       }
+}