/*
- * 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>
/*********************************************************************
* 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
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
} * 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 */
* OSMetaClassBase.
*********************************************************************/
+#if APPLE_KEXT_VTABLE_PADDING
/*********************************************************************
* Reserved vtable functions.
*********************************************************************/
{ 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
{
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
void
OSMetaClassBase::_RESERVEDOSMetaClassBase7()
{ panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); }
+#endif
/*********************************************************************
*********************************************************************/
* OSMetaClass
*********************************************************************/
+#if APPLE_KEXT_VTABLE_PADDING
/*********************************************************************
* Reserved functions.
*********************************************************************/
{ panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); }
void OSMetaClass::_RESERVEDOSMetaClass7()
{ panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); }
+#endif
/*********************************************************************
*********************************************************************/
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!
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;
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;
*********************************************************************/
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
}
}
}
+#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 { }
const char *
OSMetaClass::getClassName() const
{
+ if (!className) return NULL;
return className->getCStringNoCopy();
}
-
+/*********************************************************************
+*********************************************************************/
+const OSSymbol *
+OSMetaClass::getClassNameSymbol() const
+{
+ return className;
+}
/*********************************************************************
*********************************************************************/
unsigned int
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;
case kNoDictionaries:
sBootstrapState = kMakingDictionaries;
// No break; fall through
+ [[clang::fallthrough]];
case kMakingDictionaries:
sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
result = kOSMetaClassNoDicts;
break;
}
+ sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
- // No break; fall through
+ // No break; fall through
+ [[clang::fallthrough]];
case kCompletedBootstrap:
{
*/
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));
/* 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);
/* 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) {
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));
}
if (((int)instanceCount) < 0) {
- OSKext * myKext = (OSKext *)reserved;
+ OSKext * myKext = reserved->kext;
OSKextLog(myKext, kOSMetaClassLogSpec,
// xxx - this phrasing is rather cryptic
result = theKext->hasOSMetaClassInstances();
finish:
- OSSafeRelease(theKext);
+ OSSafeReleaseNULL(theKext);
return result;
}
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();
+}
/*********************************************************************
*********************************************************************/
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 *
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;
const OSSymbol *
OSMetaClass::getKmodName() const
{
- OSKext * myKext = (OSKext *)reserved;
+ OSKext * myKext = reserved ? reserved->kext : 0;
if (myKext) {
return myKext->getIdentifier();
}
} 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 */