]> git.saurik.com Git - apple/xnu.git/blobdiff - libkern/c++/OSMetaClass.cpp
xnu-4570.1.46.tar.gz
[apple/xnu.git] / libkern / c++ / OSMetaClass.cpp
index 6aa1b1e47903ead2f58a52a5e8e1d85963ceb1b3..3d7c2f6e44ab396d48646f2a90bb09bcffbcf065 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
 #include <libkern/OSReturn.h>
 
 #include <libkern/c++/OSMetaClass.h>
-
 #include <libkern/c++/OSObject.h>
+#include <libkern/c++/OSKext.h>
+
 #include <libkern/c++/OSCollectionIterator.h>
 #include <libkern/c++/OSDictionary.h>
 #include <libkern/c++/OSArray.h>   
-#include <libkern/c++/OSSet.h>  
+#include <libkern/c++/OSSet.h> 
 #include <libkern/c++/OSSymbol.h>
 #include <libkern/c++/OSNumber.h>
 #include <libkern/c++/OSSerialize.h>
+
 #include <libkern/c++/OSLib.h>
 #include <libkern/OSAtomic.h>
 
+#include <IOKit/IOLib.h>
+
+#include <IOKit/IOKitDebug.h>
+
+
 __BEGIN_DECLS
 
 #include <sys/systm.h>
 #include <mach/mach_types.h>
-#include <kern/lock.h>
+#include <kern/locks.h>
 #include <kern/clock.h>
 #include <kern/thread_call.h>
 #include <kern/host.h>
-#include <mach/kmod.h>
 #include <mach/mach_interface.h>
 
-extern void OSRuntimeUnloadCPP(kmod_info_t *ki, void *);
-
-#if OSALLOCDEBUG
-extern int debug_container_malloc_size;
-#define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
-#else
-#define ACCUMSIZE(s)
-#endif /* OSALLOCDEBUG */
-
+#if PRAGMA_MARK
+#pragma mark Macros
+#endif /* PRAGMA_MARK */
+/*********************************************************************
+* Macros
+*********************************************************************/
 __END_DECLS
 
+#if PRAGMA_MARK
+#pragma mark Internal constants & data structs
+#endif /* PRAGMA_MARK */
+/*********************************************************************
+* Internal constants & data structs
+*********************************************************************/
+OSKextLogSpec kOSMetaClassLogSpec =
+    kOSKextLogErrorLevel |
+    kOSKextLogLoadFlag |
+    kOSKextLogKextBookkeepingFlag;
+
 static enum {
     kCompletedBootstrap = 0,
-    kNoDictionaries = 1,
+    kNoDictionaries     = 1,
     kMakingDictionaries = 2
 } sBootstrapState = kNoDictionaries;
 
-static const int kClassCapacityIncrement = 40;
-static const int kKModCapacityIncrement = 10;
-static OSDictionary *sAllClassesDict, *sKModClassesDict, *sSortedByClassesDict;
+static const int      kClassCapacityIncrement = 40;
+static const int      kKModCapacityIncrement  = 10;
+static OSDictionary * sAllClassesDict;
+static unsigned int   sDeepestClass;
+IOLock              * sAllClassesLock = NULL;
+IOLock              * sInstancesLock  = NULL;
 
-static mutex_t *loadLock;
+/*
+ * While loading a kext and running all its constructors to register
+ * all OSMetaClass classes, the classes are queued up here. Only one
+ * kext can be in flight at a time, guarded by sStalledClassesLock
+ */
 static struct StalledData {
-    const char *kmodName;
-    OSReturn result;
-    unsigned int capacity;
-    unsigned int count;
-    OSMetaClass **classes;
-} *sStalled;
+    const char   * kextIdentifier;
+    OSReturn       result;
+    unsigned int   capacity;
+    unsigned int   count;
+    OSMetaClass ** classes;
+} * sStalled;
+IOLock * sStalledClassesLock = NULL;
+
+struct ExpansionData {
+    OSOrderedSet    * instances;
+    OSKext          * kext;
+    uint32_t          retain;
+#if IOTRACKING
+    IOTrackingQueue * tracking;
+#endif
+};
 
-static unsigned int sConsiderUnloadDelay = 60; /* secs */
 
-static const char OSMetaClassBasePanicMsg[] =
-    "OSMetaClassBase::_RESERVEDOSMetaClassBase%d called\n";
+#if PRAGMA_MARK
+#pragma mark OSMetaClassBase
+#endif /* PRAGMA_MARK */
+/*********************************************************************
+* OSMetaClassBase.
+*********************************************************************/
 
+#if APPLE_KEXT_VTABLE_PADDING
+/*********************************************************************
+* Reserved vtable functions.
+*********************************************************************/
 #if SLOT_USED
 void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
-    { panic(OSMetaClassBasePanicMsg, 0); }
+    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0); }
 void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
-    { panic(OSMetaClassBasePanicMsg, 1); }
+    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1); }
 void OSMetaClassBase::_RESERVEDOSMetaClassBase2()
-    { panic(OSMetaClassBasePanicMsg, 2); }
+    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 2); }
 #endif /* SLOT_USED */
 
 // As these slots are used move them up inside the #if above
 void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
-    { panic(OSMetaClassBasePanicMsg, 3); }
+    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3); }
 void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
-    { panic(OSMetaClassBasePanicMsg, 4); }
+    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4); }
 void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
-    { panic(OSMetaClassBasePanicMsg, 5); }
+    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); }
 void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
-    { panic(OSMetaClassBasePanicMsg, 6); }
-    
-/*
- * These used to be inline in the header but gcc didn't believe us
- * Now we MUST pull the inline out at least until the compiler is
- * repaired.
- */
-// Helper inlines for runtime type preprocessor macros
-OSMetaClassBase *OSMetaClassBase::
-safeMetaCast(const OSMetaClassBase *me, const OSMetaClass *toType)
-    { return (me)? me->metaCast(toType) : 0; }
+    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 6); }
+#endif
+
+/*********************************************************************
+* These used to be inline in the header but gcc didn't believe us
+* Now we MUST pull the inline out at least until the compiler is
+* repaired.
+*
+* Helper inlines for runtime type preprocessor macros
+*********************************************************************/
+
+/*********************************************************************
+*********************************************************************/
+OSMetaClassBase *
+OSMetaClassBase::safeMetaCast(
+    const OSMetaClassBase * me,
+    const OSMetaClass     * toType)
+{
+    return (me)? me->metaCast(toType) : 0;
+}
 
-bool OSMetaClassBase::
-checkTypeInst(const OSMetaClassBase *inst, const OSMetaClassBase *typeinst)
+/*********************************************************************
+*********************************************************************/
+bool
+OSMetaClassBase::checkTypeInst(
+    const OSMetaClassBase * inst,
+    const OSMetaClassBase * typeinst)
 {
-    const OSMetaClass *toType = OSTypeIDInst(typeinst);
+    const OSMetaClass * toType = OSTypeIDInst(typeinst);
     return typeinst && inst && (0 != inst->metaCast(toType));
 }
 
+/*********************************************************************
+*********************************************************************/
+void OSMetaClassBase::
+initialize()
+{
+    sAllClassesLock = IOLockAlloc();
+    sStalledClassesLock = IOLockAlloc();
+    sInstancesLock = IOLockAlloc();
+}
 
