diff options
author | rsc <devnull@localhost> | 2005-02-15 18:08:28 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-02-15 18:08:28 +0000 |
commit | 80b8842f3e4d562e67455de1c1de80cba5532aec (patch) | |
tree | a6413431ccada7cb9bd177be5261212bd8b327b9 /src | |
parent | ee4cffff9a1068d9c9bab99788d27fd235ade2dc (diff) | |
download | plan9port-80b8842f3e4d562e67455de1c1de80cba5532aec.tar.gz plan9port-80b8842f3e4d562e67455de1c1de80cba5532aec.tar.bz2 plan9port-80b8842f3e4d562e67455de1c1de80cba5532aec.zip |
hard-to-find locking bug
Diffstat (limited to 'src')
-rw-r--r-- | src/libthread/thread.c | 24 |
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); } /* |