Godfrey, Thanks for the extended response. And, fine by me if this becomes the starting place for documenting how all this works (I'm sure others will agree). I have a few follow-ups. At 02:51 PM 6/3/2002, Godfrey van der Linden wrote:
Basically there are two locking mechansims you will need to worry about.
One is the IOWorkLoop you are slaved against, that is the workloop of the
USB controller. The second lock is the network funnel. In general you
will not have to worry about the funnel as the IONetworkingFamily will
handle most of that for you.
OK, so the USB stuff is self-gated, so to speak so one USB completion will not preempt another USB completion. I am unclear exactly what you mean by not worrying about network funnel other than are you saying that the same applies to it as the USB completions - that is that all network calls will be self-protected (from themselves that is). Is this correct (but USB callbacks are not protected against network calls and vice-versa?- see my questions below)?
Now to address some of your questions.
In X you don't get anything at Primary interrupt time, so that is easy
(Note PCI device do have access to the primary interrupt through the
IOFilterInterruptEventSource but you are a USB device so you don't have to
worry about that.
All USB completions come on the USBs IOWorkLoop and thus holds the
gate. If you wish to synchronise a 'down' call against your completions
you can do this by creating your on IOCommandGate and registering it
against your work loop. You get the correct work loop to use by call
IOService::getWorkLoop() on yourself so that is pretty
easy. getWorkLoop() automatically walks down your provider chain looking
for a driver that exports the completion context, the USB controller in
your example.
By "down", I assume you mean a call from the network stack into my USB driver? (again, I am new to this, so I will butcher the assumptions I make and the terminology I use). If I understand this correctly, you are saying that the network calls (could/might) preempt the USB callbacks (and vice-versa) and thus need to be gated against the same gate as the USB callbacks, correct? Can you point me to code that manually creates its own IOCommandGate() (I am sure I can find this but if you can just give me a file name, that would be great).
Timers also synchronise against the work loop when you use the
IOTimerEventSource. However there is a long outstanding bug against the
IOTES where it doesn't have a deterministic way of cancelling at the
moment. If you wish to shut down a driver and still have a timer
outstanding it is usually better to just wait for the last timeout to
occur rather than attempting to cancel it. (yes I have had this bug for a
long time and the fix is pretty easy but I have a long list of other very
high priority problems to fix first).
How do you "defer" the shutdown of the driver when you get a "terminate()" call to wait for the timer completion? Are there any samples of how to do this?
Now there are a couple of X subtleties that 9 didn't have.
Provided you use the work loop paradigm then it is easy to synchronise
against all callouts and also easy to keep down calls correct by using
your own command gate. But you do have to watch out for blocking
calls. It is probably never correct to issue a call that can block
indefinitely while in a gated context. However short, (how short is
undefined?) delays acceptable, hence it is ok to use locks on a work loop
context but it is better if you don't need to.
Seems reasonable to not "block". So, this leads me to the natural questions: What calls can and can't be blocked? How long is "too" long? I think in my case, I just queue most requests and return, which, I presume is the "right" way to handle things.
(The inflictor of IOWorkLoop on a poor unsuspecting world)
The workloop is a nice concept. As you can see, however, there are natural questions that arise as to the "rules". All I can say is the more documentation and samples, the better ;) And one final question (for now!). I am sure that if I had enough time (which I don't), I could figure this out. And, the question itself is tricky: I don't understand *how* registering an event (interrupt, etc.) causes it to get gated (I would like the actual mechanism explained because I am curious). For example, I see one of the EN drivers registering an interrupt function as a workloop "task". When I look at the interrupt function itself, it just looks "normal" - that is it itself does nothing workloop/gate related. So, suppose we have a registered interrupt function named "InterruptFunc()". Obviously, the hardware does not generate an interrupt that directly calls this function - somehow, the gate code gets "in front" of this function, does the gate "thing" and then calls the function when it owns the gate. Would you mind explaining how the gate code gets put in "front" of a registered function (what is the "glue" that welds the source of the event (interrupt, timer, etc.) to the gate and then to the function being gated? Many thanks, Scott _______________________________________________ darwin-kernel mailing list | darwin-kernel@lists.apple.com Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/darwin-kernel Do not post admin requests to the list. They will be ignored.