]> 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 bc67307d294282e28eb3660471414223eb746218..3d7c2f6e44ab396d48646f2a90bb09bcffbcf065 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2006 Apple Inc. All rights reserved.
+ * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
 #include <libkern/c++/OSLib.h>
 #include <libkern/OSAtomic.h>
 
-#include <IOKit/pwr_mgt/RootDomain.h>
-#include <IOKit/IOMessage.h>
 #include <IOKit/IOLib.h>
 
+#include <IOKit/IOKitDebug.h>
+
+
 __BEGIN_DECLS
 
 #include <sys/systm.h>
@@ -66,13 +67,6 @@ __BEGIN_DECLS
 /*********************************************************************
 * Macros
 *********************************************************************/
-#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 */
-
 __END_DECLS
 
 #if PRAGMA_MARK
@@ -95,7 +89,9 @@ static enum {
 static const int      kClassCapacityIncrement = 40;
 static const int      kKModCapacityIncrement  = 10;
 static OSDictionary * sAllClassesDict;
+static unsigned int   sDeepestClass;
 IOLock              * sAllClassesLock = NULL;
+IOLock              * sInstancesLock  = NULL;
 
 /*
  * While loading a kext and running all its constructors to register
@@ -111,6 +107,16 @@ static struct StalledData {
 } * sStalled;
 IOLock * sStalledClassesLock = NULL;
 
+struct ExpansionData {
+    OSOrderedSet    * instances;
+    OSKext          * kext;
+    uint32_t          retain;
+#if IOTRACKING
+    IOTrackingQueue * tracking;
+#endif
+};
+
+
 #if PRAGMA_MARK
 #pragma mark OSMetaClassBase
 #endif /* PRAGMA_MARK */
@@ -118,6 +124,7 @@ IOLock * sStalledClassesLock = NULL;
 * OSMetaClassBase.
 *********************************************************************/
 
+#if APPLE_KEXT_VTABLE_PADDING
 /*********************************************************************
 * Reserved vtable functions.
 *********************************************************************/
@@ -139,7 +146,8 @@ void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
     { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); }
 void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
     { 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
@@ -176,8 +184,10 @@ initialize()
 {
     sAllClassesLock = IOLockAlloc();
     sStalledClassesLock = IOLockAlloc();
+    sInstancesLock = IOLockAlloc();
 }
 
+#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
@@ -186,6 +196,7 @@ initialize()
 void
 OSMetaClassBase::_RESERVEDOSMetaClassBase7()
 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); }
+#endif
 
 /*********************************************************************
 *********************************************************************/
@@ -285,6 +296,7 @@ const OSMetaClass * OSMetaClass::getMetaClass() const
 * OSMetaClass
 *********************************************************************/
 
+#if APPLE_KEXT_VTABLE_PADDING
 /*********************************************************************
 * Reserved functions.
 *********************************************************************/
@@ -304,6 +316,7 @@ void OSMetaClass::_RESERVEDOSMetaClass6()
     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); }
 void OSMetaClass::_RESERVEDOSMetaClass7()
     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); }
+#endif
 
 /*********************************************************************
 *********************************************************************/
