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