Beispiel #1
0
/* 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;
}
Beispiel #5
0
// 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();
    }
}
Beispiel #6
0
// 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;
}
Beispiel #10
0
/* 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;
}
Beispiel #12
0
/* 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);
}