/* virtual */ void IOWorkLoop::threadMain() { restartThread: do { if ( !runEventSources() ) goto exitThread; IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock); if ( !ISSETP(&fFlags, kLoopTerminate) && !workToDo) { assert_wait((void *) &workToDo, false); IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); thread_continue_t cptr = NULL; if (!reserved || !(kPreciousStack & reserved->options)) cptr = OSMemberFunctionCast( thread_continue_t, this, &IOWorkLoop::threadMain); thread_block_parameter(cptr, this); goto restartThread; /* NOTREACHED */ } // At this point we either have work to do or we need // to commit suicide. But no matter // Clear the simple lock and retore the interrupt state IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); } while(workToDo); exitThread: thread_t thread = workThread; workThread = 0; // Say we don't have a loop and free ourselves free(); thread_deallocate(thread); (void) thread_terminate(thread); }
IOReturn IOSharedInterruptController::enableInterrupt(IOService *nub, int source) { IOInterruptSource *interruptSources; IOInterruptVectorNumber vectorNumber; IOInterruptVector *vector; OSData *vectorData; IOInterruptState interruptState; interruptSources = nub->_interruptSources; vectorData = interruptSources[source].vectorData; vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); vector = &vectors[vectorNumber]; interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); if (!vector->interruptDisabledSoft) { IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); return kIOReturnSuccess; } vector->interruptDisabledSoft = 0; vectorsEnabled++; IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); if (controllerDisabled && (vectorsEnabled == vectorsRegistered)) { controllerDisabled = 0; provider->enableInterrupt(0); } return kIOReturnSuccess; }
IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub, int source) { IOInterruptSource *interruptSources; IOInterruptVectorNumber vectorNumber; IOInterruptVector *vector; OSData *vectorData; IOInterruptState interruptState; interruptSources = nub->_interruptSources; vectorData = interruptSources[source].vectorData; vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy(); vector = &vectors[vectorNumber]; interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); if (!vector->interruptDisabledSoft) { vector->interruptDisabledSoft = 1; #if !defined(__i386__) && !defined(__x86_64__) OSMemoryBarrier(); #endif vectorsEnabled--; } IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); if (!getPlatform()->atInterruptLevel()) { while (vector->interruptActive) {} } return kIOReturnSuccess; }
IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub, int source) { IOInterruptSource *interruptSources; long vectorNumber; IOInterruptVector *vector; OSData *vectorData; IOInterruptState interruptState; interruptSources = nub->_interruptSources; vectorData = interruptSources[source].vectorData; vectorNumber = *(long *)vectorData->getBytesNoCopy(); vector = &vectors[vectorNumber]; interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); if (!vector->interruptDisabledSoft) { vector->interruptDisabledSoft = 1; #if __ppc__ sync(); isync(); #endif vectorsEnabled--; } IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); if (!getPlatform()->atInterruptLevel()) { while (vector->interruptActive); #if __ppc__ isync(); #endif } return kIOReturnSuccess; }
// Free is called twice: // First when the atomic retainCount transitions from 1 -> 0 // Secondly when the work loop itself is commiting hari kari // Hence the each leg of the free must be single threaded. void IOWorkLoop::free() { if (workThread) { IOInterruptState is; // If we are here then we must be trying to shut down this work loop // in this case disable all of the event source, mark the loop // as terminating and wakeup the work thread itself and return // Note: we hold the gate across the entire operation mainly for the // benefit of our event sources so we can disable them cleanly. closeGate(); disableAllEventSources(); is = IOSimpleLockLockDisableInterrupt(workToDoLock); SETP(&fFlags, kLoopTerminate); thread_wakeup_one((void *) &workToDo); IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); openGate(); } else /* !workThread */ { IOEventSource *event, *next; for (event = eventChain; event; event = next) { next = event->getNext(); event->setWorkLoop(0); event->setNext(0); event->release(); } eventChain = 0; // Either we have a partial initialization to clean up // or the workThread itself is performing hari-kari. // Either way clean up all of our resources and return. if (controlG) { controlG->release(); controlG = 0; } if (workToDoLock) { IOSimpleLockFree(workToDoLock); workToDoLock = 0; } if (gateLock) { IORecursiveLockFree(gateLock); gateLock = 0; } if (reserved) { IODelete(reserved, ExpansionData, 1); reserved = 0; } super::free(); } }
// Internal APIs used by event sources to control the thread void IOWorkLoop::signalWorkAvailable() { if (workToDoLock) { IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock); workToDo = true; thread_wakeup_one((void *) &workToDo); IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); } }
void IOFWSyncer::privateSignal() { if (threadMustStop) { IOInterruptState is = IOSimpleLockLockDisableInterrupt(guardLock); threadMustStop = false; thread_wakeup_one((void *) &threadMustStop); IOSimpleLockUnlockEnableInterrupt(guardLock, is); } }
IOReturn IOFWSyncer::wait(bool autoRelease) { IOInterruptState is = IOSimpleLockLockDisableInterrupt(guardLock); if (threadMustStop) { assert_wait((void *) &threadMustStop, false); IOSimpleLockUnlockEnableInterrupt(guardLock, is); thread_block(THREAD_CONTINUE_NULL); } else IOSimpleLockUnlockEnableInterrupt(guardLock, is); IOReturn result = fResult; // Pick up before auto deleting! if(autoRelease) release(); return result; }
IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub, int source) { IOInterruptVectorNumber vectorNumber; IOInterruptVector *vector; IOInterruptState interruptState; for (vectorNumber = 0; vectorNumber < kIOSharedInterruptControllerDefaultVectors; vectorNumber++) { vector = &vectors[vectorNumber]; // Get the lock for this vector. IOLockLock(vector->interruptLock); // Return success if it is not already registered if (!vector->interruptRegistered || (vector->nub != nub) || (vector->source != source)) { IOLockUnlock(vector->interruptLock); continue; } // Soft disable the source and the controller too. disableInterrupt(nub, source); // Clear all the storage for the vector except for interruptLock. vector->interruptActive = 0; vector->interruptDisabledSoft = 0; vector->interruptDisabledHard = 0; vector->interruptRegistered = 0; vector->nub = 0; vector->source = 0; vector->handler = 0; vector->target = 0; vector->refCon = 0; interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); vectorsRegistered--; IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); // Move along to the next one. IOLockUnlock(vector->interruptLock); } // Re-enable the controller if all vectors are enabled. if (vectorsEnabled == vectorsRegistered) { controllerDisabled = 0; provider->enableInterrupt(0); } return kIOReturnSuccess; }
/* virtual */ bool IOWorkLoop::runEventSources() { bool res = false; bool traceWL = (gIOKitTrace & kIOTraceWorkLoops) ? true : false; bool traceES = (gIOKitTrace & kIOTraceEventSources) ? true : false; closeGate(); if (ISSETP(&fFlags, kLoopTerminate)) goto abort; if (traceWL) IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_WORK), (uintptr_t) this); bool more; do { CLRP(&fFlags, kLoopRestart); more = false; IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock); workToDo = false; IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); /* NOTE: only loop over event sources in eventChain. Bypass "passive" event sources for performance */ for (IOEventSource *evnt = eventChain; evnt; evnt = evnt->getNext()) { if (traceES) IOTimeStampStartConstant(IODBG_WORKLOOP(IOWL_CLIENT), (uintptr_t) this, (uintptr_t) evnt); more |= evnt->checkForWork(); if (traceES) IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_CLIENT), (uintptr_t) this, (uintptr_t) evnt); if (ISSETP(&fFlags, kLoopTerminate)) goto abort; else if (fFlags & kLoopRestart) { more = true; break; } } } while (more); res = true; if (traceWL) IOTimeStampEndConstant(IODBG_WORKLOOP(IOWL_WORK), (uintptr_t) this); abort: openGate(); return res; }
IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub, int source) { IOInterruptSource *interruptSources; long vectorNumber; IOInterruptVector *vector; OSData *vectorData; IOInterruptState interruptState;; interruptSources = nub->_interruptSources; vectorData = interruptSources[source].vectorData; vectorNumber = *(long *)vectorData->getBytesNoCopy(); vector = &vectors[vectorNumber]; // Get the lock for this vector. IOTakeLock(vector->interruptLock); // Return success if it is not already registered if (!vector->interruptRegistered) { IOUnlock(vector->interruptLock); return kIOReturnSuccess; } // Soft disable the source. disableInterrupt(nub, source); // Clear all the storage for the vector except for interruptLock. vector->interruptActive = 0; vector->interruptDisabledSoft = 0; vector->interruptDisabledHard = 0; vector->interruptRegistered = 0; vector->nub = 0; vector->source = 0; vector->handler = 0; vector->target = 0; vector->refCon = 0; interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); vectorsRegistered--; IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); IOUnlock(vector->interruptLock); return kIOReturnSuccess; }
/* virtual */ bool IOWorkLoop::runEventSources() { bool res = false; closeGate(); if (ISSETP(&fFlags, kLoopTerminate)) goto abort; IOTimeWorkS(); bool more; do { CLRP(&fFlags, kLoopRestart); more = false; IOInterruptState is = IOSimpleLockLockDisableInterrupt(workToDoLock); workToDo = false; IOSimpleLockUnlockEnableInterrupt(workToDoLock, is); for (IOEventSource *evnt = eventChain; evnt; evnt = evnt->getNext()) { IOTimeClientS(); more |= evnt->checkForWork(); IOTimeClientE(); if (ISSETP(&fFlags, kLoopTerminate)) goto abort; else if (fFlags & kLoopRestart) { more = true; break; } } } while (more); res = true; IOTimeWorkE(); abort: openGate(); return res; }
IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub, int source, void *target, IOInterruptHandler handler, void *refCon) { IOInterruptSource *interruptSources; IOInterruptVectorNumber vectorNumber; IOInterruptVector *vector = 0; OSData *vectorData; IOInterruptState interruptState; interruptSources = nub->_interruptSources; // Find a free vector. vectorNumber = kIOSharedInterruptControllerDefaultVectors; while (vectorsRegistered != kIOSharedInterruptControllerDefaultVectors) { for (vectorNumber = 0; vectorNumber < kIOSharedInterruptControllerDefaultVectors; vectorNumber++) { vector = &vectors[vectorNumber]; // Get the lock for this vector. IOLockLock(vector->interruptLock); // Is it unregistered? if (!vector->interruptRegistered) break; // Move along to the next one. IOLockUnlock(vector->interruptLock); } if (vectorNumber != kIOSharedInterruptControllerDefaultVectors) break; } // Could not find a free one, so give up. if (vectorNumber == kIOSharedInterruptControllerDefaultVectors) { return kIOReturnNoResources; } // Create the vectorData for the IOInterruptSource. vectorData = OSData::withBytes(&vectorNumber, sizeof(vectorNumber)); if (vectorData == 0) { IOLockUnlock(vector->interruptLock); return kIOReturnNoMemory; } // Fill in the IOInterruptSource with the controller's info. interruptSources[source].interruptController = this; interruptSources[source].vectorData = vectorData; // Fill in vector with the client's info. vector->handler = handler; vector->nub = nub; vector->source = source; vector->target = target; vector->refCon = refCon; // Get the vector ready. It starts off soft disabled. vector->interruptDisabledSoft = 1; vector->interruptRegistered = 1; interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); // Move the high water mark if needed if (++vectorsRegistered > numVectors) numVectors = vectorsRegistered; IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); IOLockUnlock(vector->interruptLock); return kIOReturnSuccess; }
void IOFWSyncer::reinit() { IOInterruptState is = IOSimpleLockLockDisableInterrupt(guardLock); threadMustStop = true; IOSimpleLockUnlockEnableInterrupt(guardLock, is); }