msleep() on recursivly locked mutexes

Hans Petter Selasky hselasky at freebsd.org
Fri Apr 27 19:34:23 UTC 2007


On Friday 27 April 2007 20:01, Julian Elischer wrote:
> Hans Petter Selasky wrote:
> > First of all: Where is FreeBSD's locking strategy document?
>
> It is just started..
> man 9 locking.  it needs a lot of work still.

Excellent.

>
> > We should have a
> > global strategy when we write device drivers, so that various modules can
> > be connected together without races and locking order reversals.
> >
> > In my view there are two categories of mutexes.
> >
> > 1) Global mutexes.
> >
> > 2) Private mutexes.
> >
> > Rule: The Global mutex is locked last.
>
> errr I'm not sure I'm following but this sounds kind-of reversed from
> normal behaviour.

Yes, it is. But you have to make a choice. Either this way or the other way. 
But not both! The reason for my choice is that I consider it to be more 
complicated to be a Global device than a private device. Complicated means 
that the Global device, which is locked last, has to unlock its lock before 
it calls back the "private" device, like I have explained below.

Hence there are fewer Global devices (e.g. USB host controllers), then private 
devices (USB device drivers), we end up with less code/headache locking the 
Global devices last. If that is unclear I can explain more.

>
> > How do we organize this.
> >
> > 1a) The global mutex protects interrupts/callbacks into a hardware
> > driver. This is the lowest level.
> >
> > 2a) Private mutexes protects sub-devices of the hardware driver. This
> > might be as simple as an IF-QUEUE.
>
> I'm having trouble following already.
> you mean subcomponents?

Yes, children of devices. Sub-devices.

>
> > I have chosen the following model:
> >
> > P0 indicates process 0. P1 indicates an optional second process.
> >
> > Up-call:
> >
> > P0 lock(2);
> > P0 lock(1);

The work done [here] might be to setup DMA-able memory, and link it into the 
hardware.

> > P0 unlock(1);
> > P0 unlock(2);
>
> this looks "interesting".
> Can you give a more concrete example of this?
> what work is done in the upcall? WHo is upcalling to who?

For example an USB device driver might be up-calling to the USB host 
controller driver. Down call is when the transfer finishes.

>
> > Down-call:
> >
> > P1 lock(1);
> > P1 wakeup P0 // for example
> > P1 unlock(1);
>
>  pretty normal.
>
> > P0 //callback:
> > P0 lock(2); // the new USB stack currently uses P1 here
> > P0 unlock(2);
> >
> >
> >
> > Sure, in the up-call you lock #2 longer than lock #1, that is why lock #1
> > has got to be a short as possible. But it does not make sense to make
> > lock #2 lock shorter than lock #1. I cannot see that the system will go
> > faster that way.
> >
> > In the downcall I see no problems at all. #1 does its things as fast as
> > possible. In parallell #2 can still execute, until the "callback".
> >
> > I hope you understand my semantics.
> >
> > What do you want to change from what I have explained?
> >
> > Any comments?
> >
> > My conclusion: If you want more paralellism, then use more mutexes. Don't
> > try to push an existing mutex by unlocking it!
>
> that may or may not be true depending on how busy the mutex is..
> but I don't think there is an argument about this.
>
>
> shouldn't this be somewhere other than "hackers"?

I've CC'ed freebsd-arch.

--HPS


More information about the freebsd-hackers mailing list