From 01f1e3da484f74a7229c3c1eb719403b4e8c7a1c Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Fri, 9 Aug 2013 12:53:35 +0400 Subject: [PATCH] runtime: traceback running goroutines Introduce freezetheworld function that is a best-effort attempt to stop any concurrently running goroutines. Call it during crash. Fixes #5873. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/12054044 --- src/pkg/runtime/panic.c | 1 + src/pkg/runtime/proc.c | 54 ++++++++++++++++++++++++++++++++++----- src/pkg/runtime/runtime.h | 1 + 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/src/pkg/runtime/panic.c b/src/pkg/runtime/panic.c index 3211415266..78b3068749 100644 --- a/src/pkg/runtime/panic.c +++ b/src/pkg/runtime/panic.c @@ -419,6 +419,7 @@ runtime·startpanic(void) g->writebuf = nil; runtime·xadd(&runtime·panicking, 1); runtime·lock(&paniclk); + runtime·freezetheworld(); } void diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c index 6eab7dba1b..1c39807e00 100644 --- a/src/pkg/runtime/proc.c +++ b/src/pkg/runtime/proc.c @@ -107,8 +107,8 @@ static G* globrunqget(P*, int32); static P* pidleget(void); static void pidleput(P*); static void injectglist(G*); -static void preemptall(void); -static void preemptone(P*); +static bool preemptall(void); +static bool preemptone(P*); static bool exitsyscallfast(void); // The bootstrap sequence is: @@ -374,6 +374,34 @@ runtime·helpgc(int32 nproc) runtime·unlock(&runtime·sched); } +// Similar to stoptheworld but best-effort and can be called several times. +// There is no reverse operation, used during crashing. +// This function must not lock any mutexes. +void +runtime·freezetheworld(void) +{ + int32 i; + + if(runtime·gomaxprocs == 1) + return; + // stopwait and preemption requests can be lost + // due to races with concurrently executing threads, + // so try several times + for(i = 0; i < 5; i++) { + // this should tell the scheduler to not start any new goroutines + runtime·sched.stopwait = 0x7fffffff; + runtime·atomicstore((uint32*)&runtime·gcwaiting, 1); + // this should stop running goroutines + if(!preemptall()) + break; // no running goroutines + runtime·usleep(1000); + } + // to be sure + runtime·usleep(1000); + preemptall(); + runtime·usleep(1000); +} + void runtime·stoptheworld(void) { @@ -1518,6 +1546,12 @@ exitsyscallfast(void) { P *p; + // Freezetheworld sets stopwait but does not retake P's. + if(runtime·sched.stopwait) { + m->p = nil; + return false; + } + // Try to re-acquire the last P. if(m->p && m->p->status == Psyscall && runtime·cas(&m->p->status, Psyscall, Prunning)) { // There's a cpu for us, so we can run. @@ -2243,18 +2277,22 @@ retake(int64 now) // This function is purely best-effort. It can fail to inform a goroutine if a // processor just started running it. // No locks need to be held. -static void +// Returns true if preemption request was issued to at least one goroutine. +static bool preemptall(void) { P *p; int32 i; + bool res; + res = false; for(i = 0; i < runtime·gomaxprocs; i++) { p = runtime·allp[i]; if(p == nil || p->status != Prunning) continue; - preemptone(p); + res |= preemptone(p); } + return res; } // Tell the goroutine running on processor P to stop. @@ -2263,7 +2301,8 @@ preemptall(void) // correct goroutine, that goroutine might ignore the request if it is // simultaneously executing runtime·newstack. // No lock needs to be held. -static void +// Returns true if preemption request was issued. +static bool preemptone(P *p) { M *mp; @@ -2271,12 +2310,13 @@ preemptone(P *p) mp = p->m; if(mp == nil || mp == m) - return; + return false; gp = mp->curg; if(gp == nil || gp == mp->g0) - return; + return false; gp->preempt = true; gp->stackguard0 = StackPreempt; + return true; } // Put mp on midle list. diff --git a/src/pkg/runtime/runtime.h b/src/pkg/runtime/runtime.h index 2529a0fdcf..7d04a75424 100644 --- a/src/pkg/runtime/runtime.h +++ b/src/pkg/runtime/runtime.h @@ -837,6 +837,7 @@ int32 runtime·callers(int32, uintptr*, int32); int64 runtime·nanotime(void); void runtime·dopanic(int32); void runtime·startpanic(void); +void runtime·freezetheworld(void); void runtime·unwindstack(G*, byte*); void runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp); void runtime·resetcpuprofiler(int32); -- 2.48.1