X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/e5568f75972dfc723778653c11cb6b4dc825716a..c0fea4742e91338fffdcf79f86a7c1d5e2b97eb1:/iokit/Kernel/IORegistryEntry.cpp diff --git a/iokit/Kernel/IORegistryEntry.cpp b/iokit/Kernel/IORegistryEntry.cpp index d7fc62d91..4be7e3aa5 100644 --- a/iokit/Kernel/IORegistryEntry.cpp +++ b/iokit/Kernel/IORegistryEntry.cpp @@ -44,6 +44,12 @@ OSDefineMetaClassAndStructors(IORegistryEntry, OSObject) /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#define kIORegPlaneParentSuffix "ParentLinks" +#define kIORegPlaneChildSuffix "ChildLinks" +#define kIORegPlaneNameSuffix "Name" +#define kIORegPlaneLocationSuffix "Location" +#define kIORegPlaneParentSuffixLen (sizeof(kIORegPlaneParentSuffix) - 1) + static IORegistryEntry * gRegistryRoot; static OSDictionary * gIORegistryPlanes; @@ -81,9 +87,9 @@ OSDefineMetaClassAndStructors(IORegistryPlane, OSObject) static IORecursiveLock * gPropertiesLock; static SInt32 gIORegistryGenerationCount; -#define UNLOCK s_lock_done( &gIORegistryLock ) -#define RLOCK s_lock_read( &gIORegistryLock ) -#define WLOCK s_lock_write( &gIORegistryLock ); \ +#define UNLOCK lck_rw_done( &gIORegistryLock ) +#define RLOCK lck_rw_lock_shared( &gIORegistryLock ) +#define WLOCK lck_rw_lock_exclusive( &gIORegistryLock ); \ gIORegistryGenerationCount++ // make atomic @@ -102,173 +108,11 @@ static SInt32 gIORegistryGenerationCount; /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -struct s_lock_t { - decl_simple_lock_data(,interlock) /* "hardware" interlock field */ - volatile unsigned int - read_count:16, /* No. of accepted readers */ - want_upgrade:1, /* Read-to-write upgrade waiting */ - want_write:1, /* Writer is waiting, or - locked for write */ - waiting:1, /* Someone is sleeping on lock */ - can_sleep:1; /* Can attempts to lock go to sleep? */ -}; - -static struct s_lock_t gIORegistryLock; - -/* Time we loop without holding the interlock. - * The former is for when we cannot sleep, the latter - * for when our thread can go to sleep (loop less) - * we shouldn't retake the interlock at all frequently - * if we cannot go to sleep, since it interferes with - * any other processors. In particular, 100 is too small - * a number for powerpc MP systems because of cache - * coherency issues and differing lock fetch times between - * the processors - */ -static unsigned int lock_wait_time[2] = { (unsigned int)-1, 100 } ; - -static void -s_lock_init( - s_lock_t *l, - boolean_t can_sleep) -{ - (void) memset((void *) l, 0, sizeof(s_lock_t)); - - simple_lock_init(&l->interlock, 0); - l->want_write = FALSE; - l->want_upgrade = FALSE; - l->read_count = 0; - l->can_sleep = can_sleep; -} - -static void -s_lock_write( - register s_lock_t * l) -{ - register int i; - - simple_lock(&l->interlock); - - /* - * Try to acquire the want_write bit. - */ - while (l->want_write) { - - i = lock_wait_time[l->can_sleep ? 1 : 0]; - if (i != 0) { - simple_unlock(&l->interlock); - while (--i != 0 && l->want_write) - continue; - simple_lock(&l->interlock); - } - - if (l->can_sleep && l->want_write) { - l->waiting = TRUE; - thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), - THREAD_UNINT); - /* interlock relocked */ - } - } - l->want_write = TRUE; - - /* Wait for readers (and upgrades) to finish */ - - while ((l->read_count != 0) || l->want_upgrade) { - - i = lock_wait_time[l->can_sleep ? 1 : 0]; - if (i != 0) { - simple_unlock(&l->interlock); - while (--i != 0 && (l->read_count != 0 || - l->want_upgrade)) - continue; - simple_lock(&l->interlock); - } - - if (l->can_sleep && (l->read_count != 0 || l->want_upgrade)) { - l->waiting = TRUE; - thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), - THREAD_UNINT); - /* interlock relocked */ - } - } - - simple_unlock(&l->interlock); -} - -static void -s_lock_done( - register s_lock_t * l) -{ - boolean_t do_wakeup = FALSE; - - simple_lock(&l->interlock); - - if (l->read_count != 0) { - l->read_count -= 1; - } - else { - if (l->want_upgrade) { - l->want_upgrade = FALSE; - } - else { - l->want_write = FALSE; - } - } - - /* - * There is no reason to wakeup a waiting thread - * if the read-count is non-zero. Consider: - * we must be dropping a read lock - * threads are waiting only if one wants a write lock - * if there are still readers, they can't proceed - */ - if (l->waiting && (l->read_count == 0)) { - l->waiting = FALSE; - do_wakeup = TRUE; - } - - simple_unlock(&l->interlock); +lck_rw_t gIORegistryLock; +lck_grp_t *gIORegistryLockGrp; +lck_grp_attr_t *gIORegistryLockGrpAttr; +lck_attr_t *gIORegistryLockAttr; - if (do_wakeup) - thread_wakeup((event_t) l); -} - -static void -s_lock_read( - register s_lock_t * l) -{ - register int i; - - simple_lock(&l->interlock); - - while ( l->want_upgrade || ((0 == l->read_count) && l->want_write )) { - - i = lock_wait_time[l->can_sleep ? 1 : 0]; - - if (i != 0) { - simple_unlock(&l->interlock); - while (--i != 0 && - (l->want_upgrade || ((0 == l->read_count) && l->want_write ))) - continue; - simple_lock(&l->interlock); - } - - if (l->can_sleep && - (l->want_upgrade || ((0 == l->read_count) && l->want_write ))) { - l->waiting = TRUE; - thread_sleep_simple_lock((event_t) l, - simple_lock_addr(l->interlock), - THREAD_UNINT); - /* interlock relocked */ - } - } - - l->read_count += 1; - simple_unlock(&l->interlock); - -} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -278,7 +122,15 @@ IORegistryEntry * IORegistryEntry::initialize( void ) if( !gRegistryRoot) { - s_lock_init( &gIORegistryLock, true ); + + gIORegistryLockGrpAttr = lck_grp_attr_alloc_init(); + //lck_grp_attr_setstat(gIORegistryLockGrpAttr); + gIORegistryLockGrp = lck_grp_alloc_init("IORegistryLock", gIORegistryLockGrpAttr); + gIORegistryLockAttr = lck_attr_alloc_init(); + lck_attr_rw_shared_priority(gIORegistryLockAttr); + //lck_attr_setdebug(gIORegistryLockAttr); + lck_rw_init( &gIORegistryLock, gIORegistryLockGrp, gIORegistryLockAttr); + gRegistryRoot = new IORegistryEntry; gPropertiesLock = IORecursiveLockAlloc(); gIORegistryPlanes = OSDictionary::withCapacity( 1 ); @@ -327,16 +179,16 @@ const IORegistryPlane * IORegistryEntry::makePlane( const char * name ) nameKey = OSSymbol::withCString( key); - strcpy( end, "ParentLinks" ); + strcpy( end, kIORegPlaneParentSuffix ); parentKey = OSSymbol::withCString( key); - strcpy( end, "ChildLinks" ); + strcpy( end, kIORegPlaneChildSuffix ); childKey = OSSymbol::withCString( key); - strcpy( end, "Name" ); + strcpy( end, kIORegPlaneNameSuffix ); pathNameKey = OSSymbol::withCString( key); - strcpy( end, "Location" ); + strcpy( end, kIORegPlaneLocationSuffix ); pathLocationKey = OSSymbol::withCString( key); plane = new IORegistryPlane; @@ -585,14 +437,14 @@ IORegistryEntry::copyProperty( type * aKey, \ bool IORegistryEntry::serializeProperties( OSSerialize * s ) const { - bool ok; - // setProperty( getRetainCount(), 32, "__retain" ); PLOCK; - ok = getPropertyTable()->serialize( s ); + OSCollection *snapshotProperties = getPropertyTable()->copyCollection(); PUNLOCK; + bool ok = snapshotProperties->serialize( s ); + snapshotProperties->release(); return( ok ); } @@ -638,6 +490,49 @@ IORegistryEntry::getProperty( const OSSymbol * aKey) const return( obj ); } +void +IORegistryEntry::removeProperty( const OSSymbol * aKey) +{ + PLOCK; + getPropertyTable()->removeObject( aKey ); + PUNLOCK; +} + +bool +IORegistryEntry::setProperty( const OSSymbol * aKey, OSObject * anObject) +{ + bool ret = false; + + // If we are inserting a collection class and the current entry + // is attached into the registry (inPlane()) then mark the collection + // as immutable. + OSCollection *coll = OSDynamicCast(OSCollection, anObject); + bool makeImmutable = (coll && inPlane()); + + PLOCK; + if( makeImmutable ) + coll->setOptions( OSCollection::kMASK, OSCollection::kImmutable ); + + ret = getPropertyTable()->setObject( aKey, anObject ); + PUNLOCK; + + return ret; +} + +IOReturn IORegistryEntry:: +runPropertyAction(Action inAction, OSObject *target, + void *arg0, void *arg1, void *arg2, void *arg3) +{ + IOReturn res; + + // closeGate is recursive so don't worry if we already hold the lock. + PLOCK; + res = (*inAction)(target, arg0, arg1, arg2, arg3); + PUNLOCK; + + return res; +} + OSObject * IORegistryEntry::getProperty( const OSString * aKey) const { @@ -658,13 +553,6 @@ IORegistryEntry::getProperty( const char * aKey) const return( obj ); } -void -IORegistryEntry::removeProperty( const OSSymbol * aKey) -{ - PLOCK; - getPropertyTable()->removeObject( aKey ); - PUNLOCK; -} void IORegistryEntry::removeProperty( const OSString * aKey) @@ -682,17 +570,6 @@ IORegistryEntry::removeProperty( const char * aKey) tmpKey->release(); } -bool -IORegistryEntry::setProperty( const OSSymbol * aKey, OSObject * anObject) -{ - bool ret = false; - PLOCK; - ret = getPropertyTable()->setObject( aKey, anObject ); - PUNLOCK; - - return ret; -} - bool IORegistryEntry::setProperty( const OSString * aKey, OSObject * anObject) { @@ -1658,7 +1535,34 @@ bool IORegistryEntry::inPlane( const IORegistryPlane * plane ) const RLOCK; - ret = (0 != getParentSetReference( plane )); + if( plane) + ret = (0 != getParentSetReference( plane )); + else { + + // Check to see if this is in any plane. If it is in a plane + // then the registryTable will contain a key with the ParentLinks + // suffix. When we iterate over the keys looking for that suffix + ret = false; + + OSCollectionIterator *iter = + OSCollectionIterator::withCollection( registryTable()); + if( iter) { + const OSSymbol *key; + + while( (key = (OSSymbol *) iter->getNextObject()) ) { + const char *keysuffix; + + // Get a pointer to this keys suffix + keysuffix = key->getCStringNoCopy() + + key->getLength() - kIORegPlaneParentSuffixLen; + if( !strcmp(keysuffix, kIORegPlaneParentSuffix) ) { + ret = true; + break; + } + } + iter->release(); + } + } UNLOCK; @@ -1684,10 +1588,33 @@ bool IORegistryEntry::attachToParent( IORegistryEntry * parent, else needParent = true; -// ret &= parent->makeLink( this, kChildSetIndex, plane ); - UNLOCK; + PLOCK; + + // Mark any collections in the property list as immutable + OSDictionary *ptable = getPropertyTable(); + OSCollectionIterator *iter = + OSCollectionIterator::withCollection( ptable ); + if( iter) { + const OSSymbol *key; + + while( (key = (OSSymbol *) iter->getNextObject( ))) { + // Is object for key a collection? + OSCollection *coll = + OSDynamicCast( OSCollection, ptable->getObject( key )); + + if( coll) { + // Yup so mark it as immutable + coll->setOptions( OSCollection::kMASK, + OSCollection::kImmutable ); + } + } + iter->release(); + } + + PUNLOCK; + if( needParent) ret &= parent->attachToChild( this, plane ); @@ -2075,8 +2002,8 @@ OSMetaClassDefineReservedUsed(IORegistryEntry, 1); OSMetaClassDefineReservedUsed(IORegistryEntry, 2); OSMetaClassDefineReservedUsed(IORegistryEntry, 3); OSMetaClassDefineReservedUsed(IORegistryEntry, 4); +OSMetaClassDefineReservedUsed(IORegistryEntry, 5); -OSMetaClassDefineReservedUnused(IORegistryEntry, 5); OSMetaClassDefineReservedUnused(IORegistryEntry, 6); OSMetaClassDefineReservedUnused(IORegistryEntry, 7); OSMetaClassDefineReservedUnused(IORegistryEntry, 8);