-// If you need this slot you had better setup an IOCTL style interface.
-// 'Cause the whole kernel world depends on OSMetaClassBase and YOU
-// CANT change the VTABLE size ever.
-void OSMetaClassBase::_RESERVEDOSMetaClassBase7()
-    { panic(OSMetaClassBasePanicMsg, 7); }
-
+#if APPLE_KEXT_VTABLE_PADDING
+/*********************************************************************
+* If you need this slot you had better setup an IOCTL style interface.
+* 'Cause the whole kernel world depends on OSMetaClassBase and YOU
+* CANT change the VTABLE size ever.
+*********************************************************************/
+void
+OSMetaClassBase::_RESERVEDOSMetaClassBase7()
+{ panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); }
+#endif
+
+/*********************************************************************
+*********************************************************************/
 OSMetaClassBase::OSMetaClassBase()
 {
 }
 
+/*********************************************************************
+*********************************************************************/
 OSMetaClassBase::~OSMetaClassBase()
 {
-    void **thisVTable;
+    void ** thisVTable;
 
     thisVTable = (void **) this;
     *thisVTable = (void *) -1UL;
 }
 
-bool OSMetaClassBase::isEqualTo(const OSMetaClassBase *anObj) const
+/*********************************************************************
+*********************************************************************/
+bool
+OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const
 {
     return this == anObj;
 }
 
-OSMetaClassBase *OSMetaClassBase::metaCast(const OSMetaClass *toMeta) const
+/*********************************************************************
+*********************************************************************/
+OSMetaClassBase *
+OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const
 {
     return toMeta->checkMetaCast(this);
 }
 
-OSMetaClassBase *OSMetaClassBase::metaCast(const OSSymbol *toMetaSymb) const
+/*********************************************************************
+*********************************************************************/
+OSMetaClassBase *
+OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const
 {
     return OSMetaClass::checkMetaCastWithName(toMetaSymb, this);
 }
 
-OSMetaClassBase *OSMetaClassBase::metaCast(const OSString *toMetaStr) const
+/*********************************************************************
+*********************************************************************/
+OSMetaClassBase *
+OSMetaClassBase::metaCast(const OSString * toMetaStr) const
 {
-    const OSSymbol *tempSymb = OSSymbol::withString(toMetaStr);
-    OSMetaClassBase *ret = 0;
+    const OSSymbol  * tempSymb = OSSymbol::withString(toMetaStr);
+    OSMetaClassBase * ret = 0;
     if (tempSymb) {
         ret = metaCast(tempSymb);
         tempSymb->release();
@@ -171,10 +252,13 @@ OSMetaClassBase *OSMetaClassBase::metaCast(const OSString *toMetaStr) const
     return ret;
 }
 
-OSMetaClassBase *OSMetaClassBase::metaCast(const char *toMetaCStr) const
+/*********************************************************************
+*********************************************************************/
+OSMetaClassBase *
+OSMetaClassBase::metaCast(const char * toMetaCStr) const
 {
-    const OSSymbol *tempSymb = OSSymbol::withCString(toMetaCStr);
-    OSMetaClassBase *ret = 0;
+    const OSSymbol  * tempSymb = OSSymbol::withCString(toMetaCStr);
+    OSMetaClassBase * ret = 0;
     if (tempSymb) {
         ret = metaCast(tempSymb);
         tempSymb->release();
@@ -182,16 +266,22 @@ OSMetaClassBase *OSMetaClassBase::metaCast(const char *toMetaCStr) const
     return ret;
 }
 
+#if PRAGMA_MARK
+#pragma mark OSMetaClassMeta
+#endif /* PRAGMA_MARK */
+/*********************************************************************
+* OSMetaClassMeta - the bootstrap metaclass of OSMetaClass
+*********************************************************************/
 class OSMetaClassMeta : public OSMetaClass 
 {
 public:
     OSMetaClassMeta();
-    OSObject *alloc() const;
+    OSObject * alloc() const;
 };
 OSMetaClassMeta::OSMetaClassMeta()
     : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass))
     { }
-OSObject *OSMetaClassMeta::alloc() const { return 0; }
+OSObject * OSMetaClassMeta::alloc() const { return 0; }
 
 static OSMetaClassMeta sOSMetaClassMeta;
 
@@ -199,659 +289,983 @@ const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta;
 const OSMetaClass * OSMetaClass::getMetaClass() const
     { return &sOSMetaClassMeta; }
 
-static const char OSMetaClassPanicMsg[] =
-    "OSMetaClass::_RESERVEDOSMetaClass%d called\n";
-
+#if PRAGMA_MARK
+#pragma mark OSMetaClass
+#endif /* PRAGMA_MARK */
+/*********************************************************************
+* OSMetaClass
+*********************************************************************/
+
+#if APPLE_KEXT_VTABLE_PADDING
+/*********************************************************************
+* Reserved functions.
+*********************************************************************/
 void OSMetaClass::_RESERVEDOSMetaClass0()
-    { panic(OSMetaClassPanicMsg, 0); }
+    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0); }
 void OSMetaClass::_RESERVEDOSMetaClass1()
-    { panic(OSMetaClassPanicMsg, 1); }
+    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1); }
 void OSMetaClass::_RESERVEDOSMetaClass2()
-    { panic(OSMetaClassPanicMsg, 2); }
+    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2); }
 void OSMetaClass::_RESERVEDOSMetaClass3()
-    { panic(OSMetaClassPanicMsg, 3); }
+    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3); }
 void OSMetaClass::_RESERVEDOSMetaClass4()
-    { panic(OSMetaClassPanicMsg, 4); }
+    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4); }
 void OSMetaClass::_RESERVEDOSMetaClass5()
-    { panic(OSMetaClassPanicMsg, 5); }
+    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5); }
 void OSMetaClass::_RESERVEDOSMetaClass6()
-    { panic(OSMetaClassPanicMsg, 6); }
+    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); }
 void OSMetaClass::_RESERVEDOSMetaClass7()
