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	    IOLockLock(sAllClassesLock);
817	    reserved->instances->release();
818	    reserved->instances = 0;
819	    IOLockUnlock(sAllClassesLock);
820	}
821    }
822
823    if (!super) IOLockUnlock(sInstancesLock);
824}
825
826void
827OSMetaClass::applyToInstances(OSOrderedSet * set,
828			      OSMetaClassInstanceApplierFunction  applier,
829                              void * context)
830{
831    enum { 	    kLocalDepth = 24 };
832    unsigned int    _nextIndex[kLocalDepth];
833    OSOrderedSet *  _sets[kLocalDepth];
834    unsigned int *  nextIndex = &_nextIndex[0];
835    OSOrderedSet ** sets      = &_sets[0];
836    OSObject *      obj;
837    OSOrderedSet *  childSet;
838    unsigned int    maxDepth;
839    unsigned int    idx;
840    unsigned int    level;
841    bool            done;
842
843    maxDepth = sDeepestClass;
844    if (maxDepth > kLocalDepth)
845    {
846    	nextIndex = IONew(typeof(nextIndex[0]), maxDepth);
847    	sets      = IONew(typeof(sets[0]), maxDepth);
848    }
849    done = false;
850    level = 0;
851    idx = 0;
852    do
853    {
854	while (!done && (obj = set->getObject(idx++)))
855	{
856	    if ((childSet = OSDynamicCast(OSOrderedSet, obj)))
857	    {
858		if (level >= maxDepth) panic(">maxDepth");
859		sets[level] = set;
860		nextIndex[level] = idx;
861		level++;
862		set = childSet;
863		idx = 0;
864		break;
865	    }
866	    done = (*applier)(obj, context);
867	}
868	if (!obj)
869	{
870	    if (!done && level)
871	    {
872		level--;
873		set = sets[level];
874		idx = nextIndex[level];
875	    } else done = true;
876	}
877    }
878    while (!done);
879    if (maxDepth > kLocalDepth)
880    {
881    	IODelete(nextIndex, typeof(nextIndex[0]), maxDepth);
882    	IODelete(sets, typeof(sets[0]), maxDepth);
883    }
884}
885
886void
887OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier,
888                              void * context) const
889{
890    IOLockLock(sInstancesLock);
891    if (reserved->instances) applyToInstances(reserved->instances, applier, context);
892    IOLockUnlock(sInstancesLock);
893}
894
895void
896OSMetaClass::applyToInstancesOfClassName(
897    				const OSSymbol * name,
898    				OSMetaClassInstanceApplierFunction  applier,
899                                void * context)
900{
901    OSMetaClass  * meta;
902    OSOrderedSet * set = 0;
903
904    IOLockLock(sAllClassesLock);
905    if (sAllClassesDict
906    	&& (meta = (OSMetaClass *) sAllClassesDict->getObject(name))
907    	&& (set = meta->reserved->instances))
908    {
909    	set->retain();
910    }
911    IOLockUnlock(sAllClassesLock);
912
913    if (!set) return;
914
915    IOLockLock(sInstancesLock);
916    applyToInstances(set, applier, context);
917    IOLockUnlock(sInstancesLock);
918    set->release();
919}
920
921/*********************************************************************
922*********************************************************************/
923void
924OSMetaClass::considerUnloads()
925{
926    OSKext::considerUnloads();
927}
928
929/*********************************************************************
930*********************************************************************/
931const OSMetaClass *
932OSMetaClass::getMetaClassWithName(const OSSymbol * name)
933{
934    OSMetaClass * retMeta = 0;
935
936    if (!name) {
937        return 0;
938    }
939
940    IOLockLock(sAllClassesLock);
941    if (sAllClassesDict) {
942        retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
943    }
944    IOLockUnlock(sAllClassesLock);
945
946    return retMeta;
947}
948
949/*********************************************************************
950*********************************************************************/
951OSObject *
952OSMetaClass::allocClassWithName(const OSSymbol * name)
953{
954    OSObject * result = 0;
955
956    const OSMetaClass * const meta = getMetaClassWithName(name);
957
958    if (meta) {
959        result = meta->alloc();
960    }
961
962    return result;
963}
964
965/*********************************************************************
966*********************************************************************/
967OSObject *
968OSMetaClass::allocClassWithName(const OSString * name)
969{
970    const OSSymbol * tmpKey = OSSymbol::withString(name);
971    OSObject * result = allocClassWithName(tmpKey);
972    tmpKey->release();
973    return result;
974}
975
976/*********************************************************************
977*********************************************************************/
978OSObject *
979OSMetaClass::allocClassWithName(const char * name)
980{
981    const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name);
982    OSObject       * result = allocClassWithName(tmpKey);
983    tmpKey->release();
984    return result;
985}
986
987
988/*********************************************************************
989*********************************************************************/
990OSMetaClassBase *
991OSMetaClass::checkMetaCastWithName(
992    const OSSymbol        * name,
993    const OSMetaClassBase * in)
994{
995    OSMetaClassBase * result = 0;
996
997    const OSMetaClass * const meta = getMetaClassWithName(name);
998
999    if (meta) {
1000        result = meta->checkMetaCast(in);
1001    }
1002
1003    return result;
1004}
1005
1006/*********************************************************************
1007*********************************************************************/
1008OSMetaClassBase * OSMetaClass::
1009checkMetaCastWithName(
1010    const OSString        * name,
1011    const OSMetaClassBase * in)
1012{
1013    const OSSymbol  * tmpKey = OSSymbol::withString(name);
1014    OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
1015
1016    tmpKey->release();
1017    return result;
1018}
1019
1020/*********************************************************************
1021*********************************************************************/
1022OSMetaClassBase *
1023OSMetaClass::checkMetaCastWithName(
1024    const char            * name,
1025    const OSMetaClassBase * in)
1026{
1027    const OSSymbol  * tmpKey = OSSymbol::withCStringNoCopy(name);
1028    OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
1029
1030    tmpKey->release();
1031    return result;
1032}
1033
1034/*********************************************************************
1035 * OSMetaClass::checkMetaCast()
1036 * Check to see if the 'check' object has this object in its metaclass chain.
1037 * Returns check if it is indeed a kind of the current meta class, 0 otherwise.
1038 *
1039 * Generally this method is not invoked directly but is used to implement
1040 * the OSMetaClassBase::metaCast member function.
1041 *
1042 * See also OSMetaClassBase::metaCast
1043*********************************************************************/
1044OSMetaClassBase * OSMetaClass::checkMetaCast(
1045    const OSMetaClassBase * check) const
1046{
1047    const OSMetaClass * const toMeta   = this;
1048    const OSMetaClass *       fromMeta;
1049
1050    for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) {
1051        if (toMeta == fromMeta) {
1052            return const_cast<OSMetaClassBase *>(check); // Discard const
1053        }
1054        if (!fromMeta->superClassLink) {
1055            break;
1056        }
1057    }
1058
1059    return 0;
1060}
1061
1062/*********************************************************************
1063*********************************************************************/
1064void
1065OSMetaClass::reservedCalled(int ind) const
1066{
1067    const char * cname = className->getCStringNoCopy();
1068    panic("%s::_RESERVED%s%d called.", cname, cname, ind);
1069}
1070
1071/*********************************************************************
1072*********************************************************************/
1073const
1074OSMetaClass *
1075OSMetaClass::getSuperClass() const
1076{
1077    return superClassLink;
1078}
1079
1080/*********************************************************************
1081* xxx - I want to rename this :-/
1082*********************************************************************/
1083const OSSymbol *
1084OSMetaClass::getKmodName() const
1085{
1086    OSKext * myKext = reserved ? reserved->kext : 0;
1087    if (myKext) {
1088        return myKext->getIdentifier();
1089    }
1090    return OSSymbol::withCStringNoCopy("unknown");
1091}
1092
1093/*********************************************************************
1094*********************************************************************/
1095unsigned int
1096OSMetaClass::getInstanceCount() const
1097{
1098    return instanceCount;
1099}
1100
1101/*********************************************************************
1102*********************************************************************/
1103/* static */
1104void
1105OSMetaClass::printInstanceCounts()
1106{
1107    OSCollectionIterator * classes;
1108    OSSymbol             * className;
1109    OSMetaClass          * meta;
1110
1111    IOLockLock(sAllClassesLock);
1112    classes = OSCollectionIterator::withCollection(sAllClassesDict);
1113    assert(classes);
1114
1115    while( (className = (OSSymbol *)classes->getNextObject())) {
1116        meta = (OSMetaClass *)sAllClassesDict->getObject(className);
1117        assert(meta);
1118
1119        printf("%24s count: %03d x 0x%03x = 0x%06x\n",
1120            className->getCStringNoCopy(),
1121            meta->getInstanceCount(),
1122            meta->getClassSize(),
1123            meta->getInstanceCount() * meta->getClassSize() );
1124    }
1125    printf("\n");
1126    classes->release();
1127    IOLockUnlock(sAllClassesLock);
1128    return;
1129}
1130
1131/*********************************************************************
1132*********************************************************************/
1133OSDictionary *
1134OSMetaClass::getClassDictionary()
1135{
1136    panic("OSMetaClass::getClassDictionary() is obsoleted.\n");
1137    return 0;
1138}
1139
1140/*********************************************************************
1141*********************************************************************/
1142bool
1143OSMetaClass::serialize(__unused OSSerialize * s) const
1144{
1145    panic("OSMetaClass::serialize(): Obsoleted\n");
1146    return false;
1147}
1148
1149/*********************************************************************
1150*********************************************************************/
1151/* static */
1152void
1153OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary)
1154{
1155    OSDictionary * classDict = NULL;
1156
1157    IOLockLock(sAllClassesLock);
1158
1159    classDict = OSDictionary::withCapacity(sAllClassesDict->getCount());
1160    if (!classDict) {
1161        goto finish;
1162    }
1163
1164    do {
1165        OSCollectionIterator * classes;
1166        const OSSymbol * className;
1167
1168        classes = OSCollectionIterator::withCollection(sAllClassesDict);
1169        if (!classes) {
1170            break;
1171        }
1172
1173        while ((className = (const OSSymbol *)classes->getNextObject())) {
1174            const OSMetaClass * meta;
1175            OSNumber * count;
1176
1177            meta = (OSMetaClass *)sAllClassesDict->getObject(className);
1178            count = OSNumber::withNumber(meta->getInstanceCount(), 32);
1179            if (count) {
1180                classDict->setObject(className, count);
1181                count->release();
1182            }
1183        }
1184        classes->release();
1185
1186        serializeDictionary->setObject("Classes", classDict);
1187    } while (0);
1188
1189finish:
1190    OSSafeRelease(classDict);
1191
1192    IOLockUnlock(sAllClassesLock);
1193
1194    return;
1195}
1196