@@ -377,6 +390,24 @@ OSMetaClass::OSMetaClass(
     classSize = inClassSize;
     superClassLink = inSuperClass;
 
+    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!
@@ -399,7 +430,7 @@ OSMetaClass::OSMetaClass(
             int newSize = oldSize
                 + kKModCapacityIncrement * sizeof(OSMetaClass *);
 
-            sStalled->classes = (OSMetaClass **)kalloc(newSize);
+            sStalled->classes = (OSMetaClass **)kalloc_tag(newSize, VM_KERN_MEMORY_OSKEXT);
             if (!sStalled->classes) {
                 sStalled->classes = oldStalled;
                 sStalled->result = kOSMetaClassNoTempData;
@@ -409,7 +440,7 @@ OSMetaClass::OSMetaClass(
             sStalled->capacity += kKModCapacityIncrement;
             memmove(sStalled->classes, oldStalled, oldSize);
             kfree(oldStalled, oldSize);
-            ACCUMSIZE(newSize - oldSize);
+            OSMETA_ACCUMSIZE(((size_t)newSize) - ((size_t)oldSize));
         }
 
         sStalled->classes[sStalled->count++] = this;
@@ -420,7 +451,7 @@ OSMetaClass::OSMetaClass(
 *********************************************************************/
 OSMetaClass::~OSMetaClass()
 {
-    OSKext * myKext = (OSKext *)reserved; // do not release
+    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
@@ -472,12 +503,15 @@ OSMetaClass::~OSMetaClass()
             }
         }
     }
+#if IOTRACKING
+    IOTrackingQueueFree(reserved->tracking);
+#endif
+    IODelete(reserved, ExpansionData, 1);
 }
 
 /*********************************************************************
 * Empty overrides.
 *********************************************************************/
-void * OSMetaClass::operator new(__unused size_t size) { return 0; }
 void OSMetaClass::retain() const { }
 void OSMetaClass::release() const { }
 void OSMetaClass::release(__unused int when) const { }
@@ -491,9 +525,16 @@ int  OSMetaClass::getRetainCount() const { return 0; }
 const char *
 OSMetaClass::getClassName() const
 {
+    if (!className) return NULL;
     return className->getCStringNoCopy();
 }
-
+/*********************************************************************
+*********************************************************************/
+const OSSymbol *
+OSMetaClass::getClassNameSymbol() const
+{
+    return className;
+}
 /*********************************************************************
 *********************************************************************/
 unsigned int
@@ -510,15 +551,15 @@ OSMetaClass::preModLoad(const char * kextIdentifier)
     IOLockLock(sStalledClassesLock);
 
     assert (sStalled == NULL);
-    sStalled = (StalledData *)kalloc(sizeof(* sStalled));
+    sStalled = (StalledData *)kalloc_tag(sizeof(* sStalled), VM_KERN_MEMORY_OSKEXT);
     if (sStalled) {
         sStalled->classes = (OSMetaClass **)
-            kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
+            kalloc_tag(kKModCapacityIncrement * sizeof(OSMetaClass *), VM_KERN_MEMORY_OSKEXT);
         if (!sStalled->classes) {
             kfree(sStalled, sizeof(*sStalled));
             return 0;
         }
-        ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
+        OSMETA_ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
             sizeof(*sStalled));
 
         sStalled->result   = kOSReturnSuccess;
@@ -563,6 +604,7 @@ OSMetaClass::postModLoad(void * loadHandle)
         case kNoDictionaries:
             sBootstrapState = kMakingDictionaries;
             // No break; fall through
+           [[clang::fallthrough]];
             
         case kMakingDictionaries:
             sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
@@ -570,8 +612,10 @@ OSMetaClass::postModLoad(void * loadHandle)
                 result = kOSMetaClassNoDicts;
                 break;
             }
+            sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
 
-        // No break; fall through
+           // No break; fall through
+           [[clang::fallthrough]];
 
         case kCompletedBootstrap:
         {
@@ -604,7 +648,7 @@ OSMetaClass::postModLoad(void * loadHandle)
             */
             IOLockLock(sAllClassesLock);
             for (i = 0; i < sStalled->count; i++) {
-                OSMetaClass * me = sStalled->classes[i];
+                const OSMetaClass * me = sStalled->classes[i];
                 OSMetaClass * orig = OSDynamicCast(OSMetaClass,
                     sAllClassesDict->getObject((const char *)me->className));
                 
@@ -613,14 +657,21 @@ OSMetaClass::postModLoad(void * loadHandle)
                    /* 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)->getIdentifierCString());
+                        ((OSKext *)orig->reserved->kext)->getIdentifierCString());
                     result = kOSMetaClassDuplicateClass;
                     break;
                 }
+               unsigned int depth = 1;
+               while ((me = me->superClassLink)) depth++;
+               if (depth > sDeepestClass) sDeepestClass = depth;
             }
             IOLockUnlock(sAllClassesLock);
             
@@ -648,7 +699,7 @@ OSMetaClass::postModLoad(void * loadHandle)
                 
                /* Do not retain the kext object here.
                 */
-                me->reserved = (ExpansionData *)myKext;
+                me->reserved->kext = myKext;
                 if (myKext) {
                     result = myKext->addClass(me, sStalled->count);
                     if (result != kOSReturnSuccess) {
@@ -679,11 +730,11 @@ finish:
         OSMetaClassLogErrorForKext(result, myKext);
     }
 
-    OSSafeRelease(myKextName);
-    OSSafeRelease(myKext);
+    OSSafeReleaseNULL(myKextName);
+    OSSafeReleaseNULL(myKext);
 
     if (sStalled) {
-        ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
+        OSMETA_ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
             sizeof(*sStalled)));
         kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *));
         kfree(sStalled, sizeof(*sStalled));
@@ -717,7 +768,7 @@ OSMetaClass::instanceDestructed() const
     }
 
     if (((int)instanceCount) < 0) {
-        OSKext * myKext = (OSKext *)reserved;
+        OSKext * myKext = reserved->kext;
 
         OSKextLog(myKext, kOSMetaClassLogSpec,
             // xxx - this phrasing is rather cryptic
@@ -742,7 +793,7 @@ OSMetaClass::modHasInstance(const char * kextIdentifier)
     result = theKext->hasOSMetaClassInstances();
 
 finish:
-    OSSafeRelease(theKext);
+    OSSafeReleaseNULL(theKext);
     return result;
 }
 
@@ -755,6 +806,140 @@ OSMetaClass::reportModInstances(const char * kextIdentifier)
         kOSKextLogExplicitLevel);
     return;
 }
