thard-to-find locking bug - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
commit 80b8842f3e4d562e67455de1c1de80cba5532aec
parent ee4cffff9a1068d9c9bab99788d27fd235ade2dc
Author: rsc 
Date:   Tue, 15 Feb 2005 18:08:28 +0000

hard-to-find locking bug

Diffstat:
  M src/libthread/thread.c              |      24 +++++++++++++++++++-----

1 file changed, 19 insertions(+), 5 deletions(-)
---
diff --git a/src/libthread/thread.c b/src/libthread/thread.c
t@@ -417,6 +417,8 @@ threadqlock(QLock *l, int block, ulong pc)
 static void
 threadqunlock(QLock *l, ulong pc)
 {
+        _Thread *ready;
+        
         lock(&l->l);
 //print("qlock unlock %p @%#x by %p (owner %p)\n", l, pc, (*threadnow)(), l->owner);
         if(l->owner == 0){
t@@ -424,11 +426,18 @@ threadqunlock(QLock *l, ulong pc)
                         argv0, pc, l->owner, (*threadnow)());
                 abort();
         }
-        if((l->owner = l->waiting.head) != nil){
+        if((l->owner = ready = l->waiting.head) != nil)
                 delthread(&l->waiting, l->owner);
-                _threadready(l->owner);
-        }
+        /*
+         * N.B. Cannot call _threadready() before unlocking l->l,
+         * because the thread we are readying might:
+         *        - be in another proc
+         *        - start running immediately
+         *        - and free l before we get a chance to run again
+         */
         unlock(&l->l);
+        if(ready)
+                _threadready(l->owner);
 }
 
 static int
t@@ -479,14 +488,17 @@ threadrunlock(RWLock *l, ulong pc)
         _Thread *t;
 
         USED(pc);
+        t = nil;
         lock(&l->l);
         --l->readers;
         if(l->readers == 0 && (t = l->wwaiting.head) != nil){
                 delthread(&l->wwaiting, t);
                 l->writer = t;
-                _threadready(t);
         }
         unlock(&l->l);
+        if(t)
+                _threadready(t);
+
 }
 
 static void
t@@ -503,12 +515,14 @@ threadwunlock(RWLock *l, ulong pc)
                 l->readers++;
                 _threadready(t);
         }
+        t = nil;
         if(l->readers == 0 && (t = l->wwaiting.head) != nil){
                 delthread(&l->wwaiting, t);
                 l->writer = t;
-                _threadready(t);
         }
         unlock(&l->l);
+        if(t)
+                _threadready(t);
 }
 
 /*