X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/1c79356b52d46aa6b508fb032f5ae709b1f2897b..378393581903b274cb7a4d18e0d978071a6b592d:/iokit/Kernel/IOService.cpp diff --git a/iokit/Kernel/IOService.cpp b/iokit/Kernel/IOService.cpp index 51a544089..781fad86c 100644 --- a/iokit/Kernel/IOService.cpp +++ b/iokit/Kernel/IOService.cpp @@ -19,17 +19,6 @@ * * @APPLE_LICENSE_HEADER_END@ */ -/* - * Copyright (c) 1991-1999 Apple Computer, Inc. All rights reserved. - * - * HISTORY - * - * 29-Jan-91 Portions from IODevice.m, Doug Mitchell at NeXT, Created. - * 18-Jun-98 start IOKit objc - * 10-Nov-98 start iokit cpp - * 25-Feb-99 sdouglas, add threads and locks to ensure deadlock - * - */ #include @@ -37,26 +26,27 @@ #include #include #include +#include #include #include #include #include #include #include -#include +#include #include #include +#include +#include +#include +#include -//#define LESS_THREAD_CREATE //#define LOG kprintf #define LOG IOLog #include "IOServicePrivate.h" -#include -#include - -#include +// take lockForArbitration before LOCKNOTIFY /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -81,6 +71,7 @@ OSDefineMetaClassAndAbstractStructors(IONotifier, OSObject) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ static IOPlatformExpert * gIOPlatform; +static class IOPMrootDomain * gIOPMRootDomain; const IORegistryPlane * gIOServicePlane; const IORegistryPlane * gIOPowerPlane; const OSSymbol * gIODeviceMemoryKey; @@ -94,6 +85,7 @@ const OSSymbol * gIONameMatchKey; const OSSymbol * gIONameMatchedKey; const OSSymbol * gIOPropertyMatchKey; const OSSymbol * gIOLocationMatchKey; +const OSSymbol * gIOParentMatchKey; const OSSymbol * gIOPathMatchKey; const OSSymbol * gIOMatchCategoryKey; const OSSymbol * gIODefaultMatchCategoryKey; @@ -104,6 +96,10 @@ const OSSymbol * gIOKitDebugKey; const OSSymbol * gIOCommandPoolSizeKey; +const OSSymbol * gIOConsoleUsersKey; +const OSSymbol * gIOConsoleSessionUIDKey; +const OSSymbol * gIOConsoleUsersSeedKey; + static int gIOResourceGenerationCount; const OSSymbol * gIOServiceKey; @@ -116,6 +112,7 @@ const OSSymbol * gIOTerminatedNotification; const OSSymbol * gIOGeneralInterest; const OSSymbol * gIOBusyInterest; const OSSymbol * gIOAppPowerStateInterest; +const OSSymbol * gIOPriorityPowerStateInterest; static OSDictionary * gNotifications; static IORecursiveLock * gNotificationLock; @@ -131,6 +128,16 @@ static int gNumConfigThreads; static int gNumWaitingThreads; static IOLock * gIOServiceBusyLock; +static thread_t gIOTerminateThread; +static UInt32 gIOTerminateWork; +static OSArray * gIOTerminatePhase2List; +static OSArray * gIOStopList; +static OSArray * gIOStopProviderList; +static OSArray * gIOFinalizeList; + +static SInt32 gIOConsoleUsersSeed; +static OSData * gIOConsoleUsersSeedValue; + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #define LOCKREADNOTIFY() \ @@ -140,6 +147,28 @@ static IOLock * gIOServiceBusyLock; #define LOCKWRITE2READNOTIFY() #define UNLOCKNOTIFY() \ IORecursiveLockUnlock( gNotificationLock ) +#define SLEEPNOTIFY(event) \ + IORecursiveLockSleep( gNotificationLock, (void *)(event), THREAD_UNINT ) +#define WAKEUPNOTIFY(event) \ + IORecursiveLockWakeup( gNotificationLock, (void *)(event), /* wake one */ false ) + +#define randomDelay() \ + int del = read_processor_clock(); \ + del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \ + IOSleep( del ); + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#define queue_element(entry, element, type, field) do { \ + vm_address_t __ele = (vm_address_t) (entry); \ + __ele -= -4 + ((size_t)(&((type) 4)->field)); \ + (element) = (type) __ele; \ + } while(0) + +#define iterqueue(que, elt) \ + for (queue_entry_t elt = queue_first(que); \ + !queue_end(que, elt); \ + elt = queue_next(elt)) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -157,6 +186,9 @@ static queue_head_t gArbitrationLockQueueWaiting; static queue_head_t gArbitrationLockQueueFree; static IOLock * gArbitrationLockQueueLock; +bool IOService::isInactive( void ) const + { return( 0 != (kIOServiceInactiveState & getState())); } + /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ void IOService::initialize( void ) @@ -171,7 +203,8 @@ void IOService::initialize( void ) gIONameMatchedKey = OSSymbol::withCStringNoCopy( kIONameMatchedKey ); gIOPropertyMatchKey = OSSymbol::withCStringNoCopy( kIOPropertyMatchKey ); gIOPathMatchKey = OSSymbol::withCStringNoCopy( kIOPathMatchKey ); - gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); + gIOLocationMatchKey = OSSymbol::withCStringNoCopy( kIOLocationMatchKey ); + gIOParentMatchKey = OSSymbol::withCStringNoCopy( kIOParentMatchKey ); gIOMatchCategoryKey = OSSymbol::withCStringNoCopy( kIOMatchCategoryKey ); gIODefaultMatchCategoryKey = OSSymbol::withCStringNoCopy( @@ -197,6 +230,7 @@ void IOService::initialize( void ) gIOGeneralInterest = OSSymbol::withCStringNoCopy( kIOGeneralInterest ); gIOBusyInterest = OSSymbol::withCStringNoCopy( kIOBusyInterest ); gIOAppPowerStateInterest = OSSymbol::withCStringNoCopy( kIOAppPowerStateInterest ); + gIOPriorityPowerStateInterest = OSSymbol::withCStringNoCopy( kIOPriorityPowerStateInterest ); gNotifications = OSDictionary::withCapacity( 1 ); gIOPublishNotification = OSSymbol::withCStringNoCopy( @@ -211,6 +245,11 @@ void IOService::initialize( void ) kIOTerminatedNotification ); gIOServiceKey = OSSymbol::withCStringNoCopy( kIOServiceClass); + gIOConsoleUsersKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersKey); + gIOConsoleSessionUIDKey = OSSymbol::withCStringNoCopy( kIOConsoleSessionUIDKey); + gIOConsoleUsersSeedKey = OSSymbol::withCStringNoCopy( kIOConsoleUsersSeedKey); + gIOConsoleUsersSeedValue = OSData::withBytesNoCopy(&gIOConsoleUsersSeed, sizeof(gIOConsoleUsersSeed)); + gNotificationLock = IORecursiveLockAlloc(); assert( gIOServicePlane && gIODeviceMemoryKey @@ -219,7 +258,9 @@ void IOService::initialize( void ) && gIOProviderClassKey && gIONameMatchKey && gIONameMatchedKey && gIOMatchCategoryKey && gIODefaultMatchCategoryKey && gIOPublishNotification && gIOMatchedNotification - && gIOTerminatedNotification && gIOServiceKey ); + && gIOTerminatedNotification && gIOServiceKey + && gIOConsoleUsersKey && gIOConsoleSessionUIDKey + && gIOConsoleUsersSeedKey && gIOConsoleUsersSeedValue); gJobsLock = IOLockAlloc(); gJobs = OSOrderedSet::withCapacity( 10 ); @@ -240,11 +281,11 @@ void IOService::initialize( void ) assert( gArbitrationLockQueueLock ); -#ifdef LESS_THREAD_CREATE - for( int i = 0; i < kMaxConfigThreads; i++) - _IOConfigThread::configThread(); -#endif - + gIOTerminatePhase2List = OSArray::withCapacity( 2 ); + gIOStopList = OSArray::withCapacity( 16 ); + gIOStopProviderList = OSArray::withCapacity( 16 ); + gIOFinalizeList = OSArray::withCapacity( 16 ); + assert( gIOTerminatePhase2List && gIOStopList && gIOStopProviderList && gIOFinalizeList ); } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -272,8 +313,8 @@ static UInt64 getDebugFlags( OSDictionary * props ) // The default score is from the property table, & may be altered // during probe to change the start order. -IOService * IOService::probe( IOService * /* provider */, - SInt32 * /* score */) +IOService * IOService::probe( IOService * provider, + SInt32 * score ) { return( this ); } @@ -283,8 +324,16 @@ bool IOService::start( IOService * provider ) return( true ); } -void IOService::stop( IOService * /* provider */ ) +void IOService::stop( IOService * provider ) +{ +} + +void IOService::free( void ) { + if( getPropertyTable()) + unregisterAllInterest(); + PMfree(); + super::free(); } /* @@ -308,12 +357,8 @@ bool IOService::attach( IOService * provider ) provider->unlockForArbitration(); } else { - gIOServiceRoot = this; ok = attachToParent( getRegistryRoot(), gIOServicePlane); - gIOResources->attachToParent( getRegistryRoot(), - gIOServicePlane ); - publishResource("IOKit"); } return( ok ); @@ -326,25 +371,51 @@ IOService * IOService::getServiceRoot( void ) void IOService::detach( IOService * provider ) { + IOService * newProvider = 0; + SInt32 busy; + bool adjParent; + if( gIOKitDebug & kIOLogAttach) LOG("%s::detach(%s)\n", getName(), provider->getName()); lockForArbitration(); - if( (__state[1] & kIOServiceBusyStateMask) - && (provider == getProvider())) - provider->adjustBusy( -1 ); + adjParent = ((busy = (__state[1] & kIOServiceBusyStateMask)) + && (provider == getProvider())); detachFromParent( provider, gIOServicePlane ); + if( busy) { + newProvider = getProvider(); + if( busy && (__state[1] & kIOServiceTermPhase3State) && (0 == newProvider)) + _adjustBusy( -busy ); + } + unlockForArbitration(); + + if( newProvider) { + newProvider->lockForArbitration(); + newProvider->_adjustBusy(1); + newProvider->unlockForArbitration(); + } + + // check for last client detach from a terminated service + if( provider->lockForArbitration( true )) { + if( adjParent) + provider->_adjustBusy( -1 ); + if( (provider->__state[1] & kIOServiceTermPhase3State) + && (0 == provider->getClient())) { + provider->scheduleFinalize(); + } + provider->unlockForArbitration(); + } } /* * Register instance - publish it for matching */ -void IOService::registerService( IOOptionBits options = 0 ) +void IOService::registerService( IOOptionBits options ) { char * pathBuf; const char * path; @@ -397,50 +468,88 @@ void IOService::registerService( IOOptionBits options = 0 ) startMatching( options ); } -void IOService::startMatching( IOOptionBits options = 0 ) +void IOService::startMatching( IOOptionBits options ) { IOService * provider; + UInt32 prevBusy = 0; bool needConfig; + bool needWake = false; bool ok; bool sync; + bool waitAgain; lockForArbitration(); sync = (options & kIOServiceSynchronous) || ((provider = getProvider()) && (provider->__state[1] & kIOServiceSynchronousState)); - if( sync) - __state[1] |= kIOServiceSynchronousState; - else - __state[1] &= ~kIOServiceSynchronousState; - needConfig = (0 == (__state[1] & kIOServiceConfigState)) - && (0 == (__state[0] & kIOServiceInactiveState)) - && (kIOServiceRegisteredState != - (__state[0] & (kIOServiceRegisteredState - | kIOServiceMatchedState))); - __state[1] |= kIOServiceConfigState; + + needConfig = (0 == (__state[1] & (kIOServiceNeedConfigState | kIOServiceConfigState))) + && (0 == (__state[0] & kIOServiceInactiveState)); + + __state[1] |= kIOServiceNeedConfigState; + // __state[0] &= ~kIOServiceInactiveState; // if( sync) LOG("OSKernelStackRemaining = %08x @ %s\n", // OSKernelStackRemaining(), getName()); + if( needConfig) { + prevBusy = _adjustBusy( 1 ); + needWake = (0 != (kIOServiceSyncPubState & __state[1])); + } + + if( sync) + __state[1] |= kIOServiceSynchronousState; + else + __state[1] &= ~kIOServiceSynchronousState; + unlockForArbitration(); if( needConfig) { - adjustBusy( 1 ); - if( sync) { - doServiceMatch( options ); - waitQuiet(); - } else + + if( needWake) { + IOLockLock( gIOServiceBusyLock ); + thread_wakeup( (event_t) this/*&__state[1]*/ ); + IOLockUnlock( gIOServiceBusyLock ); + + } else if( !sync || (kIOServiceAsynchronous & options)) { + ok = (0 != _IOServiceJob::startJob( this, kMatchNubJob, options )); + + } else do { + + if( (__state[1] & kIOServiceNeedConfigState)) + doServiceMatch( options ); + + lockForArbitration(); + IOLockLock( gIOServiceBusyLock ); + + waitAgain = (prevBusy < (__state[1] & kIOServiceBusyStateMask)); + if( waitAgain) + __state[1] |= kIOServiceSyncPubState | kIOServiceBusyWaiterState; + else + __state[1] &= ~kIOServiceSyncPubState; + + unlockForArbitration(); + + if( waitAgain) + assert_wait( (event_t) this/*&__state[1]*/, THREAD_UNINT); + + IOLockUnlock( gIOServiceBusyLock ); + if( waitAgain) + thread_block(THREAD_CONTINUE_NULL); + + } while( waitAgain ); } } IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) { OSDictionary * table; - OSIterator * iter; + OSSet * set; + OSSet * allSet = 0; IOService * service; #if IOMATCHDEBUG SInt32 count = 0; @@ -451,18 +560,23 @@ IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) while( (table = (OSDictionary *) newTables->getFirstObject())) { LOCKWRITENOTIFY(); - iter = (OSIterator *) getExistingServices( table, - kIOServiceMatchedState ); + set = (OSSet *) getExistingServices( table, + kIOServiceRegisteredState, + kIOServiceExistingSet); UNLOCKNOTIFY(); - if( iter) { - while( (service = (IOService *) iter->getNextObject())) { - service->startMatching(); + if( set) { + #if IOMATCHDEBUG - count++; + count += set->getCount(); #endif + if (allSet) { + allSet->merge((const OSSet *) set); + set->release(); } - iter->release(); + else + allSet = set; } + #if IOMATCHDEBUG if( getDebugFlags( table ) & kIOLogMatch) LOG("Matching service count = %ld\n", count); @@ -470,13 +584,21 @@ IOReturn IOService::catalogNewDrivers( OSOrderedSet * newTables ) newTables->removeObject(table); } + if (allSet) { + while( (service = (IOService *) allSet->getAnyObject())) { + service->startMatching(kIOServiceAsynchronous); + allSet->removeObject(service); + } + allSet->release(); + } + newTables->release(); return( kIOReturnSuccess ); } _IOServiceJob * _IOServiceJob::startJob( IOService * nub, int type, - IOOptionBits options = 0 ) + IOOptionBits options ) { _IOServiceJob * job; @@ -687,7 +809,7 @@ IOReturn IOService::callPlatformFunction( const char * functionName, /* - * Platform expert accessors + * Accessors for global services */ IOPlatformExpert * IOService::getPlatform( void ) @@ -695,16 +817,33 @@ IOPlatformExpert * IOService::getPlatform( void ) return( gIOPlatform); } +class IOPMrootDomain * IOService::getPMRootDomain( void ) +{ + return( gIOPMRootDomain); +} + +IOService * IOService::getResourceService( void ) +{ + return( gIOResources ); +} + void IOService::setPlatform( IOPlatformExpert * platform) { gIOPlatform = platform; + gIOResources->attachToParent( gIOServiceRoot, gIOServicePlane ); +} + +void IOService::setPMRootDomain( class IOPMrootDomain * rootDomain) +{ + gIOPMRootDomain = rootDomain; + publishResource("IOKit"); } /* * Stacking change */ -bool IOService::lockForArbitration( bool isSuccessRequired = true ) +bool IOService::lockForArbitration( bool isSuccessRequired ) { bool found; bool success; @@ -825,7 +964,9 @@ bool IOService::lockForArbitration( bool isSuccessRequired = true ) link ); // wake the victim - thread_wakeup_one(victim); + IOLockWakeup( gArbitrationLockQueueLock, + victim, + /* one thread */ true ); // allow this thread to proceed (ie. wait) success = true; // (put request on wait queue) @@ -863,15 +1004,17 @@ bool IOService::lockForArbitration( bool isSuccessRequired = true ) link ); // declare that this thread will wait for a given event -restart_sleep: assert_wait( element, - element->required ? THREAD_UNINT - : THREAD_INTERRUPTIBLE ); +restart_sleep: wait_result = assert_wait( element, + element->required ? THREAD_UNINT + : THREAD_INTERRUPTIBLE ); // unlock global access IOUnlock( gArbitrationLockQueueLock ); // put thread to sleep, waiting for our event to fire... - wait_result = thread_block((void (*)(void)) 0); + if (wait_result == THREAD_WAITING) + wait_result = thread_block(THREAD_CONTINUE_NULL); + // ...and we've been woken up; we might be in one of two states: // (a) we've been aborted and our queue element is not on @@ -1055,7 +1198,9 @@ void IOService::unlockForArbitration( void ) link ); // wake the waiting thread - thread_wakeup_one(element); + IOLockWakeup( gArbitrationLockQueueLock, + element, + /* one thread */ true ); } } @@ -1085,7 +1230,7 @@ void IOService::applyToClients( IOServiceApplierFunction applier, // send a message to a client or interested party of this service IOReturn IOService::messageClient( UInt32 type, OSObject * client, - void * argument = 0, vm_size_t argSize = 0 ) + void * argument, vm_size_t argSize ) { IOReturn ret; IOService * service; @@ -1120,7 +1265,7 @@ IOReturn IOService::messageClient( UInt32 type, OSObject * client, _IOServiceNotifierInvocation *, link ); if( kIOServiceNotifyWaiter & notify->state) { notify->state &= ~kIOServiceNotifyWaiter; - thread_wakeup( (event_t) notify); + WAKEUPNOTIFY( notify ); } UNLOCKNOTIFY(); @@ -1137,28 +1282,36 @@ void IOService::applyToInterested( const OSSymbol * typeOfInterest, OSObjectApplierFunction applier, void * context ) { - OSArray * array; - unsigned int index; - OSObject * next; - OSArray * copyArray; + OSArray * copyArray = 0; applyToClients( (IOServiceApplierFunction) applier, context ); LOCKREADNOTIFY(); - array = OSDynamicCast( OSArray, getProperty( typeOfInterest )); - if( array) { - copyArray = OSArray::withArray( array ); - UNLOCKNOTIFY(); - if( copyArray) { - for( index = 0; - (next = array->getObject( index )); - index++) { - (*applier)(next, context); - } - copyArray->release(); - } - } else - UNLOCKNOTIFY(); + + IOCommand *notifyList = + OSDynamicCast( IOCommand, getProperty( typeOfInterest )); + + if( notifyList) { + copyArray = OSArray::withCapacity(1); + + // iterate over queue, entry is set to each element in the list + iterqueue(¬ifyList->fCommandChain, entry) { + _IOServiceInterestNotifier * notify; + + queue_element(entry, notify, _IOServiceInterestNotifier *, chain); + copyArray->setObject(notify); + } + } + UNLOCKNOTIFY(); + + if( copyArray) { + unsigned int index; + OSObject * next; + + for( index = 0; (next = copyArray->getObject( index )); index++) + (*applier)(next, context); + copyArray->release(); + } } struct MessageClientsContext { @@ -1182,7 +1335,7 @@ static void messageClientsApplier( OSObject * object, void * ctx ) // send a message to all clients IOReturn IOService::messageClients( UInt32 type, - void * argument = 0, vm_size_t argSize = 0 ) + void * argument, vm_size_t argSize ) { MessageClientsContext context; @@ -1208,11 +1361,11 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, IOServiceInterestHandler handler, void * target, void * ref ) { _IOServiceInterestNotifier * notify = 0; - OSArray * set; if( (typeOfInterest != gIOGeneralInterest) && (typeOfInterest != gIOBusyInterest) - && (typeOfInterest != gIOAppPowerStateInterest)) + && (typeOfInterest != gIOAppPowerStateInterest) + && (typeOfInterest != gIOPriorityPowerStateInterest)) return( 0 ); lockForArbitration(); @@ -1234,16 +1387,23 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, ////// queue LOCKWRITENOTIFY(); - if( 0 == (set = (OSArray *) getProperty( typeOfInterest ))) { - set = OSArray::withCapacity( 1 ); - if( set) { - setProperty( typeOfInterest, set ); - set->release(); - } - } - notify->whence = set; - if( set) - set->setObject( notify ); + + // Get the head of the notifier linked list + IOCommand *notifyList = (IOCommand *) getProperty( typeOfInterest ); + if (!notifyList || !OSDynamicCast(IOCommand, notifyList)) { + notifyList = OSTypeAlloc(IOCommand); + if (notifyList) { + notifyList->init(); + setProperty( typeOfInterest, notifyList); + notifyList->release(); + } + } + + if (notifyList) { + enqueue(¬ifyList->fCommandChain, ¬ify->chain); + notify->retain(); // ref'ed while in list + } + UNLOCKNOTIFY(); } } @@ -1252,28 +1412,30 @@ IONotifier * IOService::registerInterest( const OSSymbol * typeOfInterest, return( notify ); } -static void cleanInterestArray( OSObject * object ) +static void cleanInterestList( OSObject * head ) { - OSArray * array; - unsigned int index; - _IOServiceInterestNotifier * next; - - if( (array = OSDynamicCast( OSArray, object))) { - LOCKWRITENOTIFY(); - for( index = 0; - (next = (_IOServiceInterestNotifier *) - array->getObject( index )); - index++) { - next->whence = 0; - } - UNLOCKNOTIFY(); + IOCommand *notifyHead = OSDynamicCast(IOCommand, head); + if (!notifyHead) + return; + + LOCKWRITENOTIFY(); + while ( queue_entry_t entry = dequeue(¬ifyHead->fCommandChain) ) { + queue_next(entry) = queue_prev(entry) = 0; + + _IOServiceInterestNotifier * notify; + + queue_element(entry, notify, _IOServiceInterestNotifier *, chain); + notify->release(); } + UNLOCKNOTIFY(); } void IOService::unregisterAllInterest( void ) { - cleanInterestArray( getProperty( gIOGeneralInterest )); - cleanInterestArray( getProperty( gIOBusyInterest )); + cleanInterestList( getProperty( gIOGeneralInterest )); + cleanInterestList( getProperty( gIOBusyInterest )); + cleanInterestList( getProperty( gIOAppPowerStateInterest )); + cleanInterestList( getProperty( gIOPriorityPowerStateInterest )); } /* @@ -1299,10 +1461,7 @@ void _IOServiceInterestNotifier::wait() } if( doWait) { state |= kIOServiceNotifyWaiter; - assert_wait( this, THREAD_UNINT); - UNLOCKNOTIFY(); - thread_block((void (*)(void)) 0); - LOCKWRITENOTIFY(); + SLEEPNOTIFY(this); } } while( doWait ); @@ -1318,10 +1477,10 @@ void _IOServiceInterestNotifier::remove() { LOCKWRITENOTIFY(); - if( whence) { - whence->removeObject(whence->getNextIndexOfObject( - (OSObject *) this, 0 )); - whence = 0; + if( queue_next( &chain )) { + remqueue( 0, &chain); + queue_next( &chain) = queue_prev( &chain) = 0; + release(); } state &= ~kIOServiceNotifyEnable; @@ -1359,239 +1518,567 @@ void _IOServiceInterestNotifier::enable( bool was ) UNLOCKNOTIFY(); } +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /* - * Terminate + * Termination */ -// a method in case someone needs to override it -bool IOService::terminateClient( IOService * client, IOOptionBits options ) +#define tailQ(o) setObject(o) +#define headQ(o) setObject(0, o) +#define TLOG(fmt, args...) { if(kIOLogYield & gIOKitDebug) IOLog(fmt, ## args); } + +inline void _workLoopAction( IOWorkLoop::Action action, + IOService * service, + void * p0 = 0, void * p1 = 0, + void * p2 = 0, void * p3 = 0 ) +{ + IOWorkLoop * wl; + + if( (wl = service->getWorkLoop())) { + wl->retain(); + wl->runAction( action, service, p0, p1, p2, p3 ); + wl->release(); + } else + (*action)( service, p0, p1, p2, p3 ); +} + +bool IOService::requestTerminate( IOService * provider, IOOptionBits options ) { bool ok; - if( client->isParent( this, gIOServicePlane, true)) - // we are the clients only provider - ok = client->terminate( options ); - else - ok = true; + // if its our only provider + ok = isParent( provider, gIOServicePlane, true); + + // -- compat + if( ok) { + provider->terminateClient( this, options | kIOServiceRecursing ); + ok = (0 != (__state[1] & kIOServiceRecursing)); + } + // -- return( ok ); } -struct TerminateClientsContext { - IOService * provider; - IOOptionBits options; -}; - -static void terminateInterestApplier( OSObject * object, void * ctx ) +bool IOService::terminatePhase1( IOOptionBits options ) { - TerminateClientsContext * context = (TerminateClientsContext *) ctx; + IOService * victim; + IOService * client; + OSIterator * iter; + OSArray * makeInactive; + bool ok; + bool didInactive; + bool startPhase2 = false; - context->provider->messageClient( kIOMessageServiceIsTerminated, - object, (void *) context->options ); -} + TLOG("%s::terminatePhase1(%08lx)\n", getName(), options); -static void terminateClientsApplier( IOService * client, void * ctx ) -{ - TerminateClientsContext * context = (TerminateClientsContext *) ctx; + // -- compat + if( options & kIOServiceRecursing) { + __state[1] |= kIOServiceRecursing; + return( true ); + } + // -- + + makeInactive = OSArray::withCapacity( 16 ); + if( !makeInactive) + return( false ); + + victim = this; + victim->retain(); + + while( victim ) { + + didInactive = victim->lockForArbitration( true ); + if( didInactive) { + didInactive = (0 == (victim->__state[0] & kIOServiceInactiveState)); + if( didInactive) { + victim->__state[0] |= kIOServiceInactiveState; + victim->__state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState + | kIOServiceFirstPublishState | kIOServiceFirstMatchState); + victim->_adjustBusy( 1 ); + } + victim->unlockForArbitration(); + } + if( victim == this) + startPhase2 = didInactive; + if( didInactive) { + + victim->deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); + IOUserClient::destroyUserReferences( victim ); + + iter = victim->getClientIterator(); + if( iter) { + while( (client = (IOService *) iter->getNextObject())) { + TLOG("%s::requestTerminate(%s, %08lx)\n", + client->getName(), victim->getName(), options); + ok = client->requestTerminate( victim, options ); + TLOG("%s::requestTerminate(%s, ok = %d)\n", + client->getName(), victim->getName(), ok); + if( ok) + makeInactive->setObject( client ); + } + iter->release(); + } + } + victim->release(); + victim = (IOService *) makeInactive->getObject(0); + if( victim) { + victim->retain(); + makeInactive->removeObject(0); + } + } + + makeInactive->release(); - if( gIOKitDebug & kIOLogYield) - LOG("%s::terminateClient(%s,%08lx)\n", - context->provider->getName(), - client->getName(), context->options); + if( startPhase2) + scheduleTerminatePhase2( options ); - context->provider->terminateClient( client, - ((context->options) | kIOServiceRecursing) & ~kIOServiceSynchronous ); + return( true ); } -static void terminateRequestClose( IOService * client, void * ctx ) +void IOService::scheduleTerminatePhase2( IOOptionBits options ) { - TerminateClientsContext * context = (TerminateClientsContext *) ctx; - IOService * provider = context->provider; + AbsoluteTime deadline; + int waitResult = THREAD_AWAKENED; + bool wait, haveDeadline = false; + + options |= kIOServiceRequired; + + retain(); + + IOLockLock( gJobsLock ); + + if( (options & kIOServiceSynchronous) + && (current_thread() != gIOTerminateThread)) { + + do { + wait = (gIOTerminateThread != 0); + if( wait) { + // wait to become the terminate thread + IOLockSleep( gJobsLock, &gIOTerminateThread, THREAD_UNINT); + } + } while( wait ); + + gIOTerminateThread = current_thread(); + gIOTerminatePhase2List->setObject( this ); + gIOTerminateWork++; + + do { + while( gIOTerminateWork ) + terminateWorker( options ); + wait = (0 != (__state[1] & kIOServiceBusyStateMask)); + if( wait) { + // wait for the victim to go non-busy + if( !haveDeadline) { + clock_interval_to_deadline( 15, kSecondScale, &deadline ); + haveDeadline = true; + } + waitResult = IOLockSleepDeadline( gJobsLock, &gIOTerminateWork, + deadline, THREAD_UNINT ); + if( waitResult == THREAD_TIMED_OUT) { + TLOG("%s::terminate(kIOServiceSynchronous) timeout", getName()); + } + } + } while(gIOTerminateWork || (wait && (waitResult != THREAD_TIMED_OUT))); + + gIOTerminateThread = 0; + IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); - if( provider->isOpen( client)) { - if( gIOKitDebug & kIOLogYield) - LOG("%s::terminate request close(%s,%08lx)\n", - provider->getName(), - client->getName(), context->options); - provider->messageClient( kIOMessageServiceIsRequestingClose, - client, (void *) context->options ); + } else { + // ! kIOServiceSynchronous + + gIOTerminatePhase2List->setObject( this ); + if( 0 == gIOTerminateWork++) { + if( !gIOTerminateThread) + gIOTerminateThread = IOCreateThread( &terminateThread, (void *) options ); + else + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); + } } + + IOLockUnlock( gJobsLock ); + + release(); } -bool IOService::terminate( IOOptionBits options = 0 ) +void IOService::terminateThread( void * arg ) { - bool ok; - bool wasClosed; - bool madeInactive; - TerminateClientsContext context; + IOLockLock( gJobsLock ); - if( false == lockForArbitration( (options & kIOServiceRequired) )) - return false; + while (gIOTerminateWork) + terminateWorker( (IOOptionBits) arg ); - retain(); + gIOTerminateThread = 0; + IOLockWakeup( gJobsLock, (event_t) &gIOTerminateThread, /* one-thread */ false); + + IOLockUnlock( gJobsLock ); +} - context.provider = this; - context.options = options; +void IOService::scheduleStop( IOService * provider ) +{ + TLOG("%s::scheduleStop(%s)\n", getName(), provider->getName()); - ok = (options & kIOServiceRequired); - wasClosed = (false == handleIsOpen( 0 )); - if( !ok) - ok = wasClosed; + IOLockLock( gJobsLock ); + gIOStopList->tailQ( this ); + gIOStopProviderList->tailQ( provider ); - if( !ok) { - applyToClients( &terminateRequestClose, (void *) &context ); - wasClosed = (false == handleIsOpen( 0 )); - ok = wasClosed; + if( 0 == gIOTerminateWork++) { + if( !gIOTerminateThread) + gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 ); + else + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); } - if( ok) { - madeInactive = (0 == (__state[0] & kIOServiceInactiveState)); - if( madeInactive) { - __state[0] |= kIOServiceInactiveState; - __state[0] &= ~(kIOServiceRegisteredState | kIOServiceMatchedState); - if( 0 == (options & kIOServiceRecursing)) - __state[1] |= kIOServiceTerminatedState; - } - } else - madeInactive = false; + IOLockUnlock( gJobsLock ); +} - unlockForArbitration(); +void IOService::scheduleFinalize( void ) +{ + TLOG("%s::scheduleFinalize\n", getName()); - if( madeInactive) { + IOLockLock( gJobsLock ); + gIOFinalizeList->tailQ( this ); - adjustBusy( 1 ); - applyToInterested( gIOGeneralInterest, - &terminateInterestApplier, (void *) &context ); + if( 0 == gIOTerminateWork++) { + if( !gIOTerminateThread) + gIOTerminateThread = IOCreateThread( &terminateThread, (void *) 0 ); + else + IOLockWakeup(gJobsLock, (event_t) &gIOTerminateWork, /* one-thread */ false ); + } - deliverNotification( gIOTerminatedNotification, 0, 0xffffffff ); + IOLockUnlock( gJobsLock ); +} - applyToClients( &terminateClientsApplier, (void *) &context ); +bool IOService::willTerminate( IOService * provider, IOOptionBits options ) +{ + return( true ); +} - if( wasClosed && (0 == (options & kIOServiceRecursing))) { - if( options & kIOServiceSynchronous) - doServiceTerminate( 0 ); - else - ok = (0 != _IOServiceJob::startJob( this, kTerminateNubJob, 0 )); - } - if( options & kIOServiceSynchronous) - waitQuiet(); +bool IOService::didTerminate( IOService * provider, IOOptionBits options, bool * defer ) +{ + if( false == *defer) { + + if( lockForArbitration( true )) { + if( false == provider->handleIsOpen( this )) + scheduleStop( provider ); + // -- compat + else { + message( kIOMessageServiceIsRequestingClose, provider, (void *) options ); + if( false == provider->handleIsOpen( this )) + scheduleStop( provider ); + } + // -- + unlockForArbitration(); + } } - release(); + return( true ); +} - return( ok ); +void IOService::actionWillTerminate( IOService * victim, IOOptionBits options, + OSArray * doPhase2List ) +{ + OSIterator * iter; + IOService * client; + bool ok; + + iter = victim->getClientIterator(); + if( iter) { + while( (client = (IOService *) iter->getNextObject())) { + TLOG("%s::willTerminate(%s, %08lx)\n", + client->getName(), victim->getName(), options); + ok = client->willTerminate( victim, options ); + doPhase2List->tailQ( client ); + } + iter->release(); + } } -void IOService::doServiceTerminate( IOOptionBits options ) +void IOService::actionDidTerminate( IOService * victim, IOOptionBits options ) { - IOService * next; - OSIterator * iter; - IOService * client; - OSArray * deathList = 0; - unsigned int index; - bool finalize; - bool ok = true; + OSIterator * iter; + IOService * client; + bool defer = false; - next = this; - deathList = OSArray::withObjects( & (const OSObject *) next, 1, 1 ); - assert( deathList ); - if( !deathList) - return; + victim->messageClients( kIOMessageServiceIsTerminated, (void *) options ); - index = 0; - do { - iter = next->getClientIterator(); - assert( iter ); - if( iter) { + iter = victim->getClientIterator(); + if( iter) { + while( (client = (IOService *) iter->getNextObject())) { + TLOG("%s::didTerminate(%s, %08lx)\n", + client->getName(), victim->getName(), options); + client->didTerminate( victim, options, &defer ); + TLOG("%s::didTerminate(%s, defer %d)\n", + client->getName(), victim->getName(), defer); + } + iter->release(); + } +} - while( (client = (IOService *) iter->getNextObject())) { +void IOService::actionFinalize( IOService * victim, IOOptionBits options ) +{ + TLOG("%s::finalize(%08lx)\n", victim->getName(), options); + victim->finalize( options ); +} - if( gIOKitDebug & kIOLogYield) - LOG("%s::actionClients(%s)\n", - next->getName(), client->getName()); +void IOService::actionStop( IOService * provider, IOService * client ) +{ + TLOG("%s::stop(%s)\n", client->getName(), provider->getName()); + client->stop( provider ); + if( provider->isOpen( client )) + provider->close( client ); + TLOG("%s::detach(%s)\n", client->getName(), provider->getName()); + client->detach( provider ); +} - client->stop( next ); +void IOService::terminateWorker( IOOptionBits options ) +{ + OSArray * doPhase2List; + OSArray * didPhase2List; + OSSet * freeList; + UInt32 workDone; + IOService * victim; + IOService * client; + IOService * provider; + unsigned int idx; + bool moreToDo; + bool doPhase2; + bool doPhase3; + + options |= kIOServiceRequired; + + doPhase2List = OSArray::withCapacity( 16 ); + didPhase2List = OSArray::withCapacity( 16 ); + freeList = OSSet::withCapacity( 16 ); + if( (0 == doPhase2List) || (0 == didPhase2List) || (0 == freeList)) + return; - if( next->isOpen( client )) - next->close( client ); + do { + workDone = gIOTerminateWork; - client->detach( next ); + while( (victim = (IOService *) gIOTerminatePhase2List->getObject(0) )) { + + victim->retain(); + gIOTerminatePhase2List->removeObject(0); + IOLockUnlock( gJobsLock ); - client->lockForArbitration(); - if( (client->__state[0] & kIOServiceInactiveState) - && (0 == (client->__state[1] & kIOServiceTerminatedState)) - && (0 == client->getProvider()) ) { - client->__state[1] |= kIOServiceTerminatedState; - finalize = (false == client->handleIsOpen( 0 )); - } else - finalize = false; - client->unlockForArbitration(); + while( victim ) { + + doPhase2 = victim->lockForArbitration( true ); + if( doPhase2) { + doPhase2 = (0 != (kIOServiceInactiveState & victim->__state[0])); + if( doPhase2) { + doPhase2 = (0 == (victim->__state[1] & kIOServiceTermPhase2State)) + && (0 == (victim->__state[1] & kIOServiceConfigState)); + if( doPhase2) + victim->__state[1] |= kIOServiceTermPhase2State; + } + victim->unlockForArbitration(); + } + if( doPhase2) { + if( 0 == victim->getClient()) { + // no clients - will go to finalize + IOLockLock( gJobsLock ); + gIOFinalizeList->tailQ( victim ); + IOLockUnlock( gJobsLock ); + } else { + _workLoopAction( (IOWorkLoop::Action) &actionWillTerminate, + victim, (void *) options, (void *) doPhase2List ); + } + didPhase2List->headQ( victim ); + } + victim->release(); + victim = (IOService *) doPhase2List->getObject(0); + if( victim) { + victim->retain(); + doPhase2List->removeObject(0); + } + } + + while( (victim = (IOService *) didPhase2List->getObject(0)) ) { + + if( victim->lockForArbitration( true )) { + victim->__state[1] |= kIOServiceTermPhase3State; + victim->unlockForArbitration(); + } + _workLoopAction( (IOWorkLoop::Action) &actionDidTerminate, + victim, (void *) options ); + didPhase2List->removeObject(0); + } + IOLockLock( gJobsLock ); + } - if( finalize) - deathList->setObject( client ); + // phase 3 + do { + doPhase3 = false; + // finalize leaves + while( (victim = (IOService *) gIOFinalizeList->getObject(0))) { + + IOLockUnlock( gJobsLock ); + _workLoopAction( (IOWorkLoop::Action) &actionFinalize, + victim, (void *) options ); + IOLockLock( gJobsLock ); + // hold off free + freeList->setObject( victim ); + // safe if finalize list is append only + gIOFinalizeList->removeObject(0); + } + + for( idx = 0; + (!doPhase3) && (client = (IOService *) gIOStopList->getObject(idx)); ) { + + provider = (IOService *) gIOStopProviderList->getObject(idx); + assert( provider ); + + if( !provider->isChild( client, gIOServicePlane )) { + // may be multiply queued - nop it + TLOG("%s::nop stop(%s)\n", client->getName(), provider->getName()); + } else { + // not ready for stop if it has clients, skip it + if( (client->__state[1] & kIOServiceTermPhase3State) && client->getClient()) { + TLOG("%s::defer stop(%s)\n", client->getName(), provider->getName()); + idx++; + continue; + } + + IOLockUnlock( gJobsLock ); + _workLoopAction( (IOWorkLoop::Action) &actionStop, + provider, (void *) client ); + IOLockLock( gJobsLock ); + // check the finalize list now + doPhase3 = true; + } + // hold off free + freeList->setObject( client ); + freeList->setObject( provider ); + + // safe if stop list is append only + gIOStopList->removeObject( idx ); + gIOStopProviderList->removeObject( idx ); + idx = 0; } - iter->release(); - } - - } while( (next = (IOService *) deathList->getObject( ++index )) ); - while( index--) { + } while( doPhase3 ); - next = (IOService *) deathList->getObject( index ); - assert( next ); - next->retain(); - deathList->removeObject( index ); + gIOTerminateWork -= workDone; + moreToDo = (gIOTerminateWork != 0); - IOUserClient::destroyUserReferences( next ); - - next->unregisterAllInterest(); + if( !moreToDo) { + TLOG("iokit terminate done, %d stops remain\n", gIOStopList->getCount()); + } - ok = next->finalize( options ); - assert( ok ); + } while( moreToDo ); - if( gIOKitDebug & kIOLogYield) - LOG("%s __state = %08lx:%08lx\n", next->getName(), - next->__state[0], next->__state[1]); - next->adjustBusy( -1 ); + IOLockUnlock( gJobsLock ); - next->release(); - } + freeList->release(); + doPhase2List->release(); + didPhase2List->release(); - deathList->release(); + IOLockLock( gJobsLock ); } bool IOService::finalize( IOOptionBits options ) { OSIterator * iter; IOService * provider; - + iter = getProviderIterator(); assert( iter ); if( iter) { - while( (provider = (IOService *) iter->getNextObject())) { - /* we come down here on programmatic terminate */ - stop( provider ); - if( provider->isOpen( this )) - provider->close( this ); - detach( provider ); - } - iter->release(); + while( (provider = (IOService *) iter->getNextObject())) { + + // -- compat + if( 0 == (__state[1] & kIOServiceTermPhase3State)) { + /* we come down here on programmatic terminate */ + stop( provider ); + if( provider->isOpen( this )) + provider->close( this ); + detach( provider ); + } else { + //-- + if( provider->lockForArbitration( true )) { + if( 0 == (provider->__state[1] & kIOServiceTermPhase3State)) + scheduleStop( provider ); + provider->unlockForArbitration(); + } + } + } + iter->release(); } return( true ); } +#undef tailQ +#undef headQ + +/* + * Terminate + */ + +void IOService::doServiceTerminate( IOOptionBits options ) +{ +} + +// a method in case someone needs to override it +bool IOService::terminateClient( IOService * client, IOOptionBits options ) +{ + bool ok; + + if( client->isParent( this, gIOServicePlane, true)) + // we are the clients only provider + ok = client->terminate( options ); + else + ok = true; + + return( ok ); +} + +bool IOService::terminate( IOOptionBits options ) +{ + options |= kIOServiceTerminate; + + return( terminatePhase1( options )); +} + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + /* * Open & close */ +struct ServiceOpenMessageContext +{ + IOService * service; + UInt32 type; + IOService * excludeClient; + IOOptionBits options; +}; + +static void serviceOpenMessageApplier( OSObject * object, void * ctx ) +{ + ServiceOpenMessageContext * context = (ServiceOpenMessageContext *) ctx; + + if( object != context->excludeClient) + context->service->messageClient( context->type, object, (void *) context->options ); +} + bool IOService::open( IOService * forClient, - IOOptionBits options = 0, - void * arg = 0 ) + IOOptionBits options, + void * arg ) { - bool ok; + bool ok; + ServiceOpenMessageContext context; + + context.service = this; + context.type = kIOMessageServiceIsAttemptingOpen; + context.excludeClient = forClient; + context.options = options; + + applyToInterested( gIOGeneralInterest, + &serviceOpenMessageApplier, &context ); if( false == lockForArbitration(false) ) return false; @@ -1606,46 +2093,39 @@ bool IOService::open( IOService * forClient, } void IOService::close( IOService * forClient, - IOOptionBits options = 0 ) + IOOptionBits options ) { - bool ok; bool wasClosed; bool last = false; - OSIterator * iter; - IOService * client; lockForArbitration(); wasClosed = handleIsOpen( forClient ); if( wasClosed) { handleClose( forClient, options ); - - last = ( (__state[1] & kIOServiceTerminatedState) - && (false == handleIsOpen( 0 )) ); + last = (__state[1] & kIOServiceTermPhase3State); } unlockForArbitration(); - if( last) { - ok = (0 != _IOServiceJob::startJob( this, kTerminateNubJob, 0 )); - assert( ok ); + if( last) + forClient->scheduleStop( this ); - } else if( wasClosed) { + else if( wasClosed) { - iter = getClientIterator(); - assert( iter ); + ServiceOpenMessageContext context; + + context.service = this; + context.type = kIOMessageServiceWasClosed; + context.excludeClient = forClient; + context.options = options; - if( iter) { - while( (client = (IOService *) iter->getNextObject())) { - if( client != forClient) - messageClient( kIOMessageServiceWasClosed, client, 0 ); - } - iter->release(); - } + applyToInterested( gIOGeneralInterest, + &serviceOpenMessageApplier, &context ); } } -bool IOService::isOpen( const IOService * forClient = 0 ) const +bool IOService::isOpen( const IOService * forClient ) const { IOService * self = (IOService *) this; bool ok; @@ -1671,11 +2151,12 @@ bool IOService::handleOpen( IOService * forClient, else if( options & kIOServiceSeize ) { ok = (kIOReturnSuccess == messageClient( kIOMessageServiceIsRequestingClose, - __owner, (void *) options )); - if( ok && (0 == __owner )) + __owner, (void *) options )); + if( ok && (0 == __owner )) __owner = forClient; + else + ok = false; } - return( ok ); } @@ -1808,7 +2289,7 @@ bool IOService::invokeNotifer( _IOServiceNotifier * notify ) _IOServiceNotifierInvocation *, link ); if( kIOServiceNotifyWaiter & notify->state) { notify->state &= ~kIOServiceNotifyWaiter; - thread_wakeup( (event_t) notify); + WAKEUPNOTIFY( notify ); } UNLOCKNOTIFY(); } @@ -2074,6 +2555,24 @@ void IOService::probeCandidates( OSOrderedSet * matches ) iter->release(); } + + // adjust the busy count by -1 if matching is stalled for a module, + // or +1 if a previously stalled matching is complete. + lockForArbitration(); + SInt32 adjBusy = 0; + if( needReloc) { + adjBusy = (__state[1] & kIOServiceModuleStallState) ? 0 : 1; + if( adjBusy) + __state[1] |= kIOServiceModuleStallState; + + } else if( __state[1] & kIOServiceModuleStallState) { + __state[1] &= ~kIOServiceModuleStallState; + adjBusy = -1; + } + if( adjBusy) + _adjustBusy( adjBusy ); + unlockForArbitration(); + if( startDict) startDict->release(); } @@ -2089,13 +2588,37 @@ bool IOService::startCandidate( IOService * service ) ok = service->attach( this ); - if( ok) { - // stall for any nub resources - checkResources(); - // stall for any driver resources - service->checkResources(); + if( ok) + { + if (this != gIOResources) + { + // stall for any nub resources + checkResources(); + // stall for any driver resources + service->checkResources(); + } + + AbsoluteTime startTime; + AbsoluteTime endTime; + UInt64 nano; - ok = service->start( this ); + if (kIOLogStart & gIOKitDebug) + clock_get_uptime(&startTime); + + ok = service->start(this); + + if (kIOLogStart & gIOKitDebug) + { + clock_get_uptime(&endTime); + + if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0) + { + SUB_ABSOLUTETIME(&endTime, &startTime); + absolutetime_to_nanoseconds(endTime, &nano); + if (nano > 500000000ULL) + IOLog("%s::start took %ld ms\n", service->getName(), (UInt32)(nano / 1000000ULL)); + } + } if( !ok) service->detach( this ); } @@ -2107,7 +2630,7 @@ IOService * IOService::resources( void ) return( gIOResources ); } -void IOService::publishResource( const char * key, OSObject * value = 0 ) +void IOService::publishResource( const char * key, OSObject * value ) { const OSSymbol * sym; @@ -2117,35 +2640,38 @@ void IOService::publishResource( const char * key, OSObject * value = 0 ) } } -void IOService::publishResource( const OSSymbol * key, OSObject * value = 0 ) +void IOService::publishResource( const OSSymbol * key, OSObject * value ) { if( 0 == value) value = (OSObject *) gIOServiceKey; gIOResources->setProperty( key, value); + if( IORecursiveLockHaveLock( gNotificationLock)) + return; + gIOResourceGenerationCount++; gIOResources->registerService(); } bool IOService::addNeededResource( const char * key ) { - OSObject * resources; + OSObject * resourcesProp; OSSet * set; OSString * newKey; bool ret; - resources = getProperty( gIOResourceMatchKey ); + resourcesProp = getProperty( gIOResourceMatchKey ); newKey = OSString::withCString( key ); - if( (0 == resources) || (0 == newKey)) + if( (0 == resourcesProp) || (0 == newKey)) return( false); - set = OSDynamicCast( OSSet, resources ); + set = OSDynamicCast( OSSet, resourcesProp ); if( !set) { set = OSSet::withCapacity( 1 ); if( set) - set->setObject( resources ); + set->setObject( resourcesProp ); } else set->retain(); @@ -2192,32 +2718,32 @@ bool IOService::checkResource( OSObject * matching ) bool IOService::checkResources( void ) { - OSObject * resources; + OSObject * resourcesProp; OSSet * set; OSIterator * iter; bool ok; - resources = getProperty( gIOResourceMatchKey ); - if( 0 == resources) + resourcesProp = getProperty( gIOResourceMatchKey ); + if( 0 == resourcesProp) return( true ); - if( (set = OSDynamicCast( OSSet, resources ))) { + if( (set = OSDynamicCast( OSSet, resourcesProp ))) { iter = OSCollectionIterator::withCollection( set ); ok = (0 != iter); - while( ok && (resources = iter->getNextObject()) ) - ok = checkResource( resources ); + while( ok && (resourcesProp = iter->getNextObject()) ) + ok = checkResource( resourcesProp ); if( iter) iter->release(); } else - ok = checkResource( resources ); + ok = checkResource( resourcesProp ); return( ok ); } -_IOConfigThread * _IOConfigThread::configThread( void ) +void _IOConfigThread::configThread( void ) { _IOConfigThread * inst; @@ -2226,18 +2752,17 @@ _IOConfigThread * _IOConfigThread::configThread( void ) continue; if( !inst->init()) continue; - if( !(inst->thread = IOCreateThread - ( (IOThreadFunc) &_IOConfigThread::main, inst ))) + if( !(IOCreateThread((IOThreadFunc) &_IOConfigThread::main, inst ))) continue; - return( inst ); + return; } while( false); if( inst) inst->release(); - return( 0 ); + return; } void _IOConfigThread::free( void ) @@ -2268,7 +2793,8 @@ void IOService::doServiceMatch( IOOptionBits options ) deliverNotification( gIOFirstPublishNotification, kIOServiceFirstPublishState, 0xffffffff ); LOCKREADNOTIFY(); - __state[1] &= ~kIOServiceConfigState; + __state[1] &= ~kIOServiceNeedConfigState; + __state[1] |= kIOServiceConfigState; __state[0] |= kIOServiceRegisteredState; if( reRegistered && (0 == (__state[0] & kIOServiceInactiveState))) { @@ -2297,7 +2823,7 @@ void IOService::doServiceMatch( IOOptionBits options ) } lockForArbitration(); - reRegistered = (0 != (__state[1] & kIOServiceConfigState)); + reRegistered = (0 != (__state[1] & kIOServiceNeedConfigState)); keepGuessing = (reRegistered || (catalogGeneration != gIOCatalogue->getGenerationCount())) @@ -2307,7 +2833,8 @@ void IOService::doServiceMatch( IOOptionBits options ) unlockForArbitration(); } - if( 0 == (__state[0] & kIOServiceInactiveState)) { + if( (0 == (__state[0] & kIOServiceInactiveState)) + && (0 == (__state[1] & kIOServiceModuleStallState)) ) { deliverNotification( gIOMatchedNotification, kIOServiceMatchedState, 0xffffffff ); if( 0 == (__state[0] & kIOServiceFirstMatchState)) @@ -2315,33 +2842,43 @@ void IOService::doServiceMatch( IOOptionBits options ) kIOServiceFirstMatchState, 0xffffffff ); } - unlockForArbitration(); + __state[1] &= ~kIOServiceConfigState; + if( __state[0] & kIOServiceInactiveState) + scheduleTerminatePhase2(); - adjustBusy( -1 ); + _adjustBusy( -1 ); + unlockForArbitration(); } -void IOService::adjustBusy( SInt32 delta ) +UInt32 IOService::_adjustBusy( SInt32 delta ) { IOService * next; UInt32 count; - bool wasQuiet, nowQuiet; - - if( 0 == delta) - return; + UInt32 result; + bool wasQuiet, nowQuiet, needWake; - IOTakeLock( gIOServiceBusyLock ); next = this; + result = __state[1] & kIOServiceBusyStateMask; - do { + if( delta) do { + if( next != this) + next->lockForArbitration(); count = next->__state[1] & kIOServiceBusyStateMask; assert( count < kIOServiceBusyMax); wasQuiet = (0 == count); assert( (!wasQuiet) || (delta > 0)); next->__state[1] += delta; nowQuiet = (0 == (next->__state[1] & kIOServiceBusyStateMask)); + needWake = (0 != (kIOServiceBusyWaiterState & next->__state[1])); - if( nowQuiet) + if( needWake) { + next->__state[1] &= ~kIOServiceBusyWaiterState; + IOLockLock( gIOServiceBusyLock ); thread_wakeup( (event_t) next); + IOLockUnlock( gIOServiceBusyLock ); + } + if( next != this) + next->unlockForArbitration(); if( (wasQuiet || nowQuiet) ) { OSArray * array; @@ -2368,7 +2905,14 @@ void IOService::adjustBusy( SInt32 delta ) } while( (wasQuiet || nowQuiet) && (next = next->getProvider())); - IOUnlock( gIOServiceBusyLock ); + return( result ); +} + +void IOService::adjustBusy( SInt32 delta ) +{ + lockForArbitration(); + _adjustBusy( delta ); + unlockForArbitration(); } UInt32 IOService::getBusyState( void ) @@ -2377,7 +2921,7 @@ UInt32 IOService::getBusyState( void ) } IOReturn IOService::waitForState( UInt32 mask, UInt32 value, - mach_timespec_t * timeout = 0 ) + mach_timespec_t * timeout ) { bool wait; int waitResult = THREAD_AWAKENED; @@ -2385,15 +2929,14 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, AbsoluteTime abstime; do { - IOTakeLock( gIOServiceBusyLock ); + lockForArbitration(); + IOLockLock( gIOServiceBusyLock ); wait = (value != (__state[1] & mask)); - if( wait) - { - assert_wait( (event_t) this, THREAD_UNINT ); - if ( timeout ) - { - if ( computeDeadline ) - { + if( wait) { + __state[1] |= kIOServiceBusyWaiterState; + unlockForArbitration(); + if( timeout ) { + if( computeDeadline ) { AbsoluteTime nsinterval; clock_interval_to_absolutetime_interval( timeout->tv_sec, kSecondScale, &abstime ); @@ -2404,26 +2947,26 @@ IOReturn IOService::waitForState( UInt32 mask, UInt32 value, abstime, &abstime ); computeDeadline = false; } - thread_set_timer_deadline( abstime ); + + assert_wait_deadline((event_t)this, THREAD_UNINT, __OSAbsoluteTime(abstime)); } - } - IOUnlock( gIOServiceBusyLock ); + else + assert_wait((event_t)this, THREAD_UNINT ); + } else + unlockForArbitration(); + IOLockUnlock( gIOServiceBusyLock ); if( wait) - { - waitResult = thread_block((void (*)(void)) 0); - if ( timeout && (waitResult != THREAD_TIMED_OUT)) - thread_cancel_timer(); - } + waitResult = thread_block(THREAD_CONTINUE_NULL); - } while( wait && ( waitResult != THREAD_TIMED_OUT ) ); + } while( wait && (waitResult != THREAD_TIMED_OUT)); - if ( waitResult == THREAD_TIMED_OUT ) + if( waitResult == THREAD_TIMED_OUT) return( kIOReturnTimeout ); else return( kIOReturnSuccess ); } -IOReturn IOService::waitQuiet( mach_timespec_t * timeout = 0 ) +IOReturn IOService::waitQuiet( mach_timespec_t * timeout ) { return( waitForState( kIOServiceBusyStateMask, 0, timeout )); } @@ -2446,13 +2989,7 @@ void _IOConfigThread::main( _IOConfigThread * self ) do { -#if 0 -#define randomDelay() \ - int del = read_processor_clock(); \ - del = (((int)IOThreadSelf()) ^ del ^ (del >> 10)) & 0x3ff; \ - IOSleep( del ); - randomDelay(); -#endif +// randomDelay(); semaphore_wait( gJobsSemaphore ); @@ -2462,10 +2999,8 @@ void _IOConfigThread::main( _IOConfigThread * self ) gJobs->removeObject(job); if( job) { gOutstandingJobs--; -#ifndef LESS_THREAD_CREATE // gNumConfigThreads--; // we're out of service gNumWaitingThreads--; // we're out of service -#endif } IOUnlock( gJobsLock ); @@ -2483,10 +3018,6 @@ void _IOConfigThread::main( _IOConfigThread * self ) nub->doServiceMatch( job->options ); break; - case kTerminateNubJob: - nub->doServiceTerminate( job->options ); - break; - default: LOG("config(%x): strange type (%d)\n", (int) IOThreadSelf(), job->type ); @@ -2497,14 +3028,16 @@ void _IOConfigThread::main( _IOConfigThread * self ) job->release(); IOTakeLock( gJobsLock ); -#ifndef LESS_THREAD_CREATE alive = (gOutstandingJobs > gNumWaitingThreads); if( alive) gNumWaitingThreads++; // back in service // gNumConfigThreads++; - else - gNumConfigThreads--; -#endif + else { + if( 0 == --gNumConfigThreads) { +// IOLog("MATCH IDLE\n"); + IOLockWakeup( gJobsLock, (event_t) &gNumConfigThreads, /* one-thread */ false ); + } + } IOUnlock( gJobsLock ); } @@ -2516,6 +3049,41 @@ void _IOConfigThread::main( _IOConfigThread * self ) self->release(); } +IOReturn IOService::waitMatchIdle( UInt32 msToWait ) +{ + bool wait; + int waitResult = THREAD_AWAKENED; + bool computeDeadline = true; + AbsoluteTime abstime; + + IOLockLock( gJobsLock ); + do { + wait = (0 != gNumConfigThreads); + if( wait) { + if( msToWait) { + if( computeDeadline ) { + clock_interval_to_absolutetime_interval( + msToWait, kMillisecondScale, &abstime ); + clock_absolutetime_interval_to_deadline( + abstime, &abstime ); + computeDeadline = false; + } + waitResult = IOLockSleepDeadline( gJobsLock, &gNumConfigThreads, + abstime, THREAD_UNINT ); + } else { + waitResult = IOLockSleep( gJobsLock, &gNumConfigThreads, + THREAD_UNINT ); + } + } + } while( wait && (waitResult != THREAD_TIMED_OUT)); + IOLockUnlock( gJobsLock ); + + if( waitResult == THREAD_TIMED_OUT) + return( kIOReturnTimeout ); + else + return( kIOReturnSuccess ); +} + void _IOServiceJob::pingConfig( _IOServiceJob * job ) { int count; @@ -2551,44 +3119,64 @@ void _IOServiceJob::pingConfig( _IOServiceJob * job ) semaphore_signal( gJobsSemaphore ); } - // internal - call with gNotificationLock OSObject * IOService::getExistingServices( OSDictionary * matching, - IOOptionBits inState, IOOptionBits options = 0 ) + IOOptionBits inState, IOOptionBits options ) { OSObject * current = 0; OSIterator * iter; IOService * service; + OSObject * obj; if( !matching) return( 0 ); - iter = IORegistryIterator::iterateOver( gIOServicePlane, - kIORegistryIterateRecursively ); - if( iter) { - do { - iter->reset(); - while( (service = (IOService *) iter->getNextObject())) { - if( (inState == (service->__state[0] & inState)) - && (0 == (service->__state[0] & kIOServiceInactiveState)) - && service->passiveMatch( matching )) { - - if( options & kIONotifyOnce) { - current = service; - break; - } - if( current) - ((OSSet *)current)->setObject( service ); - else - current = OSSet::withObjects( - & (const OSObject *) service, 1, 1 ); - } - } - } while( !service && !iter->isValid()); - iter->release(); + if(true + && (obj = matching->getObject(gIOProviderClassKey)) + && gIOResourcesKey + && gIOResourcesKey->isEqualTo(obj) + && (service = gIOResources)) + { + if( (inState == (service->__state[0] & inState)) + && (0 == (service->__state[0] & kIOServiceInactiveState)) + && service->passiveMatch( matching )) + { + if( options & kIONotifyOnce) + current = service; + else + current = OSSet::withObjects( + (const OSObject **) &service, 1, 1 ); + } + } + else + { + iter = IORegistryIterator::iterateOver( gIOServicePlane, + kIORegistryIterateRecursively ); + if( iter) { + do { + iter->reset(); + while( (service = (IOService *) iter->getNextObject())) { + if( (inState == (service->__state[0] & inState)) + && (0 == (service->__state[0] & kIOServiceInactiveState)) + && service->passiveMatch( matching )) { + + if( options & kIONotifyOnce) { + current = service; + break; + } + if( current) + ((OSSet *)current)->setObject( service ); + else + current = OSSet::withObjects( + (const OSObject **) &service, 1, 1 ); + } + } + } while( !service && !iter->isValid()); + iter->release(); + } } - if( current && (0 == (options & kIONotifyOnce))) { + if( current && (0 == (options & (kIONotifyOnce | kIOServiceExistingSet)))) { iter = OSCollectionIterator::withCollection( (OSSet *)current ); current->release(); current = iter; @@ -2606,7 +3194,7 @@ OSIterator * IOService::getMatchingServices( OSDictionary * matching ) LOCKWRITENOTIFY(); iter = (OSIterator *) getExistingServices( matching, - kIOServiceRegisteredState ); + kIOServiceMatchedState ); UNLOCKNOTIFY(); @@ -2618,7 +3206,7 @@ OSIterator * IOService::getMatchingServices( OSDictionary * matching ) IONotifier * IOService::setNotification( const OSSymbol * type, OSDictionary * matching, IOServiceNotificationHandler handler, void * target, void * ref, - SInt32 priority = 0 ) + SInt32 priority ) { _IOServiceNotifier * notify = 0; OSOrderedSet * set; @@ -2673,9 +3261,12 @@ IONotifier * IOService::doInstallNotification( if( !matching) return( 0 ); - if( (type == gIOPublishNotification) - || (type == gIOFirstPublishNotification)) + if( type == gIOPublishNotification) inState = kIOServiceRegisteredState; + + else if( type == gIOFirstPublishNotification) + inState = kIOServiceFirstPublishState; + else if( (type == gIOMatchedNotification) || (type == gIOFirstMatchNotification)) inState = kIOServiceMatchedState; @@ -2719,8 +3310,8 @@ IONotifier * IOService::installNotification( IONotifier * IOService::addNotification( const OSSymbol * type, OSDictionary * matching, IOServiceNotificationHandler handler, - void * target, void * ref = 0, - SInt32 priority = 0 ) + void * target, void * ref, + SInt32 priority ) { OSIterator * existing; _IOServiceNotifier * notify; @@ -2766,7 +3357,7 @@ bool IOService::syncNotificationHandler( } IOService * IOService::waitForService( OSDictionary * matching, - mach_timespec_t * timeout = 0 ) + mach_timespec_t * timeout ) { IONotifier * notify = 0; // priority doesn't help us much since we need a thread wakeup @@ -2876,7 +3467,7 @@ IOOptionBits IOService::getState( void ) const */ OSDictionary * IOService::serviceMatching( const OSString * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { if( !table) table = OSDictionary::withCapacity( 2 ); @@ -2887,7 +3478,7 @@ OSDictionary * IOService::serviceMatching( const OSString * name, } OSDictionary * IOService::serviceMatching( const char * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { const OSString * str; @@ -2901,7 +3492,7 @@ OSDictionary * IOService::serviceMatching( const char * name, } OSDictionary * IOService::nameMatching( const OSString * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { if( !table) table = OSDictionary::withCapacity( 2 ); @@ -2912,7 +3503,7 @@ OSDictionary * IOService::nameMatching( const OSString * name, } OSDictionary * IOService::nameMatching( const char * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { const OSString * str; @@ -2926,7 +3517,7 @@ OSDictionary * IOService::nameMatching( const char * name, } OSDictionary * IOService::resourceMatching( const OSString * str, - OSDictionary * table = 0 ) + OSDictionary * table ) { table = serviceMatching( gIOResourcesKey, table ); if( table) @@ -2936,7 +3527,7 @@ OSDictionary * IOService::resourceMatching( const OSString * str, } OSDictionary * IOService::resourceMatching( const char * name, - OSDictionary * table = 0 ) + OSDictionary * table ) { const OSSymbol * str; @@ -2973,10 +3564,7 @@ void _IOServiceNotifier::wait() } if( doWait) { state |= kIOServiceNotifyWaiter; - assert_wait( this, THREAD_UNINT); - UNLOCKNOTIFY(); - thread_block((void (*)(void)) 0); - LOCKWRITENOTIFY(); + SLEEPNOTIFY(this); } } while( doWait ); @@ -3090,6 +3678,43 @@ bool IOResources::matchPropertyTable( OSDictionary * table ) return( ok ); } +IOReturn IOResources::setProperties( OSObject * properties ) +{ + IOReturn err; + const OSSymbol * key; + OSDictionary * dict; + OSCollectionIterator * iter; + + err = IOUserClient::clientHasPrivilege(current_task(), kIOClientPrivilegeAdministrator); + if ( kIOReturnSuccess != err) + return( err ); + + dict = OSDynamicCast(OSDictionary, properties); + if( 0 == dict) + return( kIOReturnBadArgument); + + iter = OSCollectionIterator::withCollection( dict); + if( 0 == iter) + return( kIOReturnBadArgument); + + while( (key = OSDynamicCast(OSSymbol, iter->getNextObject()))) { + + if (gIOConsoleUsersKey == key) + { + IORegistryEntry::getRegistryRoot()->setProperty(key, dict->getObject(key)); + OSIncrementAtomic( &gIOConsoleUsersSeed ); + publishResource( gIOConsoleUsersSeedKey, gIOConsoleUsersSeedValue ); + continue; + } + + publishResource( key, dict->getObject(key) ); + } + + iter->release(); + + return( kIOReturnSuccess ); +} + /* * Helpers for matching dictionaries. * Keys existing in matching are checked in properties. @@ -3195,6 +3820,7 @@ bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) SInt32 score; OSNumber * newPri; bool match = true; + bool matchParent = false; UInt32 done; assert( table ); @@ -3202,140 +3828,174 @@ bool IOService::passiveMatch( OSDictionary * table, bool changesOK ) where = this; do { - done = 0; + do { + done = 0; - str = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey)); - if( str) { - done++; - match = (0 != where->metaCast( str )); - if( !match) - break; - } + str = OSDynamicCast( OSString, table->getObject( gIOProviderClassKey)); + if( str) { + done++; + match = (0 != where->metaCast( str )); + if( !match) + break; + } - obj = table->getObject( gIONameMatchKey ); - if( obj) { - done++; - match = compareNames( obj, changesOK ? &matched : 0 ); - if( !match) - break; - if( changesOK && matched) { - // leave a hint as to which name matched - table->setObject( gIONameMatchedKey, matched ); - matched->release(); + obj = table->getObject( gIONameMatchKey ); + if( obj) { + done++; + match = where->compareNames( obj, changesOK ? &matched : 0 ); + if( !match) + break; + if( changesOK && matched) { + // leave a hint as to which name matched + table->setObject( gIONameMatchedKey, matched ); + matched->release(); + } } - } - obj = table->getObject( gIOPropertyMatchKey ); - if( obj) { - - OSDictionary * dict; - OSDictionary * nextDict; - OSIterator * iter; - - done++; - dict = where->dictionaryWithProperties(); - if( dict) { - nextDict = OSDynamicCast( OSDictionary, obj); - if( nextDict) - iter = 0; - else - iter = OSCollectionIterator::withCollection( - OSDynamicCast(OSCollection, obj)); - - while( nextDict - || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, - iter->getNextObject()))))) { - match = dict->isEqualTo( nextDict, nextDict); - if( !match) - break; - nextDict = 0; + + str = OSDynamicCast( OSString, table->getObject( gIOLocationMatchKey )); + if( str) { + + const OSSymbol * sym; + + done++; + match = false; + sym = where->copyLocation(); + if( sym) { + match = sym->isEqualTo( str ); + sym->release(); } - dict->release(); - if( iter) - iter->release(); if( !match) break; } - } - str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); - if( str) { - done++; - entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); - match = (where == entry); - if( entry) - entry->release(); - if( !match) - break; - } + obj = table->getObject( gIOPropertyMatchKey ); + if( obj) { - num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); - if( num) { + OSDictionary * dict; + OSDictionary * nextDict; + OSIterator * iter; - OSIterator * iter; - IOService * service = 0; - UInt32 serviceCount = 0; + done++; + match = false; + dict = where->dictionaryWithProperties(); + if( dict) { + nextDict = OSDynamicCast( OSDictionary, obj); + if( nextDict) + iter = 0; + else + iter = OSCollectionIterator::withCollection( + OSDynamicCast(OSCollection, obj)); + + while( nextDict + || (iter && (0 != (nextDict = OSDynamicCast(OSDictionary, + iter->getNextObject()))))) { + match = dict->isEqualTo( nextDict, nextDict); + if( match) + break; + nextDict = 0; + } + dict->release(); + if( iter) + iter->release(); + } + if( !match) + break; + } - done++; - iter = getClientIterator(); - if( iter) { - while( (service = (IOService *) iter->getNextObject())) { - if( kIOServiceInactiveState & service->__state[0]) - continue; - if( 0 == service->getProperty( gIOMatchCategoryKey )) - continue; - ++serviceCount; + str = OSDynamicCast( OSString, table->getObject( gIOPathMatchKey )); + if( str) { + done++; + entry = IORegistryEntry::fromPath( str->getCStringNoCopy() ); + match = (where == entry); + if( entry) + entry->release(); + if( !match) + break; + } + + num = OSDynamicCast( OSNumber, table->getObject( gIOMatchedServiceCountKey )); + if( num) { + + OSIterator * iter; + IOService * service = 0; + UInt32 serviceCount = 0; + + done++; + iter = where->getClientIterator(); + if( iter) { + while( (service = (IOService *) iter->getNextObject())) { + if( kIOServiceInactiveState & service->__state[0]) + continue; + if( 0 == service->getProperty( gIOMatchCategoryKey )) + continue; + ++serviceCount; + } + iter->release(); } - iter->release(); + match = (serviceCount == num->unsigned32BitValue()); + if( !match) + break; } - match = (serviceCount == num->unsigned32BitValue()); - if( !match) - break; - } - if( done == table->getCount()) - // don't call family if we've done all the entries in the table - break; + if( done == table->getCount()) { + // don't call family if we've done all the entries in the table + matchParent = false; + break; + } - // pass in score from property table - score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); + // pass in score from property table + score = IOServiceObjectOrder( table, (void *) gIOProbeScoreKey); - // do family specific matching - match = where->matchPropertyTable( table, &score ); + // do family specific matching + match = where->matchPropertyTable( table, &score ); - if( !match) { + if( !match) { #if IOMATCHDEBUG - if( kIOLogMatch & getDebugFlags( table )) - LOG("%s: family specific matching fails\n", where->getName()); + if( kIOLogMatch & getDebugFlags( table )) + LOG("%s: family specific matching fails\n", where->getName()); #endif - break; - } + break; + } - if( changesOK) { - // save the score - newPri = OSNumber::withNumber( score, 32 ); - if( newPri) { - table->setObject( gIOProbeScoreKey, newPri ); - newPri->release(); + if( changesOK) { + // save the score + newPri = OSNumber::withNumber( score, 32 ); + if( newPri) { + table->setObject( gIOProbeScoreKey, newPri ); + newPri->release(); + } } - } - if( !(match = where->compareProperty( table, kIOBSDNameKey ))) - break; + if( !(match = where->compareProperty( table, kIOBSDNameKey ))) + break; - table = OSDynamicCast( OSDictionary, - table->getObject( gIOLocationMatchKey )); - if( table) { - match = false; - where = where->getProvider(); - if( where) - where = where->matchLocation( where ); - } + matchParent = false; - } while( table && where ); + obj = OSDynamicCast( OSDictionary, + table->getObject( gIOParentMatchKey )); + if( obj) { + match = false; + matchParent = true; + table = (OSDictionary *) obj; + break; + } + + table = OSDynamicCast( OSDictionary, + table->getObject( gIOLocationMatchKey )); + if( table) { + match = false; + where = where->getProvider(); + if( where) + where = where->matchLocation( where ); + } + + } while( table && where ); + + } while( matchParent && (where = where->getProvider()) ); if( kIOLogMatch & gIOKitDebug) if( where != this) - LOG("match location @ %s = %d\n", + LOG("match parent @ %s = %d\n", where->getName(), match ); return( match ); @@ -3500,7 +4160,7 @@ int IOService::errnoFromReturn( IOReturn rtn ) case kIOReturnBadArgument: return(EINVAL); case kIOReturnUnsupported: - return(EOPNOTSUPP); + return(ENOTSUP); case kIOReturnBusy: return(EBUSY); case kIOReturnNoPower: @@ -3545,7 +4205,7 @@ int IOService::errnoFromReturn( IOReturn rtn ) case kIOReturnBadMedia: case kIOReturnNoMedia: case kIOReturnUnformattedMedia: - return(EIO); // (media error) + return(ENXIO); // (media error) case kIOReturnDMAError: case kIOReturnOverrun: case kIOReturnUnderrun: @@ -3611,7 +4271,7 @@ IODeviceMemory * IOService::getDeviceMemoryWithIndex( unsigned int index ) } IOMemoryMap * IOService::mapDeviceMemoryWithIndex( unsigned int index, - IOOptionBits options = 0 ) + IOOptionBits options ) { IODeviceMemory * range; IOMemoryMap * map; @@ -3643,20 +4303,14 @@ void IOService::setDeviceMemory( OSArray * array ) IOReturn IOService::resolveInterrupt(IOService *nub, int source) { IOInterruptController *interruptController; - OSDictionary *propTable; OSArray *array; OSData *data; OSSymbol *interruptControllerName; long numSources; IOInterruptSource *interruptSources; - // Get the property table from the nub. - propTable = nub->getPropertyTable(); - if (propTable == 0) return kIOReturnNoResources; - - // Get the parents list from the property table. - array = OSDynamicCast(OSArray, - propTable->getObject(gIOInterruptControllersKey)); + // Get the parents list from the nub. + array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptControllersKey)); if (array == 0) return kIOReturnNoResources; // Allocate space for the IOInterruptSources if needed... then return early. @@ -3678,9 +4332,8 @@ IOReturn IOService::resolveInterrupt(IOService *nub, int source) interruptController = getPlatform()->lookUpInterruptController(interruptControllerName); if (interruptController == 0) return kIOReturnNoResources; - // Get the interrupt numbers from the property table. - array = OSDynamicCast(OSArray, - propTable->getObject(gIOInterruptSpecifiersKey)); + // Get the interrupt numbers from the nub. + array = OSDynamicCast(OSArray, nub->getProperty(gIOInterruptSpecifiersKey)); if (array == 0) return kIOReturnNoResources; data = OSDynamicCast(OSData, array->getObject(source)); if (data == 0) return kIOReturnNoResources; @@ -3799,10 +4452,11 @@ IOReturn IOService::causeInterrupt(int source) return interruptController->causeInterrupt(this, source); } -OSMetaClassDefineReservedUnused(IOService, 0); -OSMetaClassDefineReservedUnused(IOService, 1); -OSMetaClassDefineReservedUnused(IOService, 2); -OSMetaClassDefineReservedUnused(IOService, 3); +OSMetaClassDefineReservedUsed(IOService, 0); +OSMetaClassDefineReservedUsed(IOService, 1); +OSMetaClassDefineReservedUsed(IOService, 2); +OSMetaClassDefineReservedUsed(IOService, 3); + OSMetaClassDefineReservedUnused(IOService, 4); OSMetaClassDefineReservedUnused(IOService, 5); OSMetaClassDefineReservedUnused(IOService, 6);