-    { panic(OSMetaClassPanicMsg, 7); }
-
-void OSMetaClass::logError(OSReturn result)
+    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); }
+#endif
+
+/*********************************************************************
+*********************************************************************/
+static void
+OSMetaClassLogErrorForKext(
+    OSReturn   error,
+    OSKext   * aKext)
 {
-    const char *msg;
+    const char * message = NULL;
 
-    switch (result) {
-    case kOSMetaClassNoInit:
-       msg="OSMetaClass::preModLoad wasn't called, runtime internal error";
-       break;
+    switch (error) {
+    case kOSReturnSuccess:
+        return;
+    case kOSMetaClassNoInit:  // xxx - never returned; logged at fail site
+        message = "OSMetaClass: preModLoad() wasn't called (runtime internal error).";
+        break;
     case kOSMetaClassNoDicts:
-       msg="Allocation failure for Metaclass internal dictionaries"; break;
+        message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries.";
+        break;
     case kOSMetaClassNoKModSet:
-       msg="Allocation failure for internal kmodule set"; break;
+        message = "OSMetaClass: Allocation failure for internal kext recording set/set missing.";
+        break;
     case kOSMetaClassNoInsKModSet:
-       msg="Can't insert the KMod set into the module dictionary"; break;
+        message = "OSMetaClass: Failed to record class in kext.";
+        break;
     case kOSMetaClassDuplicateClass:
-       msg="Duplicate class"; break;
-    case kOSMetaClassNoSuper:
-       msg="Can't associate a class with its super class"; break;
-    case kOSMetaClassInstNoSuper:
-       msg="Instance construction, unknown super class."; break;
-    default:
+        message = "OSMetaClass: Duplicate class encountered.";
+        break;
+    case kOSMetaClassNoSuper:  // xxx - never returned
+        message = "OSMetaClass: Can't associate a class with its superclass.";
+        break;
+    case kOSMetaClassInstNoSuper:  // xxx - never returned
+        message = "OSMetaClass: Instance construction error; unknown superclass.";
+        break;
+    case kOSMetaClassNoKext:
+        message = "OSMetaClass: Kext not found for metaclass.";
+        break;
     case kOSMetaClassInternal:
-       msg="runtime internal error"; break;
-    case kOSReturnSuccess:
-       return;
+    default:
+        message = "OSMetaClass: Runtime internal error.";
+        break;
     }
-    printf("%s\n", msg);
+
+    if (message) {
+        OSKextLog(aKext, kOSMetaClassLogSpec, "%s", message);
+    }
+    return;
 }
 
-OSMetaClass::OSMetaClass(const char *inClassName,
-                         const OSMetaClass *inSuperClass,
-                         unsigned int inClassSize)
+void
+OSMetaClass::logError(OSReturn error)
+{
+    OSMetaClassLogErrorForKext(error, NULL);
+}
+
+/*********************************************************************
+* The core constructor for a MetaClass (defined with this name always
+* but within the scope of its represented class).
+*
+* MetaClass constructors are invoked in OSRuntimeInitializeCPP(),
+* in between calls to OSMetaClass::preModLoad(), which sets up for
+* registration, and OSMetaClass::postModLoad(), which actually
+* records all the class/kext relationships of the new MetaClasses.
+*********************************************************************/
+OSMetaClass::OSMetaClass(
+    const char        * inClassName,
+    const OSMetaClass * inSuperClass,
+    unsigned int        inClassSize)
 {
     instanceCount = 0;
     classSize = inClassSize;
     superClassLink = inSuperClass;
 
-    className = (const OSSymbol *) inClassName;
-
+    reserved = IONew(ExpansionData, 1);
+    bzero(reserved, sizeof(ExpansionData));
+#if IOTRACKING
+    uint32_t numSiteQs = 0;
+    if ((this == &OSSymbol    ::gMetaClass)
+     || (this == &OSString    ::gMetaClass)
+     || (this == &OSNumber    ::gMetaClass)
+     || (this == &OSString    ::gMetaClass)
+     || (this == &OSData      ::gMetaClass)
+     || (this == &OSDictionary::gMetaClass)
+     || (this == &OSArray     ::gMetaClass)
+     || (this == &OSSet       ::gMetaClass))                   numSiteQs = 27;
+
+    reserved->tracking = IOTrackingQueueAlloc(inClassName, (uintptr_t) this,
+                                             inClassSize, 0, kIOTrackingQueueTypeAlloc,
+                                             numSiteQs);
+#endif
+
+   /* Hack alert: We are just casting inClassName and storing it in
+    * an OSString * instance variable. This may be because you can't
+    * create C++ objects in static constructors, but I really don't know!
+    */
+    className = (const OSSymbol *)inClassName;
+
+    // sStalledClassesLock taken in preModLoad
     if (!sStalled) {
-       printf("OSMetaClass::preModLoad wasn't called for %s, "
-              "runtime internal error\n", inClassName);
+       /* There's no way we can look up the kext here, unfortunately.
+        */
+        OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
+            "OSMetaClass: preModLoad() wasn't called for class %s "
+            "(runtime internal error).",
+            inClassName);
     } else if (!sStalled->result) {
-       // Grow stalled array if neccessary
-       if (sStalled->count >= sStalled->capacity) {
-           OSMetaClass **oldStalled = sStalled->classes;
-           int oldSize = sStalled->capacity * sizeof(OSMetaClass *);
-           int newSize = oldSize
-                       + kKModCapacityIncrement * sizeof(OSMetaClass *);
-
-           sStalled->classes = (OSMetaClass **) kalloc(newSize);
-           if (!sStalled->classes) {
-               sStalled->classes = oldStalled;
-               sStalled->result = kOSMetaClassNoTempData;
-               return;
-           }
+        // Grow stalled array if neccessary
+        if (sStalled->count >= sStalled->capacity) {
+            OSMetaClass **oldStalled = sStalled->classes;
+            int oldSize = sStalled->capacity * sizeof(OSMetaClass *);
+            int newSize = oldSize
+                + kKModCapacityIncrement * sizeof(OSMetaClass *);
+
+            sStalled->classes = (OSMetaClass **)kalloc_tag(newSize, VM_KERN_MEMORY_OSKEXT);
+            if (!sStalled->classes) {
+                sStalled->classes = oldStalled;
+                sStalled->result = kOSMetaClassNoTempData;
+                return;
+            }
 
-           sStalled->capacity += kKModCapacityIncrement;
-           memmove(sStalled->classes, oldStalled, oldSize);
-           kfree((vm_offset_t)oldStalled, oldSize);
-           ACCUMSIZE(newSize - oldSize);
-       }
+            sStalled->capacity += kKModCapacityIncrement;
+            memmove(sStalled->classes, oldStalled, oldSize);
+            kfree(oldStalled, oldSize);
+            OSMETA_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize));
+        }
 
-       sStalled->classes[sStalled->count++] = this;
+        sStalled->classes[sStalled->count++] = this;
     }
 }
 
+/*********************************************************************
+*********************************************************************/
 OSMetaClass::~OSMetaClass()
 {
-    do {
-       OSCollectionIterator *iter;
-
-       if (sAllClassesDict) {
-           sAllClassesDict->removeObject(className);
-           className->release();
-       }
-
-       iter = OSCollectionIterator::withCollection(sKModClassesDict);
-       if (!iter)
-           break;
-
-       OSSymbol *iterKey;
-       while ( (iterKey = (OSSymbol *) iter->getNextObject()) ) {
-           OSSet *kmodClassSet;
-           kmodClassSet = (OSSet *) sKModClassesDict->getObject(iterKey);
-           if (kmodClassSet && kmodClassSet->containsObject(this)) {
-               kmodClassSet->removeObject(this);
-               break;
-           }
-       }
-       iter->release();
-    } while (false);
+    OSKext * myKext = reserved ? reserved->kext : 0; // do not release
+
+   /* Hack alert: 'className' is a C string during early C++ init, and
+    * is converted to a real OSSymbol only when we record the OSKext in
+    * OSMetaClass::postModLoad(). So only do this bit if we have an OSKext.
+    * We can't safely cast or check 'className'.
+    *
+    * Also, release className *after* calling into the kext,
+    * as removeClass() may access className.
+    */
+    IOLockLock(sAllClassesLock);
+    if (sAllClassesDict) {
+        if (myKext) {
+            sAllClassesDict->removeObject(className);
+        } else {
+            sAllClassesDict->removeObject((char *)className);
+        }
+    }
+    IOLockUnlock(sAllClassesLock);
+    
+    if (myKext) {
+        if (myKext->removeClass(this) != kOSReturnSuccess) {
+            // xxx - what can we do?
+        }
+        className->release();
+    }
 
+    // sStalledClassesLock taken in preModLoad
     if (sStalled) {
-       unsigned int i;
-
-       // First pass find class in stalled list
-       for (i = 0; i < sStalled->count; i++)
-           if (this == sStalled->classes[i])
-               break;
-
-       if (i < sStalled->count) {
-           sStalled->count--;
-           if (i < sStalled->count)
-               memmove(&sStalled->classes[i], &sStalled->classes[i+1],
-                           (sStalled->count - i) * sizeof(OSMetaClass *));
-       }
+        unsigned int i;
+        
+       /* First pass find class in stalled list. If we find it that means
+        * we started C++ init with constructors but now we're tearing down
+        * because of some failure.
+        */
+        for (i = 0; i < sStalled->count; i++) {
+            if (this == sStalled->classes[i]) {
+                break;
+            }
+        }
+        
+       /* Remove this metaclass from the stalled list so postModLoad() doesn't
+        * try to register it.
+        */
+        if (i < sStalled->count) {
+            sStalled->count--;
+            if (i < sStalled->count) {
+                memmove(&sStalled->classes[i], &sStalled->classes[i+1],
+                    (sStalled->count - i) * sizeof(OSMetaClass *));
+            }
+        }
     }
+#if IOTRACKING
+    IOTrackingQueueFree(reserved->tracking);
+#endif
+    IODelete(reserved, ExpansionData, 1);
 }
 
-void *OSMetaClass::operator new(size_t size) { return 0; }
+/*********************************************************************
+* Empty overrides.
+*********************************************************************/
 void OSMetaClass::retain() const { }
 void OSMetaClass::release() const { }
-void OSMetaClass::release(int when) const { }
-void OSMetaClass::taggedRetain(const void *tag) const { }
-void OSMetaClass::taggedRelease(const void *tag) const { }
-void OSMetaClass::taggedRelease(const void *tag, const int when) const { }
+void OSMetaClass::release(__unused int when) const { }
+void OSMetaClass::taggedRetain(__unused const void * tag) const { }
+void OSMetaClass::taggedRelease(__unused const void * tag) const { }
+void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { }
 int  OSMetaClass::getRetainCount() const { return 0; }
 
-const char *OSMetaClass::getClassName() const
+/*********************************************************************
+*********************************************************************/
+const char *
+OSMetaClass::getClassName() const
 {
+    if (!className) return NULL;
     return className->getCStringNoCopy();
 }
-
-unsigned int OSMetaClass::getClassSize() const
+/*********************************************************************
+*********************************************************************/
+const OSSymbol *
+OSMetaClass::getClassNameSymbol() const
+{
+    return className;
+}
+/*********************************************************************
+*********************************************************************/
+unsigned int
+OSMetaClass::getClassSize() const
 {
     return classSize;
 }
 
-void *OSMetaClass::preModLoad(const char *kmodName)
+/*********************************************************************
+*********************************************************************/
+void *
+OSMetaClass::preModLoad(const char * kextIdentifier)
 {
-    if (!loadLock) {
-        loadLock = mutex_alloc(0);
-       mutex_lock(loadLock);
-    }
-    else
-       mutex_lock(loadLock);
+    IOLockLock(sStalledClassesLock);
 
-    sStalled = (StalledData *) kalloc(sizeof(*sStalled));
+    assert (sStalled == NULL);
+    sStalled = (StalledData *)kalloc_tag(sizeof(* sStalled), VM_KERN_MEMORY_OSKEXT);
     if (sStalled) {
-       sStalled->classes  = (OSMetaClass **)
-                       kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
-       if (!sStalled->classes) {
-           kfree((vm_offset_t) sStalled, sizeof(*sStalled));
-           return 0;
-       }
-       ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + sizeof(*sStalled));
+        sStalled->classes = (OSMetaClass **)
+            kalloc_tag(kKModCapacityIncrement * sizeof(OSMetaClass *), VM_KERN_MEMORY_OSKEXT);
+        if (!sStalled->classes) {
+            kfree(sStalled, sizeof(*sStalled));
+            return 0;
+        }
+        OSMETA_ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
+            sizeof(*sStalled));
 
         sStalled->result   = kOSReturnSuccess;
-       sStalled->capacity = kKModCapacityIncrement;
-       sStalled->count    = 0;
-       sStalled->kmodName = kmodName;
-       bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *));
+        sStalled->capacity = kKModCapacityIncrement;
+        sStalled->count    = 0;
+        sStalled->kextIdentifier = kextIdentifier;
+        bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *));
     }
 
+    // keep sStalledClassesLock locked until postModLoad
+    
     return sStalled;
 }
 
-bool OSMetaClass::checkModLoad(void *loadHandle)
+/*********************************************************************
+*********************************************************************/
+bool
+OSMetaClass::checkModLoad(void * loadHandle)
 {
-    return sStalled && loadHandle == sStalled
-       && sStalled->result == kOSReturnSuccess;
+    return sStalled && loadHandle == sStalled &&
+        sStalled->result == kOSReturnSuccess;
 }
 
-OSReturn OSMetaClass::postModLoad(void *loadHandle)
+/*********************************************************************
+*********************************************************************/
+OSReturn
+OSMetaClass::postModLoad(void * loadHandle)
 {
-    OSReturn result = kOSReturnSuccess;
-    OSSet *kmodSet = 0;
-    OSSymbol *myname = 0;
+    OSReturn         result     = kOSReturnSuccess;
+    OSSymbol       * myKextName = 0;  // must release
+    OSKext         * myKext     = 0;  // must release
 
     if (!sStalled || loadHandle != sStalled) {
-       logError(kOSMetaClassInternal);
-       return kOSMetaClassInternal;
-    }
-
-    if (sStalled->result)
-       result = sStalled->result;
-    else switch (sBootstrapState) {
-    case kNoDictionaries:
-       sBootstrapState = kMakingDictionaries;
-       // No break; fall through
-
-    case kMakingDictionaries:
-       sKModClassesDict = OSDictionary::withCapacity(kKModCapacityIncrement);
-       sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
-       sSortedByClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
-       if (!sAllClassesDict || !sKModClassesDict || !sSortedByClassesDict) {
-           result = kOSMetaClassNoDicts;
-           break;
-       }
-       // No break; fall through
-
-    case kCompletedBootstrap:
-    {
-        unsigned int i;
-        myname = OSSymbol::withCStringNoCopy(sStalled->kmodName);
-
-       if (!sStalled->count)
-           break;      // Nothing to do so just get out
-
-       // First pass checking classes aren't already loaded
-       for (i = 0; i < sStalled->count; i++) {
-           OSMetaClass *me = sStalled->classes[i];
-
-           if (0 != sAllClassesDict->getObject((const char *) me->className)) {
-                printf("Class \"%s\" is duplicate\n", (const char *) me->className);
-                result = kOSMetaClassDuplicateClass;
+        result = kOSMetaClassInternal;
+        goto finish;
+    }
+    
+    if (sStalled->result) {
+        result = sStalled->result;
+    } else switch (sBootstrapState) {
+
+        case kNoDictionaries:
+            sBootstrapState = kMakingDictionaries;
+            // No break; fall through
+           [[clang::fallthrough]];
+            
+        case kMakingDictionaries:
+            sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
+            if (!sAllClassesDict) {
+                result = kOSMetaClassNoDicts;
+                break;
+            }
+            sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
+
+           // No break; fall through
+           [[clang::fallthrough]];
+
+        case kCompletedBootstrap:
+        {
+            unsigned int i;
+            myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy(
+                sStalled->kextIdentifier));
+            
+            if (!sStalled->count) {
+                break;  // Nothing to do so just get out
+            }
+            
+            myKext = OSKext::lookupKextWithIdentifier(myKextName);
+            if (!myKext) {
+                result = kOSMetaClassNoKext;
+
+               /* Log this error here so we can include the kext name.
+                */
+                OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
+                    "OSMetaClass: Can't record classes for kext %s - kext not found.",
+                    sStalled->kextIdentifier);
+                break;
+            }
+            
+           /* First pass checking classes aren't already loaded. If any already
+            * exist, we don't register any, and so we don't technically have
+            * to do any C++ teardown.
+            *
+            * Hack alert: me->className has been a C string until now.
+            * We only release the OSSymbol if we store the kext.
+            */
+            IOLockLock(sAllClassesLock);
+            for (i = 0; i < sStalled->count; i++) {
+                const OSMetaClass * me = sStalled->classes[i];
+                OSMetaClass * orig = OSDynamicCast(OSMetaClass,
+                    sAllClassesDict->getObject((const char *)me->className));
+                
+                if (orig) {
+
+                   /* Log this error here so we can include the class name.
+                    * xxx - we should look up the other kext that defines the class
+                    */
+#if CONFIG_EMBEDDED
+                    panic(
+#else
+                    OSKextLog(myKext, kOSMetaClassLogSpec,
+#endif /* CONFIG_EMBEDDED */
+                        "OSMetaClass: Kext %s class %s is a duplicate;"
+                        "kext %s already has a class by that name.",
+                         sStalled->kextIdentifier, (const char *)me->className,
+                        ((OSKext *)orig->reserved->kext)->getIdentifierCString());
+                    result = kOSMetaClassDuplicateClass;
+                    break;
+                }
+               unsigned int depth = 1;
+               while ((me = me->superClassLink)) depth++;
+               if (depth > sDeepestClass) sDeepestClass = depth;
+            }
+            IOLockUnlock(sAllClassesLock);
+            
+           /* Bail if we didn't go through the entire list of new classes
+            * (if we hit a duplicate).
+            */
+            if (i != sStalled->count) {
                 break;
             }
-       }
-        if (i != sStalled->count)
-           break;
-
-       kmodSet = OSSet::withCapacity(sStalled->count);
-       if (!kmodSet) {
-           result = kOSMetaClassNoKModSet;
-           break;
-       }
-
-       if (!sKModClassesDict->setObject(myname, kmodSet)) {
-           result = kOSMetaClassNoInsKModSet;
-           break;
-       }
-
-       // Second pass symbolling strings and inserting classes in dictionary
-       for (i = 0; i < sStalled->count; i++) {
-           OSMetaClass *me = sStalled->classes[i];
-           me->className = 
-                OSSymbol::withCStringNoCopy((const char *) me->className);
 
-           sAllClassesDict->setObject(me->className, me);
-           kmodSet->setObject(me);
-           sSortedByClassesDict->setObject((const OSSymbol *)me, myname);
-       }
-       sBootstrapState = kCompletedBootstrap;
-       break;
+            // Second pass symbolling strings and inserting classes in dictionary
+            IOLockLock(sAllClassesLock);
+            for (i = 0; i < sStalled->count; i++) {
+                OSMetaClass * me = sStalled->classes[i];
+                
+               /* Hack alert: me->className has been a C string until now.
+                * We only release the OSSymbol in ~OSMetaClass()
+                * if we set the reference to the kext.
+                */
+                me->className = 
+                    OSSymbol::withCStringNoCopy((const char *)me->className);
+
+                // xxx - I suppose if these fail we're going to panic soon....
+                sAllClassesDict->setObject(me->className, me);
+                
+               /* Do not retain the kext object here.
+                */
+                me->reserved->kext = myKext;
+                if (myKext) {
+                    result = myKext->addClass(me, sStalled->count);
+                    if (result != kOSReturnSuccess) {
+                       /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */
+                        break;
+                    }
+                }
+            }
+            IOLockUnlock(sAllClassesLock);
+            sBootstrapState = kCompletedBootstrap;
+            break;
+        }
+            
+        default:
+            result = kOSMetaClassInternal;
+            break;
     }
-
-    default:
-       result = kOSMetaClassInternal;
-       break;
+    
+finish:
+   /* Don't call logError() for success or the conditions logged above
+    * or by called function.
+    */
+    if (result != kOSReturnSuccess &&
+        result != kOSMetaClassNoInsKModSet &&
+        result != kOSMetaClassDuplicateClass &&
+        result != kOSMetaClassNoKext) {
+
+        OSMetaClassLogErrorForKext(result, myKext);
     }
 
-    if (kmodSet)
-       kmodSet->release();
-
-       if (myname)
-       myname->release();
+    OSSafeReleaseNULL(myKextName);
+    OSSafeReleaseNULL(myKext);
 
     if (sStalled) {
-       ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *)
-                    + sizeof(*sStalled)));
-       kfree((vm_offset_t) sStalled->classes,
-             sStalled->capacity * sizeof(OSMetaClass *));
-       kfree((vm_offset_t) sStalled, sizeof(*sStalled));
-       sStalled = 0;
+        OSMETA_ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
+            sizeof(*sStalled)));
+        kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *));
+        kfree(sStalled, sizeof(*sStalled));
+        sStalled = 0;
     }
+    
+    IOLockUnlock(sStalledClassesLock);
 
-    logError(result);
-    mutex_unlock(loadLock);
     return result;
 }
 
 
-void OSMetaClass::instanceConstructed() const
+/*********************************************************************
+*********************************************************************/
+void
+OSMetaClass::instanceConstructed() const
 {
-    // if ((0 == OSIncrementAtomic((SInt32 *)&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
-    if ((0 == OSIncrementAtomic((SInt32 *) &instanceCount)) && superClassLink)
-       superClassLink->instanceConstructed();
+    // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
+    if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) {
+        superClassLink->instanceConstructed();
+    }
 }
 
-void OSMetaClass::instanceDestructed() const
+/*********************************************************************
+*********************************************************************/
+void
+OSMetaClass::instanceDestructed() const
 {
-    if ((1 == OSDecrementAtomic((SInt32 *) &instanceCount)) && superClassLink)
-       superClassLink->instanceDestructed();
+    if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) {
+        superClassLink->instanceDestructed();
+    }
 
-    if( ((int) instanceCount) < 0)
-       printf("%s: bad retain(%d)", getClassName(), instanceCount);
+    if (((int)instanceCount) < 0) {
+        OSKext * myKext = reserved->kext;
+
+        OSKextLog(myKext, kOSMetaClassLogSpec,
+            // xxx - this phrasing is rather cryptic
+            "OSMetaClass: Class %s - bad retain (%d)",
+            getClassName(), instanceCount);
+    }
 }
 
