On Fri, Nov 12, 2010 at 02:21:34PM +0100, Johnny Billquist wrote: > > > then I realized that this solution would break if people actually > > > wrote code like > > > lock(a) > > > lock(b) > > > release(a) > > > release(b) > > > >...which is very common. > > It is? I would have thought (and hoped) that people normally did: > lock(a) > lock(b) > unlock(b) > unlock(a)
Nope. You might get away with this if we always did strict two-phase locking in the kernel, but we don't (no kernel does) to avoid excessive contention on e.g. the vnode for / and other such locks. Meanwhile, lock coupling tends to appear anytime one is transitioning through a data structure and wants to maintain consistency. Thus the typical usage is something like lock(a) b = a->b lock(b) unlock(a) c = b->c lock(c) unlock(b) do_work(c) unlock(c) It can be shown that this preserves conflict serializability as long as nothing ever follows the structure in the opposite order (c -> b -> a). The traditional place you find code like this is in pathname translation, but in a MP kernel it pops up in lots of other places too. > I agree that it's not wrong, but untidy. Keeping track of ipl > levels could have been kept within the mutex instead, thus > simplifying both the lock and unlock code, at the expense that > people actually had to unlock mutexes in the reverse order they > acquired them. Just as with the splraise/splx before. That however isn't workable. (And it still wouldn't be workable even in a kernel that had separate spinlocks and sleep-locks.) -- David A. Holland dholl...@netbsd.org