commit 80b8842f3e4d562e67455de1c1de80cba5532aec from: rsc date: Tue Feb 15 18:08:28 2005 UTC hard-to-find locking bug commit - ee4cffff9a1068d9c9bab99788d27fd235ade2dc commit + 80b8842f3e4d562e67455de1c1de80cba5532aec blob - 57ffa1cb049651a5879911a7ab2c95793275b897 blob + eb8370b34808a5da6506b4a2cd51553f3450e3e6 --- src/libthread/thread.c +++ 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); } /*