I'm not sure exactly why there isn't a IOSimpleLockSleep(), it is
just an oversight I'd guess, the Sleep set of functions came late.
The good news is that assert_wait/thread_block are a formal part of
the Mach kpi set so they are expected to work consistently and
without RRBC issues going forward.
I think in this case you may be better off rolling your own. I
suggest however that you don't use the
IOSimpleLockLockWithDisableInterrupt but rather iofies->disable()
Something like this.
volatile unsigned int producerCount;
volatile unsigned int consumerCount;
IOFilterInterruptEventSource *fies;
bool MyFilter()
{
// some work, maybe quite a lot
producerCount++;
thread_wakeup_one(&consumerCount);
return false;
}
To block a thread do the following
while (producerCount == consumerCount) {
fies->disable(); // Synchronous & efficient routine
// Guaranteed that Filter is NOT running
if (producerCount != consumerCount)
fies->enable();
else {
kr = assert_wait(&consumerCount, ....);
// check the kr for an abort condition and deal with it
fies->enable();
thread_block();
}
}
// atomically increment consumerCount
// return with data available
}
I believe this code is race free and it is very light on system
resources as it doesn't require a complete system disable of
interrupts. We implement the IOFIES::disable() using softDisables so
it doesn't even hit the MPIC unless it really has too.
Godfrey
On 05/20/2005, at 7:29 , Andrew Gallatin wrote:
Why is there no spin-lock variant of IOLockSleep()? Is it by design?
(perhaps because what I want to do is frowned upon?). Or is it
just an
accidental omission from the API and I should file an enhancement
request?
Here is some background:
Many of my device interrupts are done to deliver latency critical
wakeups to a blocked userspace thread. The sleep/interrupt/wakeup
process currently add over 10us of end-to-end latency over a simple
polling approach (which itself is 3.5us). If possible, I'd like to
issue these wakeups from a filter interrupt, rather than from my
workloop, so as to avoid the extra context switch into my workloop.
I currently use IOLockSleep() to block the userspace thread. This
boils down to the Mach lck_mtx_sleep() function. Unfortunately,
to avoid missed wakeup races, it requires that the wakeup be
issued while holding the lock. Since this is a sleep lock,
that means the wakeup can not be issued from a hardware interrupt
context.
The good news is that there is a corresponding Mach variant of
lck_mtx_sleep() called lck_spin_sleep() that I could use. If
I understand things correctly, it is OK to grab a spinlock
(IOSimpleLock) from a hardware interrupt context. It would
have to be OK to be able to schedule workloops...
My worry is that there is no IOSimpleLockSleep(), and I would have to
call a Mach function directly. Since I've been burned by going around
IOKit in the past, I thought should I ask why the IOKit wrapper is
not
there..