/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+#define kIORegPlaneParentSuffix "ParentLinks"
+#define kIORegPlaneChildSuffix "ChildLinks"
+#define kIORegPlaneNameSuffix "Name"
+#define kIORegPlaneLocationSuffix "Location"
+#define kIORegPlaneParentSuffixLen (sizeof(kIORegPlaneParentSuffix) - 1)
+
static IORegistryEntry * gRegistryRoot;
static OSDictionary * gIORegistryPlanes;
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
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
-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);
-
-}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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 );
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;
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 );
}
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
{
return( obj );
}
-void
-IORegistryEntry::removeProperty( const OSSymbol * aKey)
-{
- PLOCK;
- getPropertyTable()->removeObject( aKey );
- PUNLOCK;
-}
void
IORegistryEntry::removeProperty( const OSString * 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)
{
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;
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 );
OSMetaClassDefineReservedUsed(IORegistryEntry, 2);
OSMetaClassDefineReservedUsed(IORegistryEntry, 3);
OSMetaClassDefineReservedUsed(IORegistryEntry, 4);
+OSMetaClassDefineReservedUsed(IORegistryEntry, 5);
-OSMetaClassDefineReservedUnused(IORegistryEntry, 5);
OSMetaClassDefineReservedUnused(IORegistryEntry, 6);
OSMetaClassDefineReservedUnused(IORegistryEntry, 7);
OSMetaClassDefineReservedUnused(IORegistryEntry, 8);