Commit 2fe94823 authored by Shenghou Ma's avatar Shenghou Ma Committed by Russ Cox

runtime: add fake time support back.

Revived from CL 15690048.

Fixes #5356.

LGTM=rsc
R=adg, dvyukov, rsc
CC=golang-codereviews
https://golang.org/cl/101400043
parent 2eb1b658
...@@ -2758,6 +2758,8 @@ static void ...@@ -2758,6 +2758,8 @@ static void
checkdead(void) checkdead(void)
{ {
G *gp; G *gp;
P *p;
M *mp;
int32 run, grunning, s; int32 run, grunning, s;
uintptr i; uintptr i;
...@@ -2799,6 +2801,24 @@ checkdead(void) ...@@ -2799,6 +2801,24 @@ checkdead(void)
runtime·unlock(&runtime·allglock); runtime·unlock(&runtime·allglock);
if(grunning == 0) // possible if main goroutine calls runtime·Goexit() if(grunning == 0) // possible if main goroutine calls runtime·Goexit()
runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!"); runtime·throw("no goroutines (main called runtime.Goexit) - deadlock!");
// Maybe jump time forward for playground.
if((gp = runtime·timejump()) != nil) {
runtime·casgstatus(gp, Gwaiting, Grunnable);
globrunqput(gp);
p = pidleget();
if(p == nil)
runtime·throw("checkdead: no p for timer");
mp = mget();
if(mp == nil)
newm(nil, p);
else {
mp->nextp = p;
runtime·notewakeup(&mp->park);
}
return;
}
g->m->throwing = -1; // do not dump full stacks g->m->throwing = -1; // do not dump full stacks
runtime·throw("all goroutines are asleep - deadlock!"); runtime·throw("all goroutines are asleep - deadlock!");
} }
......
...@@ -25,6 +25,6 @@ TEXT _rt0_amd64p32_nacl(SB),NOSPLIT,$16 ...@@ -25,6 +25,6 @@ TEXT _rt0_amd64p32_nacl(SB),NOSPLIT,$16
TEXT main(SB),NOSPLIT,$0 TEXT main(SB),NOSPLIT,$0
// Uncomment for fake time like on Go Playground. // Uncomment for fake time like on Go Playground.
//MOVQ $1257894000000000000, AX MOVQ $1257894000000000000, AX
//MOVQ AX, runtime·timens(SB) MOVQ AX, runtime·faketime(SB)
JMP runtime·rt0_go(SB) JMP runtime·rt0_go(SB)
...@@ -60,7 +60,7 @@ TEXT syscall·naclWrite(SB), NOSPLIT, $24-20 ...@@ -60,7 +60,7 @@ TEXT syscall·naclWrite(SB), NOSPLIT, $24-20
TEXT runtime·write(SB),NOSPLIT,$16-20 TEXT runtime·write(SB),NOSPLIT,$16-20
// If using fake time and writing to stdout or stderr, // If using fake time and writing to stdout or stderr,
// emit playback header before actual data. // emit playback header before actual data.
MOVQ runtime·timens(SB), AX MOVQ runtime·faketime(SB), AX
CMPQ AX, $0 CMPQ AX, $0
JEQ write JEQ write
MOVL fd+0(FP), DI MOVL fd+0(FP), DI
...@@ -242,7 +242,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$8 ...@@ -242,7 +242,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$8
RET RET
TEXT time·now(SB),NOSPLIT,$16 TEXT time·now(SB),NOSPLIT,$16
MOVQ runtime·timens(SB), AX MOVQ runtime·faketime(SB), AX
CMPQ AX, $0 CMPQ AX, $0
JEQ realtime JEQ realtime
MOVQ $0, DX MOVQ $0, DX
...@@ -277,7 +277,7 @@ TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0 ...@@ -277,7 +277,7 @@ TEXT runtime·nacl_clock_gettime(SB),NOSPLIT,$0
RET RET
TEXT runtime·nanotime(SB),NOSPLIT,$16 TEXT runtime·nanotime(SB),NOSPLIT,$16
MOVQ runtime·timens(SB), AX MOVQ runtime·faketime(SB), AX
CMPQ AX, $0 CMPQ AX, $0
JEQ 3(PC) JEQ 3(PC)
MOVQ AX, ret+0(FP) MOVQ AX, ret+0(FP)
......
...@@ -35,8 +35,8 @@ var timers struct { ...@@ -35,8 +35,8 @@ var timers struct {
t []*timer t []*timer
} }
// nacl fake time support. // nacl fake time support - time in nanoseconds since 1970
var timens int64 var faketime int64
// Package time APIs. // Package time APIs.
// Godoc uses the comments in package time, not these. // Godoc uses the comments in package time, not these.
...@@ -194,7 +194,7 @@ func timerproc() { ...@@ -194,7 +194,7 @@ func timerproc() {
f(arg, seq) f(arg, seq)
lock(&timers.lock) lock(&timers.lock)
} }
if delta < 0 { if delta < 0 || faketime > 0 {
// No timers left - put goroutine to sleep. // No timers left - put goroutine to sleep.
timers.rescheduling = true timers.rescheduling = true
goparkunlock(&timers.lock, "timer goroutine (idle)") goparkunlock(&timers.lock, "timer goroutine (idle)")
...@@ -208,6 +208,29 @@ func timerproc() { ...@@ -208,6 +208,29 @@ func timerproc() {
} }
} }
func timejump() *g {
if faketime == 0 {
return nil
}
lock(&timers.lock)
if !timers.created || len(timers.t) == 0 {
unlock(&timers.lock)
return nil
}
var gp *g
if faketime < timers.t[0].when {
faketime = timers.t[0].when
if timers.rescheduling {
timers.rescheduling = false
gp = timers.gp
}
}
unlock(&timers.lock)
return gp
}
// Heap maintenance algorithms. // Heap maintenance algorithms.
func siftupTimer(i int) { func siftupTimer(i int) {
......
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