]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: use monotonic clock for timers (linux/386, linux/amd64)
authorJay Weisskopf <jay@jayschwa.net>
Mon, 24 Feb 2014 15:57:46 +0000 (10:57 -0500)
committerRuss Cox <rsc@golang.org>
Mon, 24 Feb 2014 15:57:46 +0000 (10:57 -0500)
This lays the groundwork for making Go robust when the system's
calendar time jumps around. All input values to the runtimeTimer
struct now use the runtime clock as a common reference point.
This affects net.Conn.Set[Read|Write]Deadline(), time.Sleep(),
time.Timer, etc. Under normal conditions, behavior is unchanged.

Each platform and architecture's implementation of runtime·nanotime()
should be modified to use a monotonic system clock when possible.

Platforms/architectures modified and tested with monotonic clock:
  linux/x86     - clock_gettime(CLOCK_MONOTONIC)

Update #6007

LGTM=dvyukov, rsc
R=golang-codereviews, dvyukov, alex.brainman, stephen.gutekanst, dave, rsc, mikioh.mikioh
CC=golang-codereviews
https://golang.org/cl/53010043

src/pkg/net/fd_poll_runtime.go
src/pkg/runtime/netpoll.goc
src/pkg/runtime/sys_linux_386.s
src/pkg/runtime/sys_linux_amd64.s
src/pkg/runtime/time.goc
src/pkg/time/internal_test.go
src/pkg/time/sleep.go
src/pkg/time/tick.go

index e2b2768864afb537da731c8e6a9f9c0fec2275c1..549e19cd3f325365e63a7ff7869269ae55bc32be 100644 (file)
@@ -12,6 +12,9 @@ import (
        "time"
 )
 
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
+
 func runtime_pollServerInit()
 func runtime_pollOpen(fd uintptr) (uintptr, int)
 func runtime_pollClose(ctx uintptr)
@@ -128,7 +131,7 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
 }
 
 func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
-       d := t.UnixNano()
+       d := runtimeNano() + int64(t.Sub(time.Now()))
        if t.IsZero() {
                d = 0
        }
index 3f007073379395674196716e79b5f11014600f45..e78c02c9a78983bf758cd0de4fcd6fef523aefb1 100644 (file)
@@ -83,6 +83,11 @@ static FuncVal deadlineFn    = {(void(*)(void))deadline};
 static FuncVal readDeadlineFn  = {(void(*)(void))readDeadline};
 static FuncVal writeDeadlineFn = {(void(*)(void))writeDeadline};
 
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() (ns int64) {
+       ns = runtime·nanotime();
+}
+
 func runtime_pollServerInit() {
        runtime·netpollinit();
 }
index fcda739db4ae963a7fbcbd0ce4520c0b2198ed3a..cdd729957c51c138d371d258a7085089fc80ce87 100644 (file)
@@ -106,7 +106,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-24
 // func now() (sec int64, nsec int32)
 TEXT time·now(SB), NOSPLIT, $32
        MOVL    $265, AX                        // syscall - clock_gettime
-       MOVL    $0, BX
+       MOVL    $0, BX          // CLOCK_REALTIME
        LEAL    8(SP), CX
        MOVL    $0, DX
        CALL    *runtime·_vdso(SB)
@@ -123,7 +123,7 @@ TEXT time·now(SB), NOSPLIT, $32
 // void nanotime(int64 *nsec)
 TEXT runtime·nanotime(SB), NOSPLIT, $32
        MOVL    $265, AX                        // syscall - clock_gettime
-       MOVL    $0, BX
+       MOVL    $1, BX          // CLOCK_MONOTONIC
        LEAL    8(SP), CX
        MOVL    $0, DX
        CALL    *runtime·_vdso(SB)
index 481841a6744c9d4a648b7b095e2369b95b3f752a..74dc871db7110609f3d2f0b113e1fa462594bf67 100644 (file)
@@ -136,7 +136,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
        MOVQ    runtime·__vdso_clock_gettime_sym(SB), AX
        CMPQ    AX, $0
        JEQ     fallback_gtod_nt
-       MOVL    $0, DI // CLOCK_REALTIME
+       MOVL    $1, DI // CLOCK_MONOTONIC
        LEAQ    0(SP), SI
        CALL    AX
        MOVQ    0(SP), AX       // sec
index 061d01cf2d1ca2770bed1a2686e551f373eabfe1..e73a364a1a085df5678ccdc164614c7fafbd720e 100644 (file)
@@ -26,6 +26,11 @@ static void dumptimers(int8*);
 
 // time.now is implemented in assembly.
 
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() (ns int64) {
+       ns = runtime·nanotime();
+}
+
 // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
 func Sleep(ns int64) {
        runtime·tsleep(ns, "sleep");
index 4ba6d478debac433b4307e657be6251b97bad1a7..2243d3668deaee97925971b977896d44b727a9a5 100644 (file)
@@ -29,7 +29,7 @@ func CheckRuntimeTimerOverflow() error {
        // detection logic in NewTimer: we're testing the underlying
        // runtime.addtimer function.
        r := &runtimeTimer{
-               when: nano() + (1<<63 - 1),
+               when: runtimeNano() + (1<<63 - 1),
                f:    empty,
                arg:  nil,
        }
index 4f55bebe62a6de33e5223db17c7adbbf635cf4fc..6a03f417bd00ffb7efe2dd224c6d1fe9bff95d1d 100644 (file)
@@ -8,10 +8,8 @@ package time
 // A negative or zero duration causes Sleep to return immediately.
 func Sleep(d Duration)
 
-func nano() int64 {
-       sec, nsec := now()
-       return sec*1e9 + int64(nsec)
-}
+// runtimeNano returns the current value of the runtime clock in nanoseconds.
+func runtimeNano() int64
 
 // Interface to timers implemented in package runtime.
 // Must be in sync with ../runtime/runtime.h:/^struct.Timer$
@@ -29,9 +27,9 @@ type runtimeTimer struct {
 // zero because of an overflow, MaxInt64 is returned.
 func when(d Duration) int64 {
        if d <= 0 {
-               return nano()
+               return runtimeNano()
        }
-       t := nano() + int64(d)
+       t := runtimeNano() + int64(d)
        if t < 0 {
                t = 1<<63 - 1 // math.MaxInt64
        }
@@ -92,7 +90,7 @@ func sendTime(now int64, c interface{}) {
        // the desired behavior when the reader gets behind,
        // because the sends are periodic.
        select {
-       case c.(chan Time) <- Unix(0, now):
+       case c.(chan Time) <- Now():
        default:
        }
 }
index 3b42b66cfecb18fb5ded32db11dff80373d96b97..19007841e1af045821168cbde5faf6322dfda6ad 100644 (file)
@@ -29,7 +29,7 @@ func NewTicker(d Duration) *Ticker {
        t := &Ticker{
                C: c,
                r: runtimeTimer{
-                       when:   nano() + int64(d),
+                       when:   when(d),
                        period: int64(d),
                        f:      sendTime,
                        arg:    c,