Commit 86c976ff authored by Jay Weisskopf's avatar Jay Weisskopf Committed by Russ Cox

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

LGTM=dvyukov, rsc
R=golang-codereviews, dvyukov, alex.brainman, stephen.gutekanst, dave, rsc, mikioh.mikioh
CC=golang-codereviews
https://golang.org/cl/53010043
parent 7403071a
...@@ -12,6 +12,9 @@ import ( ...@@ -12,6 +12,9 @@ import (
"time" "time"
) )
// runtimeNano returns the current value of the runtime clock in nanoseconds.
func runtimeNano() int64
func runtime_pollServerInit() func runtime_pollServerInit()
func runtime_pollOpen(fd uintptr) (uintptr, int) func runtime_pollOpen(fd uintptr) (uintptr, int)
func runtime_pollClose(ctx uintptr) func runtime_pollClose(ctx uintptr)
...@@ -128,7 +131,7 @@ func (fd *netFD) setWriteDeadline(t time.Time) error { ...@@ -128,7 +131,7 @@ func (fd *netFD) setWriteDeadline(t time.Time) error {
} }
func setDeadlineImpl(fd *netFD, t time.Time, mode int) error { func setDeadlineImpl(fd *netFD, t time.Time, mode int) error {
d := t.UnixNano() d := runtimeNano() + int64(t.Sub(time.Now()))
if t.IsZero() { if t.IsZero() {
d = 0 d = 0
} }
......
...@@ -83,6 +83,11 @@ static FuncVal deadlineFn = {(void(*)(void))deadline}; ...@@ -83,6 +83,11 @@ static FuncVal deadlineFn = {(void(*)(void))deadline};
static FuncVal readDeadlineFn = {(void(*)(void))readDeadline}; static FuncVal readDeadlineFn = {(void(*)(void))readDeadline};
static FuncVal writeDeadlineFn = {(void(*)(void))writeDeadline}; 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() { func runtime_pollServerInit() {
runtime·netpollinit(); runtime·netpollinit();
} }
......
...@@ -106,7 +106,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-24 ...@@ -106,7 +106,7 @@ TEXT runtime·mincore(SB),NOSPLIT,$0-24
// func now() (sec int64, nsec int32) // func now() (sec int64, nsec int32)
TEXT time·now(SB), NOSPLIT, $32 TEXT time·now(SB), NOSPLIT, $32
MOVL $265, AX // syscall - clock_gettime MOVL $265, AX // syscall - clock_gettime
MOVL $0, BX MOVL $0, BX // CLOCK_REALTIME
LEAL 8(SP), CX LEAL 8(SP), CX
MOVL $0, DX MOVL $0, DX
CALL *runtime·_vdso(SB) CALL *runtime·_vdso(SB)
...@@ -123,7 +123,7 @@ TEXT time·now(SB), NOSPLIT, $32 ...@@ -123,7 +123,7 @@ TEXT time·now(SB), NOSPLIT, $32
// void nanotime(int64 *nsec) // void nanotime(int64 *nsec)
TEXT runtime·nanotime(SB), NOSPLIT, $32 TEXT runtime·nanotime(SB), NOSPLIT, $32
MOVL $265, AX // syscall - clock_gettime MOVL $265, AX // syscall - clock_gettime
MOVL $0, BX MOVL $1, BX // CLOCK_MONOTONIC
LEAL 8(SP), CX LEAL 8(SP), CX
MOVL $0, DX MOVL $0, DX
CALL *runtime·_vdso(SB) CALL *runtime·_vdso(SB)
......
...@@ -136,7 +136,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16 ...@@ -136,7 +136,7 @@ TEXT runtime·nanotime(SB),NOSPLIT,$16
MOVQ runtime·__vdso_clock_gettime_sym(SB), AX MOVQ runtime·__vdso_clock_gettime_sym(SB), AX
CMPQ AX, $0 CMPQ AX, $0
JEQ fallback_gtod_nt JEQ fallback_gtod_nt
MOVL $0, DI // CLOCK_REALTIME MOVL $1, DI // CLOCK_MONOTONIC
LEAQ 0(SP), SI LEAQ 0(SP), SI
CALL AX CALL AX
MOVQ 0(SP), AX // sec MOVQ 0(SP), AX // sec
......
...@@ -26,6 +26,11 @@ static void dumptimers(int8*); ...@@ -26,6 +26,11 @@ static void dumptimers(int8*);
// time.now is implemented in assembly. // 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. // Sleep puts the current goroutine to sleep for at least ns nanoseconds.
func Sleep(ns int64) { func Sleep(ns int64) {
runtime·tsleep(ns, "sleep"); runtime·tsleep(ns, "sleep");
......
...@@ -29,7 +29,7 @@ func CheckRuntimeTimerOverflow() error { ...@@ -29,7 +29,7 @@ func CheckRuntimeTimerOverflow() error {
// detection logic in NewTimer: we're testing the underlying // detection logic in NewTimer: we're testing the underlying
// runtime.addtimer function. // runtime.addtimer function.
r := &runtimeTimer{ r := &runtimeTimer{
when: nano() + (1<<63 - 1), when: runtimeNano() + (1<<63 - 1),
f: empty, f: empty,
arg: nil, arg: nil,
} }
......
...@@ -8,10 +8,8 @@ package time ...@@ -8,10 +8,8 @@ package time
// A negative or zero duration causes Sleep to return immediately. // A negative or zero duration causes Sleep to return immediately.
func Sleep(d Duration) func Sleep(d Duration)
func nano() int64 { // runtimeNano returns the current value of the runtime clock in nanoseconds.
sec, nsec := now() func runtimeNano() int64
return sec*1e9 + int64(nsec)
}
// Interface to timers implemented in package runtime. // Interface to timers implemented in package runtime.
// Must be in sync with ../runtime/runtime.h:/^struct.Timer$ // Must be in sync with ../runtime/runtime.h:/^struct.Timer$
...@@ -29,9 +27,9 @@ type runtimeTimer struct { ...@@ -29,9 +27,9 @@ type runtimeTimer struct {
// zero because of an overflow, MaxInt64 is returned. // zero because of an overflow, MaxInt64 is returned.
func when(d Duration) int64 { func when(d Duration) int64 {
if d <= 0 { if d <= 0 {
return nano() return runtimeNano()
} }
t := nano() + int64(d) t := runtimeNano() + int64(d)
if t < 0 { if t < 0 {
t = 1<<63 - 1 // math.MaxInt64 t = 1<<63 - 1 // math.MaxInt64
} }
...@@ -92,7 +90,7 @@ func sendTime(now int64, c interface{}) { ...@@ -92,7 +90,7 @@ func sendTime(now int64, c interface{}) {
// the desired behavior when the reader gets behind, // the desired behavior when the reader gets behind,
// because the sends are periodic. // because the sends are periodic.
select { select {
case c.(chan Time) <- Unix(0, now): case c.(chan Time) <- Now():
default: default:
} }
} }
......
...@@ -29,7 +29,7 @@ func NewTicker(d Duration) *Ticker { ...@@ -29,7 +29,7 @@ func NewTicker(d Duration) *Ticker {
t := &Ticker{ t := &Ticker{
C: c, C: c,
r: runtimeTimer{ r: runtimeTimer{
when: nano() + int64(d), when: when(d),
period: int64(d), period: int64(d),
f: sendTime, f: sendTime,
arg: c, arg: c,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment