File:  [Apple XNU] / XNU / libkern / c++ / OSMetaClass.cpp
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:45:09 2018 UTC (8 years, 2 months ago) by root
Branches: MAIN, Apple
CVS tags: v68_4-1_1, HEAD
xnu-68.4-1.1

/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @APPLE_LICENSE_HEADER_END@
 */
/* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */

#include <string.h>
#include <sys/systm.h>

#include <libkern/OSReturn.h>

#include <libkern/c++/OSCollectionIterator.h>
#include <libkern/c++/OSDictionary.h>
#include <libkern/c++/OSMetaClass.h>
#include <libkern/c++/OSArray.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>

enum {
    kSuperIsCString = 0x80000000,
};

__BEGIN_DECLS

#include <mach/etap_events.h>
#include <kern/lock.h>

#ifdef DEBUG
extern int debug_container_malloc_size;
#define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
#else
#define ACCUMSIZE(s)
#endif /* DEBUG */

__END_DECLS

static enum {
    kCompletedBootstrap = 0,
    kNoDictionaries = 1,
    kMakingDictionaries = 2
} sBootstrapState = kNoDictionaries;

static const int kClassCapacityIncrement = 40;
static const int kKModCapacityIncrement = 10;
static OSDictionary *sAllClassesDict, *sKModClassesDict;

static mutex_t *loadLock;
static struct StalledData {
    const char *kmodName;
    OSReturn result;
    unsigned int capacity;
    unsigned int count;
    OSMetaClass **classes;
} *sStalled;

void OSMetaClass::logError(OSReturn result)
{
    const char *msg;

    switch (result) {
    case kOSMetaClassNoInit:
	msg="OSMetaClass::preModLoad wasn't called, runtime internal error";
	break;
    case kOSMetaClassNoDicts:
	msg="Allocation failure for Metaclass internal dictionaries"; break;
    case kOSMetaClassNoKModSet:
	msg="Allocation failure for internal kmodule set"; break;
    case kOSMetaClassNoInsKModSet:
	msg="Can't insert the KMod set into the module dictionary"; break;
    case kOSMetaClassNoSuper:
	msg="Can't associate a class with its super class"; break;
    case kOSMetaClassInstNoSuper:
	msg="Instance construction, unknown super class."; break;
    default:
    case kOSMetaClassInternal:
	msg="runtime internal error"; break;
    case kOSReturnSuccess:
	return;
    }
    printf("%s\n", msg);
}

OSMetaClass::OSMetaClass(const char *inClassName,
			 const char *inSuperClassName,
			 unsigned int inClassSize)
{
    instanceCount = 0;
    classSize = inClassSize;
    if (inSuperClassName && *inSuperClassName) {
	superClass = (OSMetaClass *) inSuperClassName;
	classSize |= kSuperIsCString;
    }
    else
	superClass = 0;

    className = (const OSSymbol *) inClassName;

    if (!sStalled) {
	printf("OSMetaClass::preModLoad wasn't called for %s, "
	       "runtime internal error\n", 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;
	    }

	    sStalled->capacity += kKModCapacityIncrement;
	    memmove(sStalled->classes, oldStalled, oldSize);
	    kfree((vm_offset_t)oldStalled, oldSize);
	    ACCUMSIZE(newSize - oldSize);
	}

	sStalled->classes[sStalled->count++] = this;
    }
}

OSMetaClass::~OSMetaClass()
{
    do {
	OSCollectionIterator *iter;

	if (sAllClassesDict)
	    sAllClassesDict->removeObject(className);

	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);

    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 *));
	}
	return;
    }
}

// Don't do anything as these classes must be statically allocated
void OSMetaClass::free() { }
void OSMetaClass::retain() { }
void OSMetaClass::release() { }

const char *OSMetaClass::getClassName() const
{
    return className->getCStringNoCopy();
}

unsigned int OSMetaClass::getClassSize() const
{
    return classSize & ~kSuperIsCString;
}

void *OSMetaClass::preModLoad(const char *kmodName)
{
    if (!loadLock) {
        loadLock = mutex_alloc(ETAP_IO_AHA);
	_mutex_lock(loadLock);
    }
    else
	_mutex_lock(loadLock);

    sStalled = (StalledData *) kalloc(sizeof(*sStalled));
    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->result   = kOSReturnSuccess;
	sStalled->capacity = kKModCapacityIncrement;
	sStalled->count	   = 0;
	sStalled->kmodName = kmodName;
	bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *));
    }

    return sStalled;
}

