aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime/proc.c
diff options
context:
space:
mode:
authorDmitriy Vyukov <dvyukov@google.com>2013-08-09 12:53:35 +0400
committerDmitriy Vyukov <dvyukov@google.com>2013-08-09 12:53:35 +0400
commit01f1e3da484f74a7229c3c1eb719403b4e8c7a1c (patch)
tree339ea64dccf5684e6ab21ae19acbae5e5654a354 /src/pkg/runtime/proc.c
parente0405b73187fddbcd685490550681d4fb742105d (diff)
downloadgo-01f1e3da484f74a7229c3c1eb719403b4e8c7a1c.tar.xz
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
Diffstat (limited to 'src/pkg/runtime/proc.c')
-rw-r--r--src/pkg/runtime/proc.c54
1 files changed, 47 insertions, 7 deletions
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.