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 (
"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
}
......
......@@ -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();
}
......
......@@ -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)
......
......@@ -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
......
......@@ -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");
......
......@@ -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,
}
......
......@@ -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:
}
}
......
......@@ -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,
......
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