bool OSMetaClass::checkModLoad(void *loadHandle)
{
    return sStalled && loadHandle == sStalled
	&& sStalled->result == kOSReturnSuccess;
}

static inline const OSSymbol *copySymbol(bool copy, const char *cString)
{
    if (copy)
	return OSSymbol::withCString(cString);
    else
	return OSSymbol::withCStringNoCopy(cString);
}

OSReturn OSMetaClass::postModLoad(void *loadHandle)
{
    OSReturn result = kOSReturnSuccess;
    OSSet *kmodSet = 0;

    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);
	if (!sAllClassesDict || !sKModClassesDict) {
	    result = kOSMetaClassNoDicts;
	    break;
	}
	// No break; fall through

    case kCompletedBootstrap:
    {
	bool copyStrings = (0 != strcmp("__kernel__", sStalled->kmodName));

	if (!sStalled->count)
	    break;	// Nothing to do so just get out

	kmodSet = OSSet::withCapacity(sStalled->count);
	if (!kmodSet) {
	    result = kOSMetaClassNoKModSet;
	    break;
	}

	if (!sKModClassesDict->setObject(sStalled->kmodName, kmodSet)) {
	    result = kOSMetaClassNoInsKModSet;
	    break;
	}

	// First pass symbolling strings and inserting classes in dictionary
	for (unsigned int i = 0; i < sStalled->count; i++) {
	    OSMetaClass *me = sStalled->classes[i];

	    me->className = copySymbol(copyStrings,
				       (const char *) me->className);
	    if (me->classSize & kSuperIsCString)
		me->superClass = (OSMetaClass *)
		    copySymbol(copyStrings, (const char *) me->superClass);

	    sAllClassesDict->setObject(me->className, me);
	    kmodSet->setObject(me);
	}

	// Second pass to connect up superclasses.
	for (unsigned int i = 0; !result && i < sStalled->count; i++) {
	    OSMetaClass *me = sStalled->classes[i];
	    OSSymbol *superSym;

	    if (me->classSize & kSuperIsCString) {

		me->classSize &= ~kSuperIsCString;
		superSym = (OSSymbol *) me->superClass;
		me->superClass = (OSMetaClass *)
				    sAllClassesDict->getObject(superSym);
		superSym->release();
		if (!me->superClass)
		    result = kOSMetaClassNoSuper;
	    }
	}
	sBootstrapState = kCompletedBootstrap;
	break;
    }

    default:
	result = kOSMetaClassInternal;
	break;
    }

    if (kmodSet)
	kmodSet->release();

    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;
    }

    logError(result);
    mutex_unlock(loadLock);
    return result;
}


void OSMetaClass::instanceConstructed() const
{
    if (sStalled && (classSize & kSuperIsCString) && superClass)
    {
	OSMetaClass *me = (OSMetaClass *) this;	 // overide const this
	const char * const superName = (const char *) superClass;

	// The superClass may be in the class dictionary already.
	if (sBootstrapState == kCompletedBootstrap && sAllClassesDict)
	    me->superClass = (OSMetaClass *)
		sAllClassesDict->getObject(superName);
	else
	    me->superClass = 0;

	if (!me->superClass) {
	    // Oh dear we have to scan the stalled list and walk the
	    // the super class chain manually.
	    unsigned int i;

	    // find superclass in stalled list
	    for (i = 0; i < sStalled->count; i++) {
		if (0 == strcmp(superName,
				(const char *) sStalled->classes[i]->className))
		    break;
	    }

	    if (i < sStalled->count) {
		me->superClass = sStalled->classes[i];
		me->classSize &= ~kSuperIsCString;
	    }
	    else
		sStalled->result = kOSMetaClassInstNoSuper;

	}
    }

    if ((0 == instanceCount++) && superClass)
	superClass->instanceConstructed();
}

void OSMetaClass::instanceDestructed() const
{
    if ((1 == instanceCount--) && superClass)
	superClass->instanceDestructed();

    if( ((int) instanceCount) < 0)
	printf("%s: bad retain(%d)", getClassName(), instanceCount);
}

bool OSMetaClass::modHasInstance(const char *kmodName)
{
    bool result = false;

    if (!loadLock) {
        loadLock = mutex_alloc(ETAP_IO_AHA);
	_mutex_lock(loadLock);
    }
    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);

    return result;
}

