/* virtual */ void IOCommandGate::setWorkLoop(IOWorkLoop *inWorkLoop) { IOWorkLoop * wl; uintptr_t * sleepersP = (uintptr_t *) &reserved; bool defer; if (!inWorkLoop && (wl = workLoop)) { // tearing down wl->closeGate(); *sleepersP |= kSleepersRemoved; while (*sleepersP & kSleepersWaitEnabled) { thread_wakeup_with_result(&enabled, THREAD_INTERRUPTED); sleepGate(sleepersP, THREAD_UNINT); } *sleepersP &= ~kSleepersWaitEnabled; defer = (0 != (kSleepersActionsMask & *sleepersP)); if (!defer) { super::setWorkLoop(0); *sleepersP &= ~kSleepersRemoved; } wl->openGate(); return; } super::setWorkLoop(inWorkLoop); }
// Timeout handler function. This function is called by the kernel when // the timeout interval expires. // void IOTimerEventSource::timeout(void *self) { IOTimerEventSource *me = (IOTimerEventSource *) self; IOStatisticsTimeout(); if (me->enabled && me->action) { IOWorkLoop * wl = me->workLoop; if (wl) { Action doit; wl->closeGate(); IOStatisticsCloseGate(); doit = (Action) me->action; if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime)) { bool trace = (gIOKitTrace & kIOTraceTimers) ? true : false; if (trace) IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION), (uintptr_t) doit, (uintptr_t) me->owner); (*doit)(me->owner, me); #if CONFIG_DTRACE DTRACE_TMR3(iotescallout__expire, Action, doit, OSObject, me->owner, void, me->workLoop); #endif if (trace) IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION), (uintptr_t) doit, (uintptr_t) me->owner); } IOStatisticsOpenGate(); wl->openGate(); }
IOReturn IOCommandGate::runAction(Action inAction, void *arg0, void *arg1, void *arg2, void *arg3) { IOWorkLoop * wl; uintptr_t * sleepersP; if (!inAction) return kIOReturnBadArgument; if (!(wl = workLoop)) return kIOReturnNotReady; // closeGate is recursive needn't worry if we already hold the lock. wl->closeGate(); sleepersP = (uintptr_t *) &reserved; // If the command gate is disabled and we aren't on the workloop thread // itself then sleep until we get enabled. IOReturn res; if (!wl->onThread()) { while (!enabled) { IOReturn sleepResult = kIOReturnSuccess; if (workLoop) { *sleepersP |= kSleepersWaitEnabled; sleepResult = wl->sleepGate(&enabled, THREAD_ABORTSAFE); *sleepersP &= ~kSleepersWaitEnabled; } bool wakeupTearDown = (!workLoop || (0 != (*sleepersP & kSleepersRemoved))); if ((kIOReturnSuccess != sleepResult) || wakeupTearDown) { wl->openGate(); if (wakeupTearDown) wl->wakeupGate(sleepersP, false); // No further resources used return kIOReturnAborted; } } } bool trace = ( gIOKitTrace & kIOTraceCommandGates ) ? true : false; if (trace) IOTimeStampStartConstant(IODBG_CMDQ(IOCMDQ_ACTION), VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner); IOStatisticsActionCall(); // Must be gated and on the work loop or enabled *sleepersP += kSleepersActions; res = (*inAction)(owner, arg0, arg1, arg2, arg3); *sleepersP -= kSleepersActions; if (trace) IOTimeStampEndConstant(IODBG_CMDQ(IOCMDQ_ACTION), VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner); if (kSleepersRemoved == ((kSleepersActionsMask|kSleepersRemoved) & *sleepersP)) { // no actions outstanding *sleepersP &= ~kSleepersRemoved; super::setWorkLoop(0); } wl->openGate(); return res; }