+/*********************************************************************
+*********************************************************************/
+
+void
+OSMetaClass::addInstance(const OSObject * instance, bool super) const
+{
+    if (!super) IOLockLock(sInstancesLock);
+
+    if (!reserved->instances) {
+       reserved->instances = OSOrderedSet::withCapacity(16);
+       if (superClassLink) {
+           superClassLink->addInstance(reserved->instances, true);
+       }
+    }
+    reserved->instances->setLastObject(instance);
+
+    if (!super) IOLockUnlock(sInstancesLock);
+}
+
+void
+OSMetaClass::removeInstance(const OSObject * instance, bool super) const
+{
+    if (!super) IOLockLock(sInstancesLock);
+
+    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);
+       }
+    }
+
+    if (!super) IOLockUnlock(sInstancesLock);
+}
+
+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);
+    }
+}
+
+void
+OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier,
+                              void * context) const
+{
+    IOLockLock(sInstancesLock);
+    if (reserved->instances) applyToInstances(reserved->instances, applier, context);
+    IOLockUnlock(sInstancesLock);
+}
+
+void
+OSMetaClass::applyToInstancesOfClassName(
+                               const OSSymbol * name,
+                               OSMetaClassInstanceApplierFunction  applier,
+                                void * context)
+{
+    OSMetaClass  * meta;
+    OSOrderedSet * set = 0;
+
+    IOLockLock(sAllClassesLock);
+    if (sAllClassesDict 
+       && (meta = (OSMetaClass *) sAllClassesDict->getObject(name))
+       && (set = meta->reserved->instances))
+    {
+       set->retain();
+    }
+    IOLockUnlock(sAllClassesLock);
+
+    if (!set) return;
+
+    IOLockLock(sInstancesLock);
+    applyToInstances(set, applier, context);
+    IOLockUnlock(sInstancesLock);
+    set->release();
+}
 
 /*********************************************************************
 *********************************************************************/
@@ -764,6 +949,43 @@ OSMetaClass::considerUnloads()
     OSKext::considerUnloads();
 }
 
+/*********************************************************************
+*********************************************************************/
+bool
+OSMetaClass::removeClasses(OSCollection * metaClasses)
+{
+    OSCollectionIterator * classIterator;
+    OSMetaClass          * checkClass;
+    bool                   result;
+
+    classIterator = OSCollectionIterator::withCollection(metaClasses);
+    if (!classIterator) return (false);
+
+    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);
+
+    IOLockUnlock(sAllClassesLock);
+    OSSafeReleaseNULL(classIterator);
+
+    return (result);
+}
+
+
 /*********************************************************************
 *********************************************************************/
 const OSMetaClass *
@@ -784,17 +1006,48 @@ OSMetaClass::getMetaClassWithName(const OSSymbol * name)
     return retMeta;
 }
 
+/*********************************************************************
+*********************************************************************/
+const OSMetaClass *
+OSMetaClass::copyMetaClassWithName(const OSSymbol * name)
+{
+    const OSMetaClass * meta;
+
+    if (!name) return (0);
+
+    meta = 0;
+    IOLockLock(sAllClassesLock);
+    if (sAllClassesDict) {
+        meta = (OSMetaClass *) sAllClassesDict->getObject(name);
+        if (meta) OSIncrementAtomic(&meta->reserved->retain);
+    }
+    IOLockUnlock(sAllClassesLock);
+
+    return (meta);
+}
+
+/*********************************************************************
+*********************************************************************/
+void
+OSMetaClass::releaseMetaClass() const
+{
+    OSDecrementAtomic(&reserved->retain);
+}
+
 /*********************************************************************
 *********************************************************************/
 OSObject *
 OSMetaClass::allocClassWithName(const OSSymbol * name)
 {
-    OSObject * result = 0;
+    const OSMetaClass * meta;
+    OSObject          * result;
 
-    const OSMetaClass * const meta = getMetaClassWithName(name);
-
-    if (meta) {
+    result = 0;
+    meta = copyMetaClassWithName(name);
+    if (meta)
+    {
         result = meta->alloc();
+        meta->releaseMetaClass();
     }
 
     return result;
@@ -921,7 +1174,7 @@ OSMetaClass::getSuperClass() const
 const OSSymbol *
 OSMetaClass::getKmodName() const
 {
-    OSKext * myKext = (OSKext *)reserved;
+    OSKext * myKext = reserved ? reserved->kext : 0;
     if (myKext) {
         return myKext->getIdentifier();
     }
@@ -1025,9 +1278,67 @@ OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary)
     } while (0);
 
 finish:
-    OSSafeRelease(classDict);
+    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--;
+
+    return (IOTrackingAccumSize(reserved->tracking, mem, size));
+}
+
+IOTrackingQueue * OSMetaClass::getTracking() const
+{
+    return (reserved->tracking);
+}
+
+#endif /* IOTRACKING */