void OSMetaClass::reportModInstances(const char *kmodName)
{
    OSSet *kmodClasses;
    OSCollectionIterator *iter;
    OSMetaClass *checkClass;

    kmodClasses = OSDynamicCast(OSSet,
				 sKModClassesDict->getObject(kmodName));
    if (!kmodClasses)
	return;

    iter = OSCollectionIterator::withCollection(kmodClasses);
    if (!iter)
	return;

    while ( (checkClass = (OSMetaClass *) iter->getNextObject()) )
	if (checkClass->getInstanceCount()) {
	    printf("%s: %s has %d instance(s)\n",
		  kmodName,
		  checkClass->getClassName(),
		  checkClass->getInstanceCount());
	}

    iter->release();
}

const OSMetaClass *OSMetaClass::getMetaClassWithName(const OSSymbol *name)
{
    OSMetaClass *retMeta = 0;

    if (!name)
	return 0;

    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 (i < sStalled->count)
	    retMeta = 0;
    }

    return retMeta;
}

const OSMetaClass *OSMetaClass::getMetaClassWithName(const OSString *name)
{
    const OSSymbol *tmpKey = OSSymbol::withString(name);
    const OSMetaClass *ret = getMetaClassWithName(tmpKey);

    tmpKey->release();
    return ret;
}

const OSMetaClass *OSMetaClass::getMetaClassWithName(const char *name)
{
    const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
    const OSMetaClass *ret = getMetaClassWithName(tmpKey);

    tmpKey->release();
    return ret;
}

OSObject *OSMetaClass::allocClassWithName(const OSSymbol *name)
{
    const OSMetaClass * const meta = getMetaClassWithName(name);

    if (meta)
	return meta->alloc();

    return 0;
}

OSObject *OSMetaClass::allocClassWithName(const OSString *name)
{
    const OSMetaClass * const meta = getMetaClassWithName(name);

    if (meta)
	return meta->alloc();

    return 0;
}

OSObject *OSMetaClass::allocClassWithName(const char *name)
{
    const OSMetaClass * const meta = getMetaClassWithName(name);

    if (meta)
	return meta->alloc();

    return 0;
}


OSObject *
OSMetaClass::checkMetaCastWithName(const OSSymbol *name, const OSObject *in)
{
    const OSMetaClass * const meta = getMetaClassWithName(name);

    if (meta)
	return meta->checkMetaCast(in);

    return 0;
}

OSObject *
OSMetaClass::checkMetaCastWithName(const OSString *name, const OSObject *in)
{
    const OSMetaClass * const meta = getMetaClassWithName(name);

    if (meta)
	return meta->checkMetaCast(in);

    return 0;
}

OSObject *
OSMetaClass::checkMetaCastWithName(const char *name, const OSObject *in)
{
    const OSMetaClass * const meta = getMetaClassWithName(name);

    if (meta)
	return meta->checkMetaCast(in);

    return 0;
}

/*
OSMetaClass::checkMetaCast
    checkMetaCast(OSObject *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 OSObject::metaCast member function.

See also OSObject::metaCast

 */
OSObject *OSMetaClass::checkMetaCast(const OSObject *check) const
{
    const OSMetaClass * const toMeta = this;
    const OSMetaClass *fromMeta;

    for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClass) {
	if (toMeta == fromMeta)
	    return (OSObject *) check; // Discard const

	if (!fromMeta->superClass || (fromMeta->classSize & kSuperIsCString))
	    break;
    }

    return 0;
}

const OSMetaClass *OSMetaClass::getSuperClass() const
{
    return superClass;
}

unsigned int OSMetaClass::getInstanceCount() const
{
    return instanceCount;
}

void OSMetaClass::printInstanceCounts()
{
    OSCollectionIterator *classes;
    OSSymbol		 *className;
    OSMetaClass		 *meta;

    classes = OSCollectionIterator::withCollection(sAllClassesDict);
    if (!classes)
	return;

    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() );
    }
    printf("\n");
    classes->release();
}

OSDictionary * OSMetaClass::getClassDictionary()
{
    return sAllClassesDict;
}

bool OSMetaClass::serialize(OSSerialize *s) const
{
    OSDictionary *	dict;
    OSNumber *		off;
    bool		ok = false;

    if (s->previouslySerialized(this)) return true;

    dict = 0;// IODictionary::withCapacity(2);
    off = OSNumber::withNumber(getInstanceCount(), 32);

    if (dict) {
	dict->setObject("InstanceCount", off );
	ok = dict->serialize(s);
    } else if( off)
	ok = off->serialize(s);

    if (dict)
	dict->release();
    if (off)
	off->release();

    return ok;
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.