cvs commit: src/sys/dev/md md.c
Nate Lawson
nate at root.org
Thu Sep 16 15:15:16 PDT 2004
Pawel Jakub Dawidek wrote:
> On Thu, Sep 16, 2004 at 12:40:23PM -0700, Nate Lawson wrote:
> +> >@@ -379,9 +379,8 @@
> +> > bp->bio_bcount = bp->bio_length;
> +> > mtx_lock(&sc->queue_mtx);
> +> > bioq_disksort(&sc->bio_queue, bp);
> +> >- mtx_unlock(&sc->queue_mtx);
> +> >-
> +> > wakeup(sc);
> +> >+ mtx_unlock(&sc->queue_mtx);
> +> > }
> +>
> +> I think the original order is correct since you can occur 2 switches if
> +> you wakeup first and then unlock.
>
> Nope, this order was wrong:
>
> thread1 thread2
> -----------------------
> mtx_lock(mtx)
> ...
> mtx_unlock(mtx)
> mtx_lock(mtx)
> wakeup(ptr)
> msleep(ptr, mtx) <- Race, it will be never woken up.
You still have a race, like this:
thread1 thread2
-----------------------------
mtx_lock(mtx)
wakeup(ptr)
mtx_unlock(mtx)
mtx_lock(mtx)
msleep(ptr, mtx)
You should be checking the work condition in thread 2 while holding the
mutex but before going to sleep. Adding work to the queue happens in
thread 1 where you write "..." and that is done with the mutex held so
there is no race. The full diagram with this detail included is:
thread1 thread2
-----------------------------
mtx_lock(mtx)
add work to queue
mtx_unlock(mtx)
mtx_lock(mtx)
wakeup(ptr)
check queue for work item
if (!work item)
msleep(ptr, mtx)
else
dequeue work item and loop
Since the work item is added in thread1 with the mutex held, the check
for it in thread2 is safe and race-free. A wakeup is only there to
kickstart thread2 if it's asleep. If it's running, it needs to check
atomically that there is no work before sleeping. If it doesn't do
this, it's a bug.
--
Nate
More information about the cvs-src
mailing list