]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: traceback running goroutines
authorDmitriy Vyukov <dvyukov@google.com>
Fri, 9 Aug 2013 08:53:35 +0000 (12:53 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Fri, 9 Aug 2013 08:53:35 +0000 (12:53 +0400)
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
src/pkg/runtime/proc.c
src/pkg/runtime/runtime.h

index 3211415266dbbfbf7d877f6a535d28ad2d59cccc..78b3068749e2ff33b818cec6546f8ca7c23d69ff 100644 (file)
@@ -419,6 +419,7 @@ runtime·startpanic(void)
                g->writebuf = nil;
        runtime·xadd(&runtime·panicking, 1);
        runtime·lock(&paniclk);
+       runtime·freezetheworld();
 }
 
 void
index 6eab7dba1bff579f909c7468189fef920a3530ea..1c39807e00d33d3ee76b9b29b2498fa0ac93d200 100644 (file)
@@ -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.
index 2529a0fdcf45ed0e7347d09732120ddac618e99c..7d04a75424abc97404d8144608ed7b7c8948f43a 100644 (file)
@@ -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);