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::retain() const { }
498void OSMetaClass::release() const { }
499void OSMetaClass::release(__unused int when) const { }
500void OSMetaClass::taggedRetain(__unused const void * tag) const { }
501void OSMetaClass::taggedRelease(__unused const void * tag) const { }
502void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { }
503int  OSMetaClass::getRetainCount() const { return 0; }
504
505/*********************************************************************
506*********************************************************************/
507const char *
508OSMetaClass::getClassName() const
509{
510    if (!className) return NULL;
511    return className->getCStringNoCopy();
512}
513/*********************************************************************
514*********************************************************************/
515const OSSymbol *
516OSMetaClass::getClassNameSymbol() const
517{
518    return className;
519}
520/*********************************************************************
521*********************************************************************/
522unsigned int
523OSMetaClass::getClassSize() const
524{
525    return classSize;
526}
527
528/*********************************************************************
529*********************************************************************/
530void *
531OSMetaClass::preModLoad(const char * kextIdentifier)
532{
533    IOLockLock(sStalledClassesLock);
534
535    assert (sStalled == NULL);
536    sStalled = (StalledData *)kalloc(sizeof(* sStalled));
537    if (sStalled) {
538        sStalled->classes = (OSMetaClass **)
539            kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
540        if (!sStalled->classes) {
541            kfree(sStalled, sizeof(*sStalled));
542            return 0;
543        }
544        ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
545            sizeof(*sStalled));
546
547        sStalled->result   = kOSReturnSuccess;
548        sStalled->capacity = kKModCapacityIncrement;
549        sStalled->count    = 0;
550        sStalled->kextIdentifier = kextIdentifier;
551        bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *));
552    }
553
554    // keep sStalledClassesLock locked until postModLoad
555
556    return sStalled;
557}
558
559/*********************************************************************
560*********************************************************************/
561bool
562OSMetaClass::checkModLoad(void * loadHandle)
563{
564    return sStalled && loadHandle == sStalled &&
565        sStalled->result == kOSReturnSuccess;
566}
567
568/*********************************************************************
569*********************************************************************/
570OSReturn
571OSMetaClass::postModLoad(void * loadHandle)
572{
573    OSReturn         result     = kOSReturnSuccess;
574    OSSymbol       * myKextName = 0;  // must release
575    OSKext         * myKext     = 0;  // must release
576
577    if (!sStalled || loadHandle != sStalled) {
578        result = kOSMetaClassInternal;
579        goto finish;
580    }
581
582    if (sStalled->result) {
583        result = sStalled->result;
584    } else switch (sBootstrapState) {
585
586        case kNoDictionaries:
587            sBootstrapState = kMakingDictionaries;
588            // No break; fall through
589
590        case kMakingDictionaries:
591            sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
592            if (!sAllClassesDict) {
593                result = kOSMetaClassNoDicts;
594                break;
595            }
596            sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
597
598        // No break; fall through
599
600        case kCompletedBootstrap:
601        {
602            unsigned int i;
603            myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy(
604                sStalled->kextIdentifier));
605
606            if (!sStalled->count) {
607                break;  // Nothing to do so just get out
608            }
609
610            myKext = OSKext::lookupKextWithIdentifier(myKextName);
611            if (!myKext) {
612                result = kOSMetaClassNoKext;
613
614               /* Log this error here so we can include the kext name.
615                */
616                OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
617                    "OSMetaClass: Can't record classes for kext %s - kext not found.",
618                    sStalled->kextIdentifier);
619                break;
620            }
621
622           /* First pass checking classes aren't already loaded. If any already
623            * exist, we don't register any, and so we don't technically have
624            * to do any C++ teardown.
625            *
626            * Hack alert: me->className has been a C string until now.
627            * We only release the OSSymbol if we store the kext.
628            */
629            IOLockLock(sAllClassesLock);
630            for (i = 0; i < sStalled->count; i++) {
631                const OSMetaClass * me = sStalled->classes[i];
632                OSMetaClass * orig = OSDynamicCast(OSMetaClass,
633                    sAllClassesDict->getObject((const char *)me->className));
634
635                if (orig) {
636
637                   /* Log this error here so we can include the class name.
638                    * xxx - we should look up the other kext that defines the class
639                    */
640                    OSKextLog(myKext, kOSMetaClassLogSpec,
641                        "OSMetaClass: Kext %s class %s is a duplicate;"
642                        "kext %s already has a class by that name.",
643                         sStalled->kextIdentifier, (const char *)me->className,
644                        ((OSKext *)orig->reserved->kext)->getIdentifierCString());
645                    result = kOSMetaClassDuplicateClass;
646                    break;
647                }
648		unsigned int depth = 1;
649		while ((me = me->superClassLink)) depth++;
650		if (depth > sDeepestClass) sDeepestClass = depth;
651            }
652            IOLockUnlock(sAllClassesLock);
653
654           /* Bail if we didn't go through the entire list of new classes
655            * (if we hit a duplicate).
656            */
657            if (i != sStalled->count) {
658                break;
659            }
660
661            // Second pass symbolling strings and inserting classes in dictionary
662            IOLockLock(sAllClassesLock);
663            for (i = 0; i < sStalled->count; i++) {
664                OSMetaClass * me = sStalled->classes[i];
665
666               /* Hack alert: me->className has been a C string until now.
667                * We only release the OSSymbol in ~OSMetaClass()
668                * if we set the reference to the kext.
669                */
670                me->className =
671                    OSSymbol::withCStringNoCopy((const char *)me->className);
672
673                // xxx - I suppose if these fail we're going to panic soon....
674                sAllClassesDict->setObject(me->className, me);
675
676               /* Do not retain the kext object here.
677                */
678                me->reserved->kext = myKext;
679                if (myKext) {
680                    result = myKext->addClass(me, sStalled->count);
681                    if (result != kOSReturnSuccess) {
682                       /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */
683                        break;
684                    }
685                }
686            }
687            IOLockUnlock(sAllClassesLock);
688            sBootstrapState = kCompletedBootstrap;
689            break;
690        }
691
692        default:
693            result = kOSMetaClassInternal;
694            break;
695    }
696
697finish:
698   /* Don't call logError() for success or the conditions logged above
699    * or by called function.
700    */
701    if (result != kOSReturnSuccess &&
702        result != kOSMetaClassNoInsKModSet &&
703        result != kOSMetaClassDuplicateClass &&
704        result != kOSMetaClassNoKext) {
705
706        OSMetaClassLogErrorForKext(result, myKext);
707    }
708
709    OSSafeRelease(myKextName);
710    OSSafeRelease(myKext);
711
712    if (sStalled) {
713        ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
714            sizeof(*sStalled)));
715        kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *));
716        kfree(sStalled, sizeof(*sStalled));
717        sStalled = 0;
718    }
719
720    IOLockUnlock(sStalledClassesLock);
721
722    return result;
723}
724
725
726/*********************************************************************
727*********************************************************************/
728void
729OSMetaClass::instanceConstructed() const
730{
731    // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
732    if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) {
733        superClassLink->instanceConstructed();
734    }
735}
736
737/*********************************************************************
738*********************************************************************/
739void
740OSMetaClass::instanceDestructed() const
741{
742    if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) {
743        superClassLink->instanceDestructed();
744    }
745
746    if (((int)instanceCount) < 0) {
747        OSKext * myKext = reserved->kext;
748
749        OSKextLog(myKext, kOSMetaClassLogSpec,
750            // xxx - this phrasing is rather cryptic
751            "OSMetaClass: Class %s - bad retain (%d)",
752            getClassName(), instanceCount);
753    }
754}
755
756/*********************************************************************
757*********************************************************************/
758bool
759OSMetaClass::modHasInstance(const char * kextIdentifier)
760{
761    bool     result  = false;
762    OSKext * theKext = NULL;  // must release
763
764    theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
765    if (!theKext) {
766        goto finish;
767    }
768
769    result = theKext->hasOSMetaClassInstances();
770
771finish:
772    OSSafeRelease(theKext);
773    return result;
774}
775
776/*********************************************************************
777*********************************************************************/
778void
779OSMetaClass::reportModInstances(const char * kextIdentifier)
780{
781    OSKext::reportOSMetaClassInstances(kextIdentifier,
782        kOSKextLogExplicitLevel);
783    return;
784}
785/*********************************************************************
786*********************************************************************/
787
788void
789OSMetaClass::addInstance(const OSObject * instance, bool super) const
790{
791    if (!super) IOLockLock(sInstancesLock);
792
793    if (!reserved->instances) {
794	reserved->instances = OSOrderedSet::withCapacity(16);
795	if (superClassLink) {
796	    superClassLink->addInstance(reserved->instances, true);
797	}
798    }
799    reserved->instances->setLastObject(instance);
800
801    if (!super) IOLockUnlock(sInstancesLock);
802}
803
804void
805OSMetaClass::removeInstance(const OSObject * instance, bool super) const
806{
807    if (!super) IOLockLock(sInstancesLock);
808
809    if (reserved->instances) {
810	reserved->instances->removeObject(instance);
811	if (0 == reserved->instances->getCount()) {
812	    if (superClassLink) {
813		superClassLink->removeInstance(reserved->instances, true);
814	    }
815	    IOLockLock(sAllClassesLock);
816	    reserved->instances->release();
817	    reserved->instances = 0;
818	    IOLockUnlock(sAllClassesLock);
819	}
820    }
821
822    if (!super) IOLockUnlock(sInstancesLock);
823}
824
825void
826OSMetaClass::applyToInstances(OSOrderedSet * set,
827			      OSMetaClassInstanceApplierFunction  applier,
828                              void * context)
829{
830    enum { 	    kLocalDepth = 24 };
831    unsigned int    _nextIndex[kLocalDepth];
832    OSOrderedSet *  _sets[kLocalDepth];
833    unsigned int *  nextIndex = &_nextIndex[0];
834    OSOrderedSet ** sets      = &_sets[0];
835    OSObject *      obj;
836    OSOrderedSet *  childSet;
837    unsigned int    maxDepth;
838    unsigned int    idx;
839    unsigned int    level;
840    bool            done;
841
842    maxDepth = sDeepestClass;
843    if (maxDepth > kLocalDepth)
844    {
845    	nextIndex = IONew(typeof(nextIndex[0]), maxDepth);
846    	sets      = IONew(typeof(sets[0]), maxDepth);
847    }
848    done = false;
849    level = 0;
850    idx = 0;
851    do
852    {
853	while (!done && (obj = set->getObject(idx++)))
854	{
855	    if ((childSet = OSDynamicCast(OSOrderedSet, obj)))
856	    {
857		if (level >= maxDepth) panic(">maxDepth");
858		sets[level] = set;
859		nextIndex[level] = idx;
860		level++;
861		set = childSet;
862		idx = 0;
863		break;
864	    }
865	    done = (*applier)(obj, context);
866	}
867	if (!obj)
868	{
869	    if (!done && level)
870	    {
871		level--;
872		set = sets[level];
873		idx = nextIndex[level];
874	    } else done = true;
875	}
876    }
877    while (!done);
878    if (maxDepth > kLocalDepth)
879    {
880    	IODelete(nextIndex, typeof(nextIndex[0]), maxDepth);
881    	IODelete(sets, typeof(sets[0]), maxDepth);
882    }
883}
884
885void
886OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier,
887                              void * context) const
888{
889    IOLockLock(sInstancesLock);
890    if (reserved->instances) applyToInstances(reserved->instances, applier, context);
891    IOLockUnlock(sInstancesLock);
892}
893
894void
895OSMetaClass::applyToInstancesOfClassName(
896    				const OSSymbol * name,
897    				OSMetaClassInstanceApplierFunction  applier,
898                                void * context)
899{
900    OSMetaClass  * meta;
901    OSOrderedSet * set = 0;
902
903    IOLockLock(sAllClassesLock);
904    if (sAllClassesDict
905    	&& (meta = (OSMetaClass *) sAllClassesDict->getObject(name))
906    	&& (set = meta->reserved->instances))
907    {
908    	set->retain();
909    }
910    IOLockUnlock(sAllClassesLock);
911
912    if (!set) return;
913
914    IOLockLock(sInstancesLock);
915    applyToInstances(set, applier, context);
916    IOLockUnlock(sInstancesLock);
917    set->release();
918}
919
920/*********************************************************************
921*********************************************************************/
922void
923OSMetaClass::considerUnloads()
924{
925    OSKext::considerUnloads();
926}
927
928/*********************************************************************
929*********************************************************************/
930const OSMetaClass *
931OSMetaClass::getMetaClassWithName(const OSSymbol * name)
932{
933    OSMetaClass * retMeta = 0;
934
935    if (!name) {
936        return 0;
937    }
938
939    IOLockLock(sAllClassesLock);
940    if (sAllClassesDict) {
941        retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
942    }
943    IOLockUnlock(sAllClassesLock);
944
945    return retMeta;
946}
947
948/*********************************************************************
949*********************************************************************/
950OSObject *
951OSMetaClass::allocClassWithName(const OSSymbol * name)
952{
953    OSObject * result = 0;
954
955    const OSMetaClass * const meta = getMetaClassWithName(name);
956
957    if (meta) {
958        result = meta->alloc();
959    }
960
961    return result;
962}
963
964/*********************************************************************
965*********************************************************************/
966OSObject *
967OSMetaClass::allocClassWithName(const OSString * name)
968{
969    const OSSymbol * tmpKey = OSSymbol::withString(name);
970    OSObject * result = allocClassWithName(tmpKey);
971    tmpKey->release();
972    return result;
973}
974
975/*********************************************************************
976*********************************************************************/
977OSObject *
978OSMetaClass::allocClassWithName(const char * name)
979{
980    const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name);
981    OSObject       * result = allocClassWithName(tmpKey);
982    tmpKey->release();
983    return result;
984}
985
986
987/*********************************************************************
988*********************************************************************/
989OSMetaClassBase *
990OSMetaClass::checkMetaCastWithName(
991    const OSSymbol        * name,
992    const OSMetaClassBase * in)
993{
994    OSMetaClassBase * result = 0;
995
996    const OSMetaClass * const meta = getMetaClassWithName(name);
997
998    if (meta) {
999        result = meta->checkMetaCast(in);
1000    }
1001
1002    return result;
1003}
1004
1005/*********************************************************************
1006*********************************************************************/
1007OSMetaClassBase * OSMetaClass::
1008checkMetaCastWithName(
1009    const OSString        * name,
1010    const OSMetaClassBase * in)
1011{
1012    const OSSymbol  * tmpKey = OSSymbol::withString(name);
1013    OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
1014
1015    tmpKey->release();
1016    return result;
1017}
1018
1019/*********************************************************************
1020*********************************************************************/
1021OSMetaClassBase *
1022OSMetaClass::checkMetaCastWithName(
1023    const char            * name,
1024    const OSMetaClassBase * in)
1025{
1026    const OSSymbol  * tmpKey = OSSymbol::withCStringNoCopy(name);
1027    OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
1028
1029    tmpKey->release();
1030    return result;
1031}
1032
1033/*********************************************************************
1034 * OSMetaClass::checkMetaCast()
1035 * Check to see if the 'check' object has this object in its metaclass chain.
1036 * Returns check if it is indeed a kind of the current meta class, 0 otherwise.
1037 *
1038 * Generally this method is not invoked directly but is used to implement
1039 * the OSMetaClassBase::metaCast member function.
1040 *
1041 * See also OSMetaClassBase::metaCast
1042*********************************************************************/
1043OSMetaClassBase * OSMetaClass::checkMetaCast(
1044    const OSMetaClassBase * check) const
1045{
1046    const OSMetaClass * const toMeta   = this;
1047    const OSMetaClass *       fromMeta;
1048
1049    for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) {
1050        if (toMeta == fromMeta) {
1051            return const_cast<OSMetaClassBase *>(check); // Discard const
1052        }
1053        if (!fromMeta->superClassLink) {
1054            break;
1055        }
1056    }
1057
1058    return 0;
1059}
1060
1061/*********************************************************************
1062*********************************************************************/
1063void
1064OSMetaClass::reservedCalled(int ind) const
1065{
1066    const char * cname = className->getCStringNoCopy();
1067    panic("%s::_RESERVED%s%d called.", cname, cname, ind);
1068}
1069
1070/*********************************************************************
1071*********************************************************************/
1072const
1073OSMetaClass *
1074OSMetaClass::getSuperClass() const
1075{
1076    return superClassLink;
1077}
1078
1079/*********************************************************************
1080* xxx - I want to rename this :-/
1081*********************************************************************/
1082const OSSymbol *
1083OSMetaClass::getKmodName() const
1084{
1085    OSKext * myKext = reserved ? reserved->kext : 0;
1086    if (myKext) {
1087        return myKext->getIdentifier();
1088    }
1089    return OSSymbol::withCStringNoCopy("unknown");
1090}
1091
1092/*********************************************************************
1093*********************************************************************/
1094unsigned int
1095OSMetaClass::getInstanceCount() const
1096{
1097    return instanceCount;
1098}
1099
1100/*********************************************************************
1101*********************************************************************/
1102/* static */
1103void
1104OSMetaClass::printInstanceCounts()
1105{
1106    OSCollectionIterator * classes;
1107    OSSymbol             * className;
1108    OSMetaClass          * meta;
1109
1110    IOLockLock(sAllClassesLock);
1111    classes = OSCollectionIterator::withCollection(sAllClassesDict);
1112    assert(classes);
1113
1114    while( (className = (OSSymbol *)classes->getNextObject())) {
1115        meta = (OSMetaClass *)sAllClassesDict->getObject(className);
1116        assert(meta);
1117
1118        printf("%24s count: %03d x 0x%03x = 0x%06x\n",
1119            className->getCStringNoCopy(),
1120            meta->getInstanceCount(),
1121            meta->getClassSize(),
1122            meta->getInstanceCount() * meta->getClassSize() );
1123    }
1124    printf("\n");
1125    classes->release();
1126    IOLockUnlock(sAllClassesLock);
1127    return;
1128}
1129
1130/*********************************************************************
1131*********************************************************************/
1132OSDictionary *
1133OSMetaClass::getClassDictionary()
1134{
1135    panic("OSMetaClass::getClassDictionary() is obsoleted.\n");
1136    return 0;
1137}
1138
1139/*********************************************************************
1140*********************************************************************/
1141bool
1142OSMetaClass::serialize(__unused OSSerialize * s) const
1143{
1144    panic("OSMetaClass::serialize(): Obsoleted\n");
1145    return false;
1146}
1147
1148/*********************************************************************
1149*********************************************************************/
1150/* static */
1151void
1152OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary)
1153{
1154    OSDictionary * classDict = NULL;
1155
1156    IOLockLock(sAllClassesLock);
1157
1158    classDict = OSDictionary::withCapacity(sAllClassesDict->getCount());
1159    if (!classDict) {
1160        goto finish;
1161    }
1162
1163    do {
1164        OSCollectionIterator * classes;
1165        const OSSymbol * className;
1166
1167        classes = OSCollectionIterator::withCollection(sAllClassesDict);
1168        if (!classes) {
1169            break;
1170        }
1171
1172        while ((className = (const OSSymbol *)classes->getNextObject())) {
1173            const OSMetaClass * meta;
1174            OSNumber * count;
1175
1176            meta = (OSMetaClass *)sAllClassesDict->getObject(className);
1177            count = OSNumber::withNumber(meta->getInstanceCount(), 32);
1178            if (count) {
1179                classDict->setObject(className, count);
1180                count->release();
1181            }
1182        }
1183        classes->release();
1184
1185        serializeDictionary->setObject("Classes", classDict);
1186    } while (0);
1187
1188finish:
1189    OSSafeRelease(classDict);
1190
1191    IOLockUnlock(sAllClassesLock);
1192
1193    return;
1194}
1195