+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_INTERRUPTIBLE);
+ *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_ADDRHIDE(inAction), VM_KERNEL_ADDRHIDE(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_ADDRHIDE(inAction), VM_KERNEL_ADDRHIDE(owner));
+ }
+
+ if (kSleepersRemoved == ((kSleepersActionsMask | kSleepersRemoved) & *sleepersP)) {
+ // no actions outstanding
+ *sleepersP &= ~kSleepersRemoved;
+ super::setWorkLoop(NULL);
+ }
+
+ wl->openGate();
+
+ return res;
+}