From 80b8842f3e4d562e67455de1c1de80cba5532aec Mon Sep 17 00:00:00 2001 From: rsc Date: Tue, 15 Feb 2005 18:08:28 +0000 Subject: hard-to-find locking bug --- src/libthread/thread.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) (limited to 'src/libthread') 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); } /* -- cgit v1.2.3