-bool OSMetaClass::modHasInstance(const char *kmodName)
+/*********************************************************************
+*********************************************************************/
+bool
+OSMetaClass::modHasInstance(const char * kextIdentifier)
 {
-    bool result = false;
-
-    if (!loadLock) {
-        loadLock = mutex_alloc(0);
-       mutex_lock(loadLock);
+    bool     result  = false;
+    OSKext * theKext = NULL;  // must release
+    
+    theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
+    if (!theKext) {
+        goto finish;
     }
-    else
-       mutex_lock(loadLock);
-
-    do {
-       OSSet *kmodClasses;
-       OSCollectionIterator *iter;
-       OSMetaClass *checkClass;
-
-       kmodClasses = OSDynamicCast(OSSet,
-                                   sKModClassesDict->getObject(kmodName));
-       if (!kmodClasses)
-           break;
-
-       iter = OSCollectionIterator::withCollection(kmodClasses);
-       if (!iter)
-           break;
-
-       while ( (checkClass = (OSMetaClass *) iter->getNextObject()) )
-           if (checkClass->getInstanceCount()) {
-               result = true;
-               break;
-           }
-
-       iter->release();
-    } while (false);
-
-    mutex_unlock(loadLock);
+    
+    result = theKext->hasOSMetaClassInstances();
 
+finish:
+    OSSafeReleaseNULL(theKext);
     return result;
 }
 
-void OSMetaClass::reportModInstances(const char *kmodName)
+/*********************************************************************
+*********************************************************************/
+void
+OSMetaClass::reportModInstances(const char * kextIdentifier)
+{
+    OSKext::reportOSMetaClassInstances(kextIdentifier,
+        kOSKextLogExplicitLevel);
+    return;
+}
+/*********************************************************************
+*********************************************************************/
+
+void
+OSMetaClass::addInstance(const OSObject * instance, bool super) const
 {
-    OSSet *kmodClasses;
-    OSCollectionIterator *iter;
-    OSMetaClass *checkClass;
+    if (!super) IOLockLock(sInstancesLock);
+
+    if (!reserved->instances) {
+       reserved->instances = OSOrderedSet::withCapacity(16);
+       if (superClassLink) {
+           superClassLink->addInstance(reserved->instances, true);
+       }
+    }
+    reserved->instances->setLastObject(instance);
 
-    kmodClasses = OSDynamicCast(OSSet,
-                                sKModClassesDict->getObject(kmodName));
-    if (!kmodClasses)
-       return;
+    if (!super) IOLockUnlock(sInstancesLock);
+}
 
-    iter = OSCollectionIterator::withCollection(kmodClasses);
-    if (!iter)
-       return;
+void
+OSMetaClass::removeInstance(const OSObject * instance, bool super) const
+{
+    if (!super) IOLockLock(sInstancesLock);
 
-    while ( (checkClass = (OSMetaClass *) iter->getNextObject()) )
-       if (checkClass->getInstanceCount()) {
-           printf("%s: %s has %d instance(s)\n",
-                 kmodName,
-                 checkClass->getClassName(),
-                 checkClass->getInstanceCount());
+    if (reserved->instances) {
+       reserved->instances->removeObject(instance);
+       if (0 == reserved->instances->getCount()) {
+           if (superClassLink) {
+               superClassLink->removeInstance(reserved->instances, true);
+           }
+           IOLockLock(sAllClassesLock);
+           reserved->instances->release();
+           reserved->instances = 0;
+           IOLockUnlock(sAllClassesLock);
        }
+    }
 
-    iter->release();
+    if (!super) IOLockUnlock(sInstancesLock);
 }
 
-extern "C" kern_return_t kmod_unload_cache(void);
+void
+OSMetaClass::applyToInstances(OSOrderedSet * set,
+                             OSMetaClassInstanceApplierFunction  applier,
+                              void * context)
+{
+    enum {         kLocalDepth = 24 };
+    unsigned int    _nextIndex[kLocalDepth];
+    OSOrderedSet *  _sets[kLocalDepth];
+    unsigned int *  nextIndex = &_nextIndex[0];
+    OSOrderedSet ** sets      = &_sets[0];
+    OSObject *      obj;
+    OSOrderedSet *  childSet;
+    unsigned int    maxDepth;
+    unsigned int    idx;
+    unsigned int    level;
+    bool            done;
+
+    maxDepth = sDeepestClass;
+    if (maxDepth > kLocalDepth)
+    {
+       nextIndex = IONew(typeof(nextIndex[0]), maxDepth);
+       sets      = IONew(typeof(sets[0]), maxDepth);
+    }
+    done = false;
+    level = 0;
+    idx = 0;
+    do
+    {
+       while (!done && (obj = set->getObject(idx++)))
+       {
+           if ((childSet = OSDynamicCast(OSOrderedSet, obj)))
+           {
+               if (level >= maxDepth) panic(">maxDepth");
+               sets[level] = set;
+               nextIndex[level] = idx;
+               level++;
+               set = childSet;
+               idx = 0;
+               break;
+           }
+           done = (*applier)(obj, context);
+       }
+       if (!obj)
+       {
+           if (!done && level)
+           {
+               level--;
+               set = sets[level];
+               idx = nextIndex[level];
+           } else done = true;
+       }
+    }
+    while (!done);
+    if (maxDepth > kLocalDepth)
+    {
+       IODelete(nextIndex, typeof(nextIndex[0]), maxDepth);
+       IODelete(sets, typeof(sets[0]), maxDepth);
+    }
+}
 
-static void _OSMetaClassConsiderUnloads(thread_call_param_t p0,
-                                        thread_call_param_t p1)
+void
+OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier,
+                              void * context) const
 {
-    OSSet *kmodClasses;
-    OSSymbol *kmodName;
-    OSCollectionIterator *kmods;
-    OSCollectionIterator *classes;
-    OSMetaClass *checkClass;
-    kmod_info_t *ki = 0;
-    kern_return_t ret;
-    bool didUnload;
+    IOLockLock(sInstancesLock);
+    if (reserved->instances) applyToInstances(reserved->instances, applier, context);
+    IOLockUnlock(sInstancesLock);
+}
 
-    mutex_lock(loadLock);
+void
+OSMetaClass::applyToInstancesOfClassName(
+                               const OSSymbol * name,
+                               OSMetaClassInstanceApplierFunction  applier,
+                                void * context)
+{
+    OSMetaClass  * meta;
+    OSOrderedSet * set = 0;
 
-    do {
+    IOLockLock(sAllClassesLock);
+    if (sAllClassesDict 
+       && (meta = (OSMetaClass *) sAllClassesDict->getObject(name))
+       && (set = meta->reserved->instances))
+    {
+       set->retain();
+    }
+    IOLockUnlock(sAllClassesLock);
 
-       kmods = OSCollectionIterator::withCollection(sKModClassesDict);
-       if (!kmods)
-           break;
+    if (!set) return;
 
-        didUnload = false;
-        while ( (kmodName = (OSSymbol *) kmods->getNextObject()) ) {
+    IOLockLock(sInstancesLock);
+    applyToInstances(set, applier, context);
+    IOLockUnlock(sInstancesLock);
+    set->release();
+}
 
-            if (ki) {
-                kfree((vm_offset_t) ki, sizeof(kmod_info_t));
-                ki = 0;
-            }
+/*********************************************************************
+*********************************************************************/
+void
+OSMetaClass::considerUnloads()
+{
+    OSKext::considerUnloads();
+}
 
-            ki = kmod_lookupbyname_locked((char *)kmodName->getCStringNoCopy());
-            if (!ki)
-                continue;
+/*********************************************************************
+*********************************************************************/
+bool
+OSMetaClass::removeClasses(OSCollection * metaClasses)
+{
+    OSCollectionIterator * classIterator;
+    OSMetaClass          * checkClass;
+    bool                   result;
 
-            if (ki->reference_count) {
-                 continue;
-            }
+    classIterator = OSCollectionIterator::withCollection(metaClasses);
+    if (!classIterator) return (false);
 
-            kmodClasses = OSDynamicCast(OSSet,
-                                sKModClassesDict->getObject(kmodName));
-            classes = OSCollectionIterator::withCollection(kmodClasses);
-            if (!classes)
-                continue;
-    
-            while ((checkClass = (OSMetaClass *) classes->getNextObject())
-              && (0 == checkClass->getInstanceCount()))
-                {}
-            classes->release();
-
-            if (0 == checkClass) {
-                OSRuntimeUnloadCPP(ki, 0);     // call destructors
-                ret = kmod_destroy(host_priv_self(), ki->id);
-                didUnload = true;
-            }
+    IOLockLock(sAllClassesLock);
 
+    result = false;
+    do
+    {
+        while ((checkClass = (OSMetaClass *)classIterator->getNextObject())
+            && !checkClass->getInstanceCount()
+            && !checkClass->reserved->retain) {}
+        if (checkClass) break;
+        classIterator->reset();
+        while ((checkClass = (OSMetaClass *)classIterator->getNextObject()))
+        {
+            sAllClassesDict->removeObject(checkClass->className);
         }
+        result = true;
+    }
+    while (false);
 
-        kmods->release();
-
-    } while (didUnload);
-
-    mutex_unlock(loadLock);
+    IOLockUnlock(sAllClassesLock);
+    OSSafeReleaseNULL(classIterator);
 
-    kmod_unload_cache();
+    return (result);
 }
 
-void OSMetaClass::considerUnloads()
-{
-    static thread_call_t unloadCallout;
-    AbsoluteTime when;
 
-    mutex_lock(loadLock);
+/*********************************************************************
+*********************************************************************/
+const OSMetaClass *
+OSMetaClass::getMetaClassWithName(const OSSymbol * name)
+{
+    OSMetaClass * retMeta = 0;
 
-    if (!unloadCallout)
-        unloadCallout = thread_call_allocate(&_OSMetaClassConsiderUnloads, 0);
+    if (!name) {
+        return 0;
+    }
 
-    thread_call_cancel(unloadCallout);
-    clock_interval_to_deadline(sConsiderUnloadDelay, 1000 * 1000 * 1000, &when);
-    thread_call_enter_delayed(unloadCallout, when);
+    IOLockLock(sAllClassesLock);
+    if (sAllClassesDict) {
+        retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
+    }
+    IOLockUnlock(sAllClassesLock);
 
-    mutex_unlock(loadLock);
+    return retMeta;
 }
 
-const OSMetaClass *OSMetaClass::getMetaClassWithName(const OSSymbol *name)
+/*********************************************************************
+*********************************************************************/
+const OSMetaClass *
+OSMetaClass::copyMetaClassWithName(const OSSymbol * name)
 {
-    OSMetaClass *retMeta = 0;
-
-    if (!name)
-       return 0;
+    const OSMetaClass * meta;
 
-    if (sAllClassesDict)
-       retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
-
-    if (!retMeta && sStalled)
-    {
-       // Oh dear we have to scan the stalled list and walk the
-       // the stalled list manually.
-       const char *cName = name->getCStringNoCopy();
-       unsigned int i;
-
-       // find class in stalled list
-       for (i = 0; i < sStalled->count; i++) {
-           retMeta = sStalled->classes[i];
-           if (0 == strcmp(cName, (const char *) retMeta->className))
-               break;
-       }
+    if (!name) return (0);
 
-       if (i < sStalled->count)
-           retMeta = 0;
+    meta = 0;
+    IOLockLock(sAllClassesLock);
+    if (sAllClassesDict) {
+        meta = (OSMetaClass *) sAllClassesDict->getObject(name);
+        if (meta) OSIncrementAtomic(&meta->reserved->retain);
     }
+    IOLockUnlock(sAllClassesLock);
 
-    return retMeta;
+    return (meta);
 }
 
-OSObject *OSMetaClass::allocClassWithName(const OSSymbol *name)
+/*********************************************************************
+*********************************************************************/
+void
+OSMetaClass::releaseMetaClass() const
 {
-    OSObject * result;
-    mutex_lock(loadLock);
+    OSDecrementAtomic(&reserved->retain);
+}
 
-    const OSMetaClass * const meta = getMetaClassWithName(name);
+/*********************************************************************
+*********************************************************************/
+OSObject *
+OSMetaClass::allocClassWithName(const OSSymbol * name)
+{
+    const OSMetaClass * meta;
+    OSObject          * result;
 
+    result = 0;
+    meta = copyMetaClassWithName(name);
     if (meta)
-       result = meta->alloc();
-    else
-        result = 0;
-
-    mutex_unlock(loadLock);
+    {
+        result = meta->alloc();
+        meta->releaseMetaClass();
+    }
 
     return result;
 }
 
-OSObject *OSMetaClass::allocClassWithName(const OSString *name)
+/*********************************************************************
+*********************************************************************/
+OSObject *
+OSMetaClass::allocClassWithName(const OSString * name)
 {
-    const OSSymbol *tmpKey = OSSymbol::withString(name);
-    OSObject *result = allocClassWithName(tmpKey);
+    const OSSymbol * tmpKey = OSSymbol::withString(name);
+    OSObject * result = allocClassWithName(tmpKey);
     tmpKey->release();
     return result;
 }
 
-OSObject *OSMetaClass::allocClassWithName(const char *name)
+/*********************************************************************
+*********************************************************************/
+OSObject *
+OSMetaClass::allocClassWithName(const char * name)
 {
-    const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
-    OSObject *result = allocClassWithName(tmpKey);
+    const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name);
+    OSObject       * result = allocClassWithName(tmpKey);
     tmpKey->release();
     return result;
 }
 
 
-OSMetaClassBase *OSMetaClass::
-checkMetaCastWithName(const OSSymbol *name, const OSMetaClassBase *in)
+/*********************************************************************
+*********************************************************************/
+OSMetaClassBase *
+OSMetaClass::checkMetaCastWithName(
+    const OSSymbol        * name,
+    const OSMetaClassBase * in)
 {
-    OSMetaClassBase * result;
-    mutex_lock(loadLock);
+    OSMetaClassBase * result = 0;
+
     const OSMetaClass * const meta = getMetaClassWithName(name);
 
-    if (meta)
-       result = meta->checkMetaCast(in);
-    else
-        result = 0;
+    if (meta) {
+        result = meta->checkMetaCast(in);
+    }
 
-    mutex_unlock(loadLock);
     return result;
 }
 
-OSMetaClassBase *OSMetaClass::
-checkMetaCastWithName(const OSString *name, const OSMetaClassBase *in)
+/*********************************************************************
+*********************************************************************/
+OSMetaClassBase * OSMetaClass::
+checkMetaCastWithName(
+    const OSString        * name,
+    const OSMetaClassBase * in)
 {
-    const OSSymbol *tmpKey = OSSymbol::withString(name);
-    OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in);
+    const OSSymbol  * tmpKey = OSSymbol::withString(name);
+    OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
+
     tmpKey->release();
     return result;
 }
 
-OSMetaClassBase *OSMetaClass::
-checkMetaCastWithName(const char *name, const OSMetaClassBase *in)
+/*********************************************************************
+*********************************************************************/
+OSMetaClassBase *
+OSMetaClass::checkMetaCastWithName(
+    const char            * name,
+    const OSMetaClassBase * in)
 {
-    const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
-    OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in);
+    const OSSymbol  * tmpKey = OSSymbol::withCStringNoCopy(name);
+    OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
+
     tmpKey->release();
     return result;
 }
 
-/*
-OSMetaClass::checkMetaCast
-    checkMetaCast(const OSMetaClassBase *check)
-
-Check to see if the 'check' object has this object in it's metaclass chain.  Returns check if it is indeed a kind of the current meta class, 0 otherwise.
-
-Generally this method is not invoked directly but is used to implement the OSMetaClassBase::metaCast member function.
-
-See also OSMetaClassBase::metaCast
-
- */
-OSMetaClassBase *OSMetaClass::checkMetaCast(const OSMetaClassBase *check) const
+/*********************************************************************
+ * OSMetaClass::checkMetaCast()
+ * Check to see if the 'check' object has this object in its metaclass chain.
+ * Returns check if it is indeed a kind of the current meta class, 0 otherwise.
+ *
+ * Generally this method is not invoked directly but is used to implement
+ * the OSMetaClassBase::metaCast member function.
+ *
+ * See also OSMetaClassBase::metaCast
+*********************************************************************/
+OSMetaClassBase * OSMetaClass::checkMetaCast(
+    const OSMetaClassBase * check) const
 {
-    const OSMetaClass * const toMeta = this;
-    const OSMetaClass *fromMeta;
+    const OSMetaClass * const toMeta   = this;
+    const OSMetaClass *       fromMeta;
 
     for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) {
-       if (toMeta == fromMeta)
-           return (OSMetaClassBase *) check; // Discard const
-
-       if (!fromMeta->superClassLink)
-           break;
+        if (toMeta == fromMeta) {
+            return const_cast<OSMetaClassBase *>(check); // Discard const
+        }
+        if (!fromMeta->superClassLink) {
+            break;
+        }
     }
 
     return 0;
 }
 
