Re: msleep() on recursivly locked mutexes



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
_______________________________________________
freebsd-arch@xxxxxxxxxxx mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-arch
To unsubscribe, send any mail to "freebsd-arch-unsubscribe@xxxxxxxxxxx"



Relevant Pages