The IOCommandGate is designed to do this, check out the header doc. However I wrote a paper on designing a PCI device quite a while ago which should still be available on RobB's How too site. In simple explanation is that the workloop is the master lock for one driver stack. In your case kext A will be registering with your provider's workloop. Now a work loop has lots of event sources registered with it and each event source has an associated Action. It is guaranteed that one and only one Action routine can run on a particular workloop at any time. So in your example if you find your workloop by just calling provider->getWorkLoop() in KextA you will automatically be able to synchronise with the USBs work loop and all completion routines come out on that context. Then if you need to protect your own driver against these completion routines and you addEventSource() them to your providers work loop. Note it is also OK to add IOTimerEventSources if you have times outs. (Note however the IOTimerEventSource doesn't currently have a reliable cancel path so be very careful when you are trying to unload your driver.) Then In the APIs from your client you wish to synchronise you use the fGate->runAction(...) function. Pseudo code follows (check header doc for details). in your start routine in Kext A fGate = IOCommandGate::commandGate(this); IOWorkLoop *wl = getWorkLoop(); // Find my providers work loop. if (!fGate || !wl) return false; if (kIOReturnSuccess != wl->addEventSource(fGate)) return false; // That's it your now have an IOCommandGate set up in member variable fGate IOReturn KextA::myClientsAPI(args) { return fGate->runAction(&KextA::myClientsAPIGated, args); } // Make sure this function is declared as a 'static' function in the header IOReturn KextA::myClientsAPIGated(IOService *servSelf, void *vArg1, void *vArg2, /*etc ... */ ) { KextA *self = (KextA *) servSelf; UInt32 arg1 = (UInt32) vArg1; // You can see where this is going I'm sure // Just remember to either call a member function here or prefix // all class access with self-> return result; } FInally I recommend only cleaning up the fGate at free time and no earlier. A lot of tear down problems have been due to premature tear down of the synchroniser. free() { if (fGate) { IOWorkLoop *wl = fGate->getWorkLoop(); if (wl) wl->removeEventSource(fGate); fGate->release(); fGate = 0; } } Godfrey At 8:20 -0700 02-6-28, Scott Taggart wrote: Hi, I have two kexts: kext A is a USB driver sub-classed from IOService and Kext B sub-classed from IOEthernetController. B "calls" into "A" at various times to perform functions such as delivering outbound frames. I want to "lock" B from entering into A if A has already been entered (via USB callback, timer, etc.) (i.e., its "gate/lock" is busy). Can someone please give me the basics of how I make a given function entry point into A and have it play the "IO Gate" game (i.e., to make sure it's the only one with the lock). Function calls and a pointer to some sample code would be a big help. 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.
participants (1)
-
Godfrey van der Linden