-void OSMetaClass::reservedCalled(int ind) const
+/*********************************************************************
+*********************************************************************/
+void
+OSMetaClass::reservedCalled(int ind) const
 {
-    const char *cname = className->getCStringNoCopy();
-    panic("%s::_RESERVED%s%d called\n", cname, cname, ind);
+    const char * cname = className->getCStringNoCopy();
+    panic("%s::_RESERVED%s%d called.", cname, cname, ind);
 }
 
-const OSMetaClass *OSMetaClass::getSuperClass() const
+/*********************************************************************
+*********************************************************************/
+const
+OSMetaClass *
+OSMetaClass::getSuperClass() const
 {
     return superClassLink;
 }
 
-const OSSymbol *OSMetaClass::getKmodName() const
-{      
-    return sSortedByClassesDict->getObject((const OSSymbol *)this);
+/*********************************************************************
+* xxx - I want to rename this :-/
+*********************************************************************/
+const OSSymbol *
+OSMetaClass::getKmodName() const
+{
+    OSKext * myKext = reserved ? reserved->kext : 0;
+    if (myKext) {
+        return myKext->getIdentifier();
+    }
+    return OSSymbol::withCStringNoCopy("unknown");
 }
 
-unsigned int OSMetaClass::getInstanceCount() const
+/*********************************************************************
+*********************************************************************/
+unsigned int
+OSMetaClass::getInstanceCount() const
 {
     return instanceCount;
 }
 
-void OSMetaClass::printInstanceCounts()
+/*********************************************************************
+*********************************************************************/
+/* static */
+void
+OSMetaClass::printInstanceCounts()
 {
-    OSCollectionIterator *classes;
-    OSSymbol            *className;
-    OSMetaClass                 *meta;
+    OSCollectionIterator * classes;
+    OSSymbol             * className;
+    OSMetaClass          meta;
 
+    IOLockLock(sAllClassesLock);
     classes = OSCollectionIterator::withCollection(sAllClassesDict);
-    if (!classes)
-       return;
+    assert(classes);
 
     while( (className = (OSSymbol *)classes->getNextObject())) {
-       meta = (OSMetaClass *) sAllClassesDict->getObject(className);
-       assert(meta);
-
-       printf("%24s count: %03d x 0x%03x = 0x%06x\n",
-           className->getCStringNoCopy(),
-           meta->getInstanceCount(),
-           meta->getClassSize(),
-           meta->getInstanceCount() * meta->getClassSize() );
+        meta = (OSMetaClass *)sAllClassesDict->getObject(className);
+        assert(meta);
+
+        printf("%24s count: %03d x 0x%03x = 0x%06x\n",
+            className->getCStringNoCopy(),
+            meta->getInstanceCount(),
+            meta->getClassSize(),
+            meta->getInstanceCount() * meta->getClassSize() );
     }
     printf("\n");
     classes->release();
+    IOLockUnlock(sAllClassesLock);
+    return;
 }
 
-OSDictionary * OSMetaClass::getClassDictionary()
+/*********************************************************************
+*********************************************************************/
+OSDictionary *
+OSMetaClass::getClassDictionary()
 {
-    panic("OSMetaClass::getClassDictionary(): Obsoleted\n");
+    panic("OSMetaClass::getClassDictionary() is obsoleted.\n");
     return 0;
 }
 
-bool OSMetaClass::serialize(OSSerialize *s) const
+/*********************************************************************
+*********************************************************************/
+bool
+OSMetaClass::serialize(__unused OSSerialize * s) const
 {
     panic("OSMetaClass::serialize(): Obsoleted\n");
     return false;
 }
 
-void OSMetaClass::serializeClassDictionary(OSDictionary *serializeDictionary)
+/*********************************************************************
+*********************************************************************/
+/* static */
+void
+OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary)
 {
-    OSDictionary *classDict;
+    OSDictionary * classDict = NULL;
+
+    IOLockLock(sAllClassesLock);
 
     classDict = OSDictionary::withCapacity(sAllClassesDict->getCount());
-    if (!classDict)
-        return;
+    if (!classDict) {
+        goto finish;
+    }
 
-    mutex_lock(loadLock);
     do {
-        OSCollectionIterator *classes;
-        const OSSymbol *className;
+        OSCollectionIterator * classes;
+        const OSSymbol * className;
 
         classes = OSCollectionIterator::withCollection(sAllClassesDict);
-        if (!classes)
+        if (!classes) {
             break;
+        }
     
-        while ((className = (const OSSymbol *) classes->getNextObject())) {
-            const OSMetaClass *meta;
-            OSNumber *count;
+        while ((className = (const OSSymbol *)classes->getNextObject())) {
+            const OSMetaClass * meta;
+            OSNumber * count;
 
-            meta = (OSMetaClass *) sAllClassesDict->getObject(className);
+            meta = (OSMetaClass *)sAllClassesDict->getObject(className);
             count = OSNumber::withNumber(meta->getInstanceCount(), 32);
             if (count) {
                 classDict->setObject(className, count);
@@ -863,7 +1277,68 @@ void OSMetaClass::serializeClassDictionary(OSDictionary *serializeDictionary)
         serializeDictionary->setObject("Classes", classDict);
     } while (0);
 
-    mutex_unlock(loadLock);
+finish:
+    OSSafeReleaseNULL(classDict);
+
+    IOLockUnlock(sAllClassesLock);
+
+    return;
+}
+
+
+/*********************************************************************
+*********************************************************************/
+
+#if IOTRACKING
+
+void *OSMetaClass::trackedNew(size_t size)
+{
+    IOTracking * mem;
+
+    mem = (typeof(mem)) kalloc_tag_bt(size + sizeof(IOTracking), VM_KERN_MEMORY_LIBKERN);
+    assert(mem);
+    if (!mem) return (mem);
+
+    memset(mem, 0, size + sizeof(IOTracking));
+    mem++;
+
+    OSIVAR_ACCUMSIZE(size);
+
+    return (mem);
+}
+
+void OSMetaClass::trackedDelete(void * instance, size_t size)
+{
+    IOTracking * mem = (typeof(mem)) instance; mem--;
+
+    kfree(mem, size + sizeof(IOTracking));
+    OSIVAR_ACCUMSIZE(-size);
+}
+
+void OSMetaClass::trackedInstance(OSObject * instance) const
+{
+    IOTracking * mem = (typeof(mem)) instance; mem--;
+
+    return (IOTrackingAdd(reserved->tracking, mem, classSize, false, VM_KERN_MEMORY_NONE));
+}
+
+void OSMetaClass::trackedFree(OSObject * instance) const
+{
+    IOTracking * mem = (typeof(mem)) instance; mem--;
+
+    return (IOTrackingRemove(reserved->tracking, mem, classSize));
+}
+
+void OSMetaClass::trackedAccumSize(OSObject * instance, size_t size) const
+{
+    IOTracking * mem = (typeof(mem)) instance; mem--;
 
-    classDict->release();
+    return (IOTrackingAccumSize(reserved->tracking, mem, size));
 }
+
+IOTrackingQueue * OSMetaClass::getTracking() const
+{
+    return (reserved->tracking);
+}
+
+#endif /* IOTRACKING */