aboutsummaryrefslogtreecommitdiff
path: root/src/libthread
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2005-02-15 18:08:28 +0000
committerrsc <devnull@localhost>2005-02-15 18:08:28 +0000
commit80b8842f3e4d562e67455de1c1de80cba5532aec (patch)
treea6413431ccada7cb9bd177be5261212bd8b327b9 /src/libthread
parentee4cffff9a1068d9c9bab99788d27fd235ade2dc (diff)
downloadplan9port-80b8842f3e4d562e67455de1c1de80cba5532aec.tar.gz
plan9port-80b8842f3e4d562e67455de1c1de80cba5532aec.tar.bz2
plan9port-80b8842f3e4d562e67455de1c1de80cba5532aec.zip
hard-to-find locking bug
Diffstat (limited to 'src/libthread')
-rw-r--r--src/libthread/thread.c24
1 files changed, 19 insertions, 5 deletions
diff --git a/src/libthread/thread.c b/src/libthread/thread.c
index 57ffa1cb..eb8370b3 100644
--- a/src/libthread/thread.c
+++ b/src/libthread/thread.c
@@ -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){
@@ -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
@@ -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
@@ -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);
}
/*