IOReturn IOCommandGate::attemptAction(Action inAction, void *arg0, void *arg1, void *arg2, void *arg3) { IOReturn res; IOWorkLoop * wl; if (!inAction) return kIOReturnBadArgument; if (!(wl = workLoop)) return kIOReturnNotReady; // Try to close the gate if can't get return immediately. if (!wl->tryCloseGate()) return kIOReturnCannotLock; // If the command gate is disabled then sleep until we get a wakeup if (!wl->onThread() && !enabled) res = kIOReturnNotPermitted; else { bool trace = ( gIOKitTrace & kIOTraceCommandGates ) ? true : false; if (trace) IOTimeStampStartConstant(IODBG_CMDQ(IOCMDQ_ACTION), VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner); IOStatisticsActionCall(); res = (*inAction)(owner, arg0, arg1, arg2, arg3); if (trace) IOTimeStampEndConstant(IODBG_CMDQ(IOCMDQ_ACTION), VM_KERNEL_UNSLIDE(inAction), (uintptr_t) owner); } wl->openGate(); return res; }
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; }