1/*
2 * Copyright (c) 2000-2006 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */
29
30#include <string.h>
31
32#include <libkern/OSReturn.h>
33
34#include <libkern/c++/OSMetaClass.h>
35#include <libkern/c++/OSObject.h>
36#include <libkern/c++/OSKext.h>
37
38#include <libkern/c++/OSCollectionIterator.h>
39#include <libkern/c++/OSDictionary.h>
40#include <libkern/c++/OSArray.h>
41#include <libkern/c++/OSSet.h>
42#include <libkern/c++/OSSymbol.h>
43#include <libkern/c++/OSNumber.h>
44#include <libkern/c++/OSSerialize.h>
45
46#include <libkern/c++/OSLib.h>
47#include <libkern/OSAtomic.h>
48
49#include <IOKit/IOLib.h>
50
51__BEGIN_DECLS
52
53#include <sys/systm.h>
54#include <mach/mach_types.h>
55#include <kern/locks.h>
56#include <kern/clock.h>
57#include <kern/thread_call.h>
58#include <kern/host.h>
59#include <mach/mach_interface.h>
60
61#if PRAGMA_MARK
62#pragma mark Macros
63#endif /* PRAGMA_MARK */
64/*********************************************************************
65* Macros
66*********************************************************************/
67#if OSALLOCDEBUG
68extern int debug_container_malloc_size;
69#define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while (0)
70#else
71#define ACCUMSIZE(s)
72#endif /* OSALLOCDEBUG */
73
74__END_DECLS
75
76#if PRAGMA_MARK
77#pragma mark Internal constants & data structs
78#endif /* PRAGMA_MARK */
79/*********************************************************************
80* Internal constants & data structs
81*********************************************************************/
82OSKextLogSpec kOSMetaClassLogSpec =
83    kOSKextLogErrorLevel |
84    kOSKextLogLoadFlag |
85    kOSKextLogKextBookkeepingFlag;
86
87static enum {
88    kCompletedBootstrap = 0,
89    kNoDictionaries     = 1,
90    kMakingDictionaries = 2
91} sBootstrapState = kNoDictionaries;
92
93static const int      kClassCapacityIncrement = 40;
94static const int      kKModCapacityIncrement  = 10;
95static OSDictionary * sAllClassesDict;
96static unsigned int   sDeepestClass;
97IOLock              * sAllClassesLock = NULL;
98IOLock              * sInstancesLock  = NULL;
99
100/*
101 * While loading a kext and running all its constructors to register
102 * all OSMetaClass classes, the classes are queued up here. Only one
103 * kext can be in flight at a time, guarded by sStalledClassesLock
104 */
105static struct StalledData {
106    const char   * kextIdentifier;
107    OSReturn       result;
108    unsigned int   capacity;
109    unsigned int   count;
110    OSMetaClass ** classes;
111} * sStalled;
112IOLock * sStalledClassesLock = NULL;
113
114
115struct ExpansionData {
116    OSOrderedSet * instances;
117    OSKext *       kext;
118};
119
120
121#if PRAGMA_MARK
122#pragma mark OSMetaClassBase
123#endif /* PRAGMA_MARK */
124/*********************************************************************
125* OSMetaClassBase.
126*********************************************************************/
127
128#if APPLE_KEXT_VTABLE_PADDING
129/*********************************************************************
130* Reserved vtable functions.
131*********************************************************************/
132#if SLOT_USED
133void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
134    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0); }
135void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
136    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1); }
137void OSMetaClassBase::_RESERVEDOSMetaClassBase2()
138    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 2); }
139#endif /* SLOT_USED */
140
141// As these slots are used move them up inside the #if above
142void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
143    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3); }
144void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
145    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4); }
146void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
147    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); }
148void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
149    { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 6); }
150#endif
151
152/*********************************************************************
153* These used to be inline in the header but gcc didn't believe us
154* Now we MUST pull the inline out at least until the compiler is
155* repaired.
156*
157* Helper inlines for runtime type preprocessor macros
158*********************************************************************/
159
160/*********************************************************************
161*********************************************************************/
162OSMetaClassBase *
163OSMetaClassBase::safeMetaCast(
164    const OSMetaClassBase * me,
165    const OSMetaClass     * toType)
166{
167    return (me)? me->metaCast(toType) : 0;
168}
169
170/*********************************************************************
171*********************************************************************/
172bool
173OSMetaClassBase::checkTypeInst(
174    const OSMetaClassBase * inst,
175    const OSMetaClassBase * typeinst)
176{
177    const OSMetaClass * toType = OSTypeIDInst(typeinst);
178    return typeinst && inst && (0 != inst->metaCast(toType));
179}
180
181/*********************************************************************
182*********************************************************************/
183void OSMetaClassBase::
184initialize()
185{
186    sAllClassesLock = IOLockAlloc();
187    sStalledClassesLock = IOLockAlloc();
188    sInstancesLock = IOLockAlloc();
189}
190
191#if APPLE_KEXT_VTABLE_PADDING
192/*********************************************************************
193* If you need this slot you had better setup an IOCTL style interface.
194* 'Cause the whole kernel world depends on OSMetaClassBase and YOU
195* CANT change the VTABLE size ever.
196*********************************************************************/
197void
198OSMetaClassBase::_RESERVEDOSMetaClassBase7()
199{ panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); }
200#endif
201
202/*********************************************************************
203*********************************************************************/
204OSMetaClassBase::OSMetaClassBase()
205{
206}
207
208/*********************************************************************
209*********************************************************************/
210OSMetaClassBase::~OSMetaClassBase()
211{
212    void ** thisVTable;
213
214    thisVTable = (void **) this;
215    *thisVTable = (void *) -1UL;
216}
217
218/*********************************************************************
219*********************************************************************/
220bool
221OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const
222{
223    return this == anObj;
224}
225
226/*********************************************************************
227*********************************************************************/
228OSMetaClassBase *
229OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const
230{
231    return toMeta->checkMetaCast(this);
232}
233
234/*********************************************************************
235*********************************************************************/
236OSMetaClassBase *
237OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const
238{
239    return OSMetaClass::checkMetaCastWithName(toMetaSymb, this);
240}
241
242/*********************************************************************
243*********************************************************************/
244OSMetaClassBase *
245OSMetaClassBase::metaCast(const OSString * toMetaStr) const
246{
247    const OSSymbol  * tempSymb = OSSymbol::withString(toMetaStr);
248    OSMetaClassBase * ret = 0;
249    if (tempSymb) {
250        ret = metaCast(tempSymb);
251        tempSymb->release();
252    }
253    return ret;
254}
255
256/*********************************************************************
257*********************************************************************/
258OSMetaClassBase *
259OSMetaClassBase::metaCast(const char * toMetaCStr) const
260{
261    const OSSymbol  * tempSymb = OSSymbol::withCString(toMetaCStr);
262    OSMetaClassBase * ret = 0;
263    if (tempSymb) {
264        ret = metaCast(tempSymb);
265        tempSymb->release();
266    }
267    return ret;
268}
269
270#if PRAGMA_MARK
271#pragma mark OSMetaClassMeta
272#endif /* PRAGMA_MARK */
273/*********************************************************************
274* OSMetaClassMeta - the bootstrap metaclass of OSMetaClass
275*********************************************************************/
276class OSMetaClassMeta : public OSMetaClass
277{
278public:
279    OSMetaClassMeta();
280    OSObject * alloc() const;
281};
282OSMetaClassMeta::OSMetaClassMeta()
283    : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass))
284    { }
285OSObject * OSMetaClassMeta::alloc() const { return 0; }
286
287static OSMetaClassMeta sOSMetaClassMeta;
288
289const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta;
290const OSMetaClass * OSMetaClass::getMetaClass() const
291    { return &sOSMetaClassMeta; }
292
293#if PRAGMA_MARK
294#pragma mark OSMetaClass
295#endif /* PRAGMA_MARK */
296/*********************************************************************
297* OSMetaClass
298*********************************************************************/
299
300#if APPLE_KEXT_VTABLE_PADDING
301/*********************************************************************
302* Reserved functions.
303*********************************************************************/
304void OSMetaClass::_RESERVEDOSMetaClass0()
305    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0); }
306void OSMetaClass::_RESERVEDOSMetaClass1()
307    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1); }
308void OSMetaClass::_RESERVEDOSMetaClass2()
309    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2); }
310void OSMetaClass::_RESERVEDOSMetaClass3()
311    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3); }
312void OSMetaClass::_RESERVEDOSMetaClass4()
313    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4); }
314void OSMetaClass::_RESERVEDOSMetaClass5()
315    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5); }
316void OSMetaClass::_RESERVEDOSMetaClass6()
317    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); }
318void OSMetaClass::_RESERVEDOSMetaClass7()
319    { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); }
320#endif
321
322/*********************************************************************
323*********************************************************************/
324static void
325OSMetaClassLogErrorForKext(
326    OSReturn   error,
327    OSKext   * aKext)
328{
329    const char * message = NULL;
330
331    switch (error) {
332    case kOSReturnSuccess:
333        return;
334    case kOSMetaClassNoInit:  // xxx - never returned; logged at fail site
335        message = "OSMetaClass: preModLoad() wasn't called (runtime internal error).";
336        break;
337    case kOSMetaClassNoDicts:
338        message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries.";
339        break;
340    case kOSMetaClassNoKModSet:
341        message = "OSMetaClass: Allocation failure for internal kext recording set/set missing.";
342        break;
343    case kOSMetaClassNoInsKModSet:
344        message = "OSMetaClass: Failed to record class in kext.";
345        break;
346    case kOSMetaClassDuplicateClass:
347        message = "OSMetaClass: Duplicate class encountered.";
348        break;
349    case kOSMetaClassNoSuper:  // xxx - never returned
350        message = "OSMetaClass: Can't associate a class with its superclass.";
351        break;
352    case kOSMetaClassInstNoSuper:  // xxx - never returned
353        message = "OSMetaClass: Instance construction error; unknown superclass.";
354        break;
355    case kOSMetaClassNoKext:
356        message = "OSMetaClass: Kext not found for metaclass.";
357        break;
358    case kOSMetaClassInternal:
359    default:
360        message = "OSMetaClass: Runtime internal error.";
361        break;
362    }
363
364    if (message) {
365        OSKextLog(aKext, kOSMetaClassLogSpec, "%s", message);
366    }
367    return;
368}
369
370void
371OSMetaClass::logError(OSReturn error)
372{
373    OSMetaClassLogErrorForKext(error, NULL);
374}
375
376/*********************************************************************
377* The core constructor for a MetaClass (defined with this name always
378* but within the scope of its represented class).
379*
380* MetaClass constructors are invoked in OSRuntimeInitializeCPP(),
381* in between calls to OSMetaClass::preModLoad(), which sets up for
382* registration, and OSMetaClass::postModLoad(), which actually
383* records all the class/kext relationships of the new MetaClasses.
384*********************************************************************/
385OSMetaClass::OSMetaClass(
386    const char        * inClassName,
387    const OSMetaClass * inSuperClass,
388    unsigned int        inClassSize)
389{
390    instanceCount = 0;
391    classSize = inClassSize;
392    superClassLink = inSuperClass;
393
394    reserved = IONew(ExpansionData, 1);
395    bzero(reserved, sizeof(ExpansionData));
396
397   /* Hack alert: We are just casting inClassName and storing it in
398    * an OSString * instance variable. This may be because you can't
399    * create C++ objects in static constructors, but I really don't know!
400    */
401    className = (const OSSymbol *)inClassName;
402
403    // sStalledClassesLock taken in preModLoad
404    if (!sStalled) {
405       /* There's no way we can look up the kext here, unfortunately.
406        */
407        OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
408            "OSMetaClass: preModLoad() wasn't called for class %s "
409            "(runtime internal error).",
410            inClassName);
411    } else if (!sStalled->result) {
412        // Grow stalled array if neccessary
413        if (sStalled->count >= sStalled->capacity) {
414            OSMetaClass **oldStalled = sStalled->classes;
415            int oldSize = sStalled->capacity * sizeof(OSMetaClass *);
416            int newSize = oldSize
417                + kKModCapacityIncrement * sizeof(OSMetaClass *);
418
419            sStalled->classes = (OSMetaClass **)kalloc(newSize);
420            if (!sStalled->classes) {
421                sStalled->classes = oldStalled;
422                sStalled->result = kOSMetaClassNoTempData;
423                return;
424            }
425
426            sStalled->capacity += kKModCapacityIncrement;
427            memmove(sStalled->classes, oldStalled, oldSize);
428            kfree(oldStalled, oldSize);
429            ACCUMSIZE(newSize - oldSize);
430        }
431
432        sStalled->classes[sStalled->count++] = this;
433    }
434}
435
436/*********************************************************************
437*********************************************************************/
438OSMetaClass::~OSMetaClass()
439{
440    OSKext * myKext = reserved ? reserved->kext : 0; // do not release
441
442   /* Hack alert: 'className' is a C string during early C++ init, and
443    * is converted to a real OSSymbol only when we record the OSKext in
444    * OSMetaClass::postModLoad(). So only do this bit if we have an OSKext.
445    * We can't safely cast or check 'className'.
446    *
447    * Also, release className *after* calling into the kext,
448    * as removeClass() may access className.
449    */
450    IOLockLock(sAllClassesLock);
451    if (sAllClassesDict) {
452        if (myKext) {
453            sAllClassesDict->removeObject(className);
454        } else {
455            sAllClassesDict->removeObject((char *)className);
456        }
457    }
458    IOLockUnlock(sAllClassesLock);
459
460    if (myKext) {
461        if (myKext->removeClass(this) != kOSReturnSuccess) {
462            // xxx - what can we do?
463        }
464        className->release();
465    }
466
467    // sStalledClassesLock taken in preModLoad
468    if (sStalled) {
469        unsigned int i;
470
471       /* First pass find class in stalled list. If we find it that means
472        * we started C++ init with constructors but now we're tearing down
473        * because of some failure.
474        */
475        for (i = 0; i < sStalled->count; i++) {
476            if (this == sStalled->classes[i]) {
477                break;
478            }
479        }
480
481       /* Remove this metaclass from the stalled list so postModLoad() doesn't
482        * try to register it.
483        */
484        if (i < sStalled->count) {
485            sStalled->count--;
486            if (i < sStalled->count) {
487                memmove(&sStalled->classes[i], &sStalled->classes[i+1],
488                    (sStalled->count - i) * sizeof(OSMetaClass *));
489            }
490        }
491    }
492}
493
494/*********************************************************************
495* Empty overrides.
496*********************************************************************/
497void * OSMetaClass::operator new(__unused size_t size) { return 0; }
498void OSMetaClass::retain() const { }
499void OSMetaClass::release() const { }
500void OSMetaClass::release(__unused int when) const { }
501void OSMetaClass::taggedRetain(__unused const void * tag) const { }
502void OSMetaClass::taggedRelease(__unused const void * tag) const { }
503void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { }
504int  OSMetaClass::getRetainCount() const { return 0; }
505
506/*********************************************************************
507*********************************************************************/
508const char *
509OSMetaClass::getClassName() const
510{
511    if (!className) return NULL;
512    return className->getCStringNoCopy();
513}
514/*********************************************************************
515*********************************************************************/
516const OSSymbol *
517OSMetaClass::getClassNameSymbol() const
518{
519    return className;
520}
521/*********************************************************************
522*********************************************************************/
523unsigned int
524OSMetaClass::getClassSize() const
525{
526    return classSize;
527}
528
529/*********************************************************************
530*********************************************************************/
531void *
532OSMetaClass::preModLoad(const char * kextIdentifier)
533{
534    IOLockLock(sStalledClassesLock);
535
536    assert (sStalled == NULL);
537    sStalled = (StalledData *)kalloc(sizeof(* sStalled));
538    if (sStalled) {
539        sStalled->classes = (OSMetaClass **)
540            kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
541        if (!sStalled->classes) {
542            kfree(sStalled, sizeof(*sStalled));
543            return 0;
544        }
545        ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
546            sizeof(*sStalled));
547
548        sStalled->result   = kOSReturnSuccess;
549        sStalled->capacity = kKModCapacityIncrement;
550        sStalled->count    = 0;
551        sStalled->kextIdentifier = kextIdentifier;
552        bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *));
553    }
554
555    // keep sStalledClassesLock locked until postModLoad
556
557    return sStalled;
558}
559
560/*********************************************************************
561*********************************************************************/
562bool
563OSMetaClass::checkModLoad(void * loadHandle)
564{
565    return sStalled && loadHandle == sStalled &&
566        sStalled->result == kOSReturnSuccess;
567}
568
569/*********************************************************************
570*********************************************************************/
571OSReturn
572OSMetaClass::postModLoad(void * loadHandle)
573{
574    OSReturn         result     = kOSReturnSuccess;
575    OSSymbol       * myKextName = 0;  // must release
576    OSKext         * myKext     = 0;  // must release
577
578    if (!sStalled || loadHandle != sStalled) {
579        result = kOSMetaClassInternal;
580        goto finish;
581    }
582
583    if (sStalled->result) {
584        result = sStalled->result;
585    } else switch (sBootstrapState) {
586
587        case kNoDictionaries:
588            sBootstrapState = kMakingDictionaries;
589            // No break; fall through
590
591        case kMakingDictionaries:
592            sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
593            if (!sAllClassesDict) {
594                result = kOSMetaClassNoDicts;
595                break;
596            }
597            sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
598
599        // No break; fall through
600
601        case kCompletedBootstrap:
602        {
603            unsigned int i;
604            myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy(
605                sStalled->kextIdentifier));
606
607            if (!sStalled->count) {
608                break;  // Nothing to do so just get out
609            }
610
611            myKext = OSKext::lookupKextWithIdentifier(myKextName);
612            if (!myKext) {
613                result = kOSMetaClassNoKext;
614
615               /* Log this error here so we can include the kext name.
616                */
617                OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
618                    "OSMetaClass: Can't record classes for kext %s - kext not found.",
619                    sStalled->kextIdentifier);
620                break;
621            }
622
623           /* First pass checking classes aren't already loaded. If any already
624            * exist, we don't register any, and so we don't technically have
625            * to do any C++ teardown.
626            *
627            * Hack alert: me->className has been a C string until now.
628            * We only release the OSSymbol if we store the kext.
629            */
630            IOLockLock(sAllClassesLock);
631            for (i = 0; i < sStalled->count; i++) {
632                const OSMetaClass * me = sStalled->classes[i];
633                OSMetaClass * orig = OSDynamicCast(OSMetaClass,
634                    sAllClassesDict->getObject((const char *)me->className));
635
636                if (orig) {
637
638                   /* Log this error here so we can include the class name.
639                    * xxx - we should look up the other kext that defines the class
640                    */
641                    OSKextLog(myKext, kOSMetaClassLogSpec,
642                        "OSMetaClass: Kext %s class %s is a duplicate;"
643                        "kext %s already has a class by that name.",
644                         sStalled->kextIdentifier, (const char *)me->className,
645                        ((OSKext *)orig->reserved->kext)->getIdentifierCString());
646                    result = kOSMetaClassDuplicateClass;
647                    break;
648                }
649		unsigned int depth = 1;
650		while ((me = me->superClassLink)) depth++;
651		if (depth > sDeepestClass) sDeepestClass = depth;
652            }
653            IOLockUnlock(sAllClassesLock);
654
655           /* Bail if we didn't go through the entire list of new classes
656            * (if we hit a duplicate).
657            */
658            if (i != sStalled->count) {
659                break;
660            }
661
662            // Second pass symbolling strings and inserting classes in dictionary
663            IOLockLock(sAllClassesLock);
664            for (i = 0; i < sStalled->count; i++) {
665                OSMetaClass * me = sStalled->classes[i];
666
667               /* Hack alert: me->className has been a C string until now.
668                * We only release the OSSymbol in ~OSMetaClass()
669                * if we set the reference to the kext.
670                */
671                me->className =
672                    OSSymbol::withCStringNoCopy((const char *)me->className);
673
674                // xxx - I suppose if these fail we're going to panic soon....
675                sAllClassesDict->setObject(me->className, me);
676
677               /* Do not retain the kext object here.
678                */
679                me->reserved->kext = myKext;
680                if (myKext) {
681                    result = myKext->addClass(me, sStalled->count);
682                    if (result != kOSReturnSuccess) {
683                       /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */
684                        break;
685                    }
686                }
687            }
688            IOLockUnlock(sAllClassesLock);
689            sBootstrapState = kCompletedBootstrap;
690            break;
691        }
692
693        default:
694            result = kOSMetaClassInternal;
695            break;
696    }
697
698finish:
699   /* Don't call logError() for success or the conditions logged above
700    * or by called function.
701    */
702    if (result != kOSReturnSuccess &&
703        result != kOSMetaClassNoInsKModSet &&
704        result != kOSMetaClassDuplicateClass &&
705        result != kOSMetaClassNoKext) {
706
707        OSMetaClassLogErrorForKext(result, myKext);
708    }
709
710    OSSafeRelease(myKextName);
711    OSSafeRelease(myKext);
712
713    if (sStalled) {
714        ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
715            sizeof(*sStalled)));
716        kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *));
717        kfree(sStalled, sizeof(*sStalled));
718        sStalled = 0;
719    }
720
721    IOLockUnlock(sStalledClassesLock);
722
723    return result;
724}
725
726
727/*********************************************************************
728*********************************************************************/
729void
730OSMetaClass::instanceConstructed() const
731{
732    // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
733    if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) {
734        superClassLink->instanceConstructed();
735    }
736}
737
738/*********************************************************************
739*********************************************************************/
740void
741OSMetaClass::instanceDestructed() const
742{
743    if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) {
744        superClassLink->instanceDestructed();
745    }
746
747    if (((int)instanceCount) < 0) {
748        OSKext * myKext = reserved->kext;
749
750        OSKextLog(myKext, kOSMetaClassLogSpec,
751            // xxx - this phrasing is rather cryptic
752            "OSMetaClass: Class %s - bad retain (%d)",
753            getClassName(), instanceCount);
754    }
755}
756
757/*********************************************************************
758*********************************************************************/
759bool
760OSMetaClass::modHasInstance(const char * kextIdentifier)
761{
762    bool     result  = false;
763    OSKext * theKext = NULL;  // must release
764
765    theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
766    if (!theKext) {
767        goto finish;
768    }
769
770    result = theKext->hasOSMetaClassInstances();
771
772finish:
773    OSSafeRelease(theKext);
774    return result;
775}
776
777/*********************************************************************
778*********************************************************************/
779void
780OSMetaClass::reportModInstances(const char * kextIdentifier)
781{
782    OSKext::reportOSMetaClassInstances(kextIdentifier,
783        kOSKextLogExplicitLevel);
784    return;
785}
786/*********************************************************************
787*********************************************************************/
788
789void
790OSMetaClass::addInstance(const OSObject * instance, bool super) const
791{
792    if (!super) IOLockLock(sInstancesLock);
793
794    if (!reserved->instances) {
795	reserved->instances = OSOrderedSet::withCapacity(16);
796	if (superClassLink) {
797	    superClassLink->addInstance(reserved->instances, true);
798	}
799    }
800    reserved->instances->setLastObject(instance);
801
802    if (!super) IOLockUnlock(sInstancesLock);
803}
804
805void
806OSMetaClass::removeInstance(const OSObject * instance, bool super) const
807{
808    if (!super) IOLockLock(sInstancesLock);
809
810    if (reserved->instances) {
811	reserved->instances->removeObject(instance);
812	if (0 == reserved->instances->getCount()) {
813	    if (superClassLink) {
814		superClassLink->removeInstance(reserved->instances, true);
815	    }
816	    reserved->instances->release();
817	    reserved->instances = 0;
818	}
819    }
820
821    if (!super) IOLockUnlock(sInstancesLock);
822}
823
824void
825OSMetaClass::applyToInstances(OSOrderedSet * set,
826			      OSMetaClassInstanceApplierFunction  applier,
827                              void * context)
828{
829    enum { 	    kLocalDepth = 24 };
830    unsigned int    _nextIndex[kLocalDepth];
831    OSOrderedSet *  _sets[kLocalDepth];
832    unsigned int *  nextIndex = &_nextIndex[0];
833    OSOrderedSet ** sets      = &_sets[0];
834    OSObject *      obj;
835    OSOrderedSet *  childSet;
836    unsigned int    maxDepth;
837    unsigned int    idx;
838    unsigned int    level;
839    bool            done;
840
841    maxDepth = sDeepestClass;
842    if (maxDepth > kLocalDepth)
843    {
844    	nextIndex = IONew(typeof(nextIndex[0]), maxDepth);
845    	sets      = IONew(typeof(sets[0]), maxDepth);
846    }
847    done = false;
848    level = 0;
849    idx = 0;
850    do
851    {
852	while (!done && (obj = set->getObject(idx++)))
853	{
854	    if ((childSet = OSDynamicCast(OSOrderedSet, obj)))
855	    {
856		if (level >= maxDepth) panic(">maxDepth");
857		sets[level] = set;
858		nextIndex[level] = idx;
859		level++;
860		set = childSet;
861		idx = 0;
862		break;
863	    }
864	    done = (*applier)(obj, context);
865	}
866	if (!obj)
867	{
868	    if (!done && level)
869	    {
870		level--;
871		set = sets[level];
872		idx = nextIndex[level];
873	    } else done = true;
874	}
875    }
876    while (!done);
877    if (maxDepth > kLocalDepth)
878    {
879    	IODelete(nextIndex, typeof(nextIndex[0]), maxDepth);
880    	IODelete(sets, typeof(sets[0]), maxDepth);
881    }
882}
883
884void
885OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier,
886                              void * context) const
887{
888    IOLockLock(sInstancesLock);
889    if (reserved->instances) applyToInstances(reserved->instances, applier, context);
890    IOLockUnlock(sInstancesLock);
891}
892
893void
894OSMetaClass::applyToInstancesOfClassName(
895    				const OSSymbol * name,
896    				OSMetaClassInstanceApplierFunction  applier,
897                                void * context)
898{
899    OSMetaClass  * meta;
900    OSOrderedSet * set = 0;
901
902    IOLockLock(sAllClassesLock);
903    if (sAllClassesDict
904    	&& (meta = (OSMetaClass *) sAllClassesDict->getObject(name))
905    	&& (set = meta->reserved->instances))
906    {
907    	set->retain();
908    }
909    IOLockUnlock(sAllClassesLock);
910
911    if (!set) return;
912
913    IOLockLock(sInstancesLock);
914    applyToInstances(set, applier, context);
915    IOLockUnlock(sInstancesLock);
916    set->release();
917}
918
919/*********************************************************************
920*********************************************************************/
921void
922OSMetaClass::considerUnloads()
923{
924    OSKext::considerUnloads();
925}
926
927/*********************************************************************
928*********************************************************************/
929const OSMetaClass *
930OSMetaClass::getMetaClassWithName(const OSSymbol * name)
931{
932    OSMetaClass * retMeta = 0;
933
934    if (!name) {
935        return 0;
936    }
937
938    IOLockLock(sAllClassesLock);
939    if (sAllClassesDict) {
940        retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
941    }
942    IOLockUnlock(sAllClassesLock);
943
944    return retMeta;
945}
946
947/*********************************************************************
948*********************************************************************/
949OSObject *
950OSMetaClass::allocClassWithName(const OSSymbol * name)
951{
952    OSObject * result = 0;
953
954    const OSMetaClass * const meta = getMetaClassWithName(name);
955
956    if (meta) {
957        result = meta->alloc();
958    }
959
960    return result;
961}
962
963/*********************************************************************
964*********************************************************************/
965OSObject *
966OSMetaClass::allocClassWithName(const OSString * name)
967{
968    const OSSymbol * tmpKey = OSSymbol::withString(name);
969    OSObject * result = allocClassWithName(tmpKey);
970    tmpKey->release();
971    return result;
972}
973
974/*********************************************************************
975*********************************************************************/
976OSObject *
977OSMetaClass::allocClassWithName(const char * name)
978{
979    const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name);
980    OSObject       * result = allocClassWithName(tmpKey);
981    tmpKey->release();
982    return result;
983}
984
985
986/*********************************************************************
987*********************************************************************/
988OSMetaClassBase *
989OSMetaClass::checkMetaCastWithName(
990    const OSSymbol        * name,
991    const OSMetaClassBase * in)
992{
993    OSMetaClassBase * result = 0;
994
995    const OSMetaClass * const meta = getMetaClassWithName(name);
996
997    if (meta) {
998        result = meta->checkMetaCast(in);
999    }
1000
1001    return result;
1002}
1003
1004/*********************************************************************
1005*********************************************************************/
1006OSMetaClassBase * OSMetaClass::
1007checkMetaCastWithName(
1008    const OSString        * name,
1009    const OSMetaClassBase * in)
1010{
1011    const OSSymbol  * tmpKey = OSSymbol::withString(name);
1012    OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
1013
1014    tmpKey->release();
1015    return result;
1016}
1017
1018/*********************************************************************
1019*********************************************************************/
1020OSMetaClassBase *
1021OSMetaClass::checkMetaCastWithName(
1022    const char            * name,
1023    const OSMetaClassBase * in)
1024{
1025    const OSSymbol  * tmpKey = OSSymbol::withCStringNoCopy(name);
1026    OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
1027
1028    tmpKey->release();
1029    return result;
1030}
1031
1032/*********************************************************************
1033 * OSMetaClass::checkMetaCast()
1034 * Check to see if the 'check' object has this object in its metaclass chain.
1035 * Returns check if it is indeed a kind of the current meta class, 0 otherwise.
1036 *
1037 * Generally this method is not invoked directly but is used to implement
1038 * the OSMetaClassBase::metaCast member function.
1039 *
1040 * See also OSMetaClassBase::metaCast
1041*********************************************************************/
1042OSMetaClassBase * OSMetaClass::checkMetaCast(
1043    const OSMetaClassBase * check) const
1044{
1045    const OSMetaClass * const toMeta   = this;
1046    const OSMetaClass *       fromMeta;
1047
1048    for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) {
1049        if (toMeta == fromMeta) {
1050            return const_cast<OSMetaClassBase *>(check); // Discard const
1051        }
1052        if (!fromMeta->superClassLink) {
1053            break;
1054        }
1055    }
1056
1057    return 0;
1058}
1059
1060/*********************************************************************
1061*********************************************************************/
1062void
1063OSMetaClass::reservedCalled(int ind) const
1064{
1065    const char * cname = className->getCStringNoCopy();
1066    panic("%s::_RESERVED%s%d called.", cname, cname, ind);
1067}
1068
1069/*********************************************************************
1070*********************************************************************/
1071const
1072OSMetaClass *
1073OSMetaClass::getSuperClass() const
1074{
1075    return superClassLink;
1076}
1077
1078/*********************************************************************
1079* xxx - I want to rename this :-/
1080*********************************************************************/
1081const OSSymbol *
1082OSMetaClass::getKmodName() const
1083{
1084    OSKext * myKext = reserved ? reserved->kext : 0;
1085    if (myKext) {
1086        return myKext->getIdentifier();
1087    }
1088    return OSSymbol::withCStringNoCopy("unknown");
1089}
1090
1091/*********************************************************************
1092*********************************************************************/
1093unsigned int
1094OSMetaClass::getInstanceCount() const
1095{
1096    return instanceCount;
1097}
1098
1099/*********************************************************************
1100*********************************************************************/
1101/* static */
1102void
1103OSMetaClass::printInstanceCounts()
1104{
1105    OSCollectionIterator * classes;
1106    OSSymbol             * className;
1107    OSMetaClass          * meta;
1108
1109    IOLockLock(sAllClassesLock);
1110    classes = OSCollectionIterator::withCollection(sAllClassesDict);
1111    assert(classes);
1112
1113    while( (className = (OSSymbol *)classes->getNextObject())) {
1114        meta = (OSMetaClass *)sAllClassesDict->getObject(className);
1115        assert(meta);
1116
1117        printf("%24s count: %03d x 0x%03x = 0x%06x\n",
1118            className->getCStringNoCopy(),
1119            meta->getInstanceCount(),
1120            meta->getClassSize(),
1121            meta->getInstanceCount() * meta->getClassSize() );
1122    }
1123    printf("\n");
1124    classes->release();
1125    IOLockUnlock(sAllClassesLock);
1126    return;
1127}
1128
1129/*********************************************************************
1130*********************************************************************/
1131OSDictionary *
1132OSMetaClass::getClassDictionary()
1133{
1134    panic("OSMetaClass::getClassDictionary() is obsoleted.\n");
1135    return 0;
1136}
1137
1138/*********************************************************************
1139*********************************************************************/
1140bool
1141OSMetaClass::serialize(__unused OSSerialize * s) const
1142{
1143    panic("OSMetaClass::serialize(): Obsoleted\n");
1144    return false;
1145}
1146
1147/*********************************************************************
1148*********************************************************************/
1149/* static */
1150void
1151OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary)
1152{
1153    OSDictionary * classDict = NULL;
1154
1155    IOLockLock(sAllClassesLock);
1156
1157    classDict = OSDictionary::withCapacity(sAllClassesDict->getCount());
1158    if (!classDict) {
1159        goto finish;
1160    }
1161
1162    do {
1163        OSCollectionIterator * classes;
1164        const OSSymbol * className;
1165
1166        classes = OSCollectionIterator::withCollection(sAllClassesDict);
1167        if (!classes) {
1168            break;
1169        }
1170
1171        while ((className = (const OSSymbol *)classes->getNextObject())) {
1172            const OSMetaClass * meta;
1173            OSNumber * count;
1174
1175            meta = (OSMetaClass *)sAllClassesDict->getObject(className);
1176            count = OSNumber::withNumber(meta->getInstanceCount(), 32);
1177            if (count) {
1178                classDict->setObject(className, count);
1179                count->release();
1180            }
1181        }
1182        classes->release();
1183
1184        serializeDictionary->setObject("Classes", classDict);
1185    } while (0);
1186
1187finish:
1188    OSSafeRelease(classDict);
1189
1190    IOLockUnlock(sAllClassesLock);
1191
1192    return;
1193}
1194