]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: fix deadlock
authorDmitriy Vyukov <dvyukov@google.com>
Thu, 7 Mar 2013 17:39:59 +0000 (21:39 +0400)
committerDmitriy Vyukov <dvyukov@google.com>
Thu, 7 Mar 2013 17:39:59 +0000 (21:39 +0400)
The deadlock episodically occurs on misc/cgo/test/TestCthread.
The problem is that starttheworld() leaves some P's with local work
without M's. Then all active M's enter into syscalls, but reject to
wake another M's due to the following check (both in entersyscallblock() and in retake()):
if(p->runqhead == p->runqtail &&
        runtime·atomicload(&runtime·sched.nmspinning) +
        runtime·atomicload(&runtime·sched.npidle) > 0)
        continue;

R=rsc
CC=golang-dev
https://golang.org/cl/7424054

src/pkg/runtime/proc.c

index 4ce0a718cd776f631ceee969eab41e618887067b..d0f6745aa7ddc72cfb8286cd3945bef8c6470375 100644 (file)
@@ -392,7 +392,7 @@ mhelpgc(void)
 void
 runtime·starttheworld(void)
 {
-       P *p;
+       P *p, *p1;
        M *mp;
        bool add;
 
@@ -405,6 +405,7 @@ runtime·starttheworld(void)
                procresize(runtime·gomaxprocs);
        runtime·gcwaiting = 0;
 
+       p1 = nil;
        while(p = pidleget()) {
                // procresize() puts p's with work at the beginning of the list.
                // Once we reach a p without a run queue, the rest don't have one either.
@@ -414,8 +415,9 @@ runtime·starttheworld(void)
                }
                mp = mget();
                if(mp == nil) {
-                       pidleput(p);
-                       break;
+                       p->link = p1;
+                       p1 = p;
+                       continue;
                }
                if(mp->nextp)
                        runtime·throw("starttheworld: inconsistent mp->nextp");
@@ -428,6 +430,13 @@ runtime·starttheworld(void)
        }
        runtime·unlock(&runtime·sched);
 
+       while(p1) {
+               p = p1;
+               p1 = p1->link;
+               add = false;
+               newm(nil, p);
+       }
+
        if(add) {
                // If GC could have used another helper proc, start one now,
                // in the hope that it will be available next time.