Commits

Jay Weisskopf  committed 79f855a

runtime: use monotonic clock for timers (linux/386, linux/amd64)

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 issue 6007

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

Committer: Russ Cox <rsc@golang.org>

  • Participants
  • Parent commits 7e130e3
  • Branches default

Comments (0)

Files changed (8)

File src/pkg/net/fd_poll_runtime.go

 	"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)
 }
 
 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
 	}

File src/pkg/runtime/netpoll.goc

 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();
 }

File src/pkg/runtime/sys_linux_386.s

 // 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)
 // 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)

File src/pkg/runtime/sys_linux_amd64.s

 	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

File src/pkg/runtime/time.goc

 
 // 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");

File src/pkg/time/internal_test.go

 	// 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,
 	}

File src/pkg/time/sleep.go

 // 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$
 // 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
 	}
 	// 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:
 	}
 }

File src/pkg/time/tick.go

 	t := &Ticker{
 		C: c,
 		r: runtimeTimer{
-			when:   nano() + int64(d),
+			when:   when(d),
 			period: int64(d),
 			f:      sendTime,
 			arg:    c,