xref: /xnu-11215/libkern/c++/OSMetaClass.cpp (revision 186b8fce)
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
68 extern 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 *********************************************************************/
82 OSKextLogSpec kOSMetaClassLogSpec =
83     kOSKextLogErrorLevel |
84     kOSKextLogLoadFlag |
85     kOSKextLogKextBookkeepingFlag;
86 
87 static enum {
88     kCompletedBootstrap = 0,
89     kNoDictionaries     = 1,
90     kMakingDictionaries = 2
91 } sBootstrapState = kNoDictionaries;
92 
93 static const int      kClassCapacityIncrement = 40;
94 static const int      kKModCapacityIncrement  = 10;
95 static OSDictionary * sAllClassesDict;
96 static unsigned int   sDeepestClass;
97 IOLock              * sAllClassesLock = NULL;
98 IOLock              * 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  */
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 
115 struct 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
133 void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
134     { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0); }
135 void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
136     { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1); }
137 void 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
142 void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
143     { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3); }
144 void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
145     { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4); }
146 void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
147     { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); }
148 void 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 *********************************************************************/
162 OSMetaClassBase *
163 OSMetaClassBase::safeMetaCast(
164     const OSMetaClassBase * me,
165     const OSMetaClass     * toType)
166 {
167     return (me)? me->metaCast(toType) : 0;
168 }
169 
170 /*********************************************************************
171 *********************************************************************/
172 bool
173 OSMetaClassBase::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 *********************************************************************/
183 void OSMetaClassBase::
184 initialize()
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 *********************************************************************/
197 void
198 OSMetaClassBase::_RESERVEDOSMetaClassBase7()
199 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); }
200 #endif
201 
202 /*********************************************************************
203 *********************************************************************/
204 OSMetaClassBase::OSMetaClassBase()
205 {
206 }
207 
208 /*********************************************************************
209 *********************************************************************/
210 OSMetaClassBase::~OSMetaClassBase()
211 {
212     void ** thisVTable;
213 
214     thisVTable = (void **) this;
215     *thisVTable = (void *) -1UL;
216 }
217 
218 /*********************************************************************
219 *********************************************************************/
220 bool
221 OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const
222 {
223     return this == anObj;
224 }
225 
226 /*********************************************************************
227 *********************************************************************/
228 OSMetaClassBase *
229 OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const
230 {
231     return toMeta->checkMetaCast(this);
232 }
233 
234 /*********************************************************************
235 *********************************************************************/
236 OSMetaClassBase *
237 OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const
238 {
239     return OSMetaClass::checkMetaCastWithName(toMetaSymb, this);
240 }
241 
242 /*********************************************************************
243 *********************************************************************/
244 OSMetaClassBase *
245 OSMetaClassBase::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 *********************************************************************/
258 OSMetaClassBase *
259 OSMetaClassBase::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 *********************************************************************/
276 class OSMetaClassMeta : public OSMetaClass
277 {
278 public:
279     OSMetaClassMeta();
280     OSObject * alloc() const;
281 };
282 OSMetaClassMeta::OSMetaClassMeta()
283     : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass))
284     { }
285 OSObject * OSMetaClassMeta::alloc() const { return 0; }
286 
287 static OSMetaClassMeta sOSMetaClassMeta;
288 
289 const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta;
290 const 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 *********************************************************************/
304 void OSMetaClass::_RESERVEDOSMetaClass0()
305     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0); }
306 void OSMetaClass::_RESERVEDOSMetaClass1()
307     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1); }
308 void OSMetaClass::_RESERVEDOSMetaClass2()
309     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2); }
310 void OSMetaClass::_RESERVEDOSMetaClass3()
311     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3); }
312 void OSMetaClass::_RESERVEDOSMetaClass4()
313     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4); }
314 void OSMetaClass::_RESERVEDOSMetaClass5()
315     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5); }
316 void OSMetaClass::_RESERVEDOSMetaClass6()
317     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); }
318 void OSMetaClass::_RESERVEDOSMetaClass7()
319     { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); }
320 #endif
321 
322 /*********************************************************************
323 *********************************************************************/
324 static void
325 OSMetaClassLogErrorForKext(
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 
370 void
371 OSMetaClass::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 *********************************************************************/
385 OSMetaClass::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 *********************************************************************/
438 OSMetaClass::~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 *********************************************************************/
497 void * OSMetaClass::operator new(__unused size_t size) { return 0; }
498 void OSMetaClass::retain() const { }
499 void OSMetaClass::release() const { }
500 void OSMetaClass::release(__unused int when) const { }
501 void OSMetaClass::taggedRetain(__unused const void * tag) const { }
502 void OSMetaClass::taggedRelease(__unused const void * tag) const { }
503 void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { }
504 int  OSMetaClass::getRetainCount() const { return 0; }
505 
506 /*********************************************************************
507 *********************************************************************/
508 const char *
509 OSMetaClass::getClassName() const
510 {
511     if (!className) return NULL;
512     return className->getCStringNoCopy();
513 }
514 /*********************************************************************
515 *********************************************************************/
516 const OSSymbol *
517 OSMetaClass::getClassNameSymbol() const
518 {
519     return className;
520 }
521 /*********************************************************************
522 *********************************************************************/
523 unsigned int
524 OSMetaClass::getClassSize() const
525 {
526     return classSize;
527 }
528 
529 /*********************************************************************
530 *********************************************************************/
531 void *
532 OSMetaClass::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 *********************************************************************/
562 bool
563 OSMetaClass::checkModLoad(void * loadHandle)
564 {
565     return sStalled && loadHandle == sStalled &&
566         sStalled->result == kOSReturnSuccess;
567 }
568 
569 /*********************************************************************
570 *********************************************************************/
571 OSReturn
572 OSMetaClass::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 
698 finish:
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 *********************************************************************/
729 void
730 OSMetaClass::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 *********************************************************************/
740 void
741 OSMetaClass::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 *********************************************************************/
759 bool
760 OSMetaClass::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 
772 finish:
773     OSSafeRelease(theKext);
774     return result;
775 }
776 
777 /*********************************************************************
778 *********************************************************************/
779 void
780 OSMetaClass::reportModInstances(const char * kextIdentifier)
781 {
782     OSKext::reportOSMetaClassInstances(kextIdentifier,
783         kOSKextLogExplicitLevel);
784     return;
785 }
786 /*********************************************************************
787 *********************************************************************/
788 
789 void
790 OSMetaClass::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 
805 void
806 OSMetaClass::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 
826 void
827 OSMetaClass::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 
886 void
887 OSMetaClass::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 
895 void
896 OSMetaClass::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 *********************************************************************/
923 void
924 OSMetaClass::considerUnloads()
925 {
926     OSKext::considerUnloads();
927 }
928 
929 /*********************************************************************
930 *********************************************************************/
931 const OSMetaClass *
932 OSMetaClass::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 *********************************************************************/
951 OSObject *
952 OSMetaClass::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 *********************************************************************/
967 OSObject *
968 OSMetaClass::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 *********************************************************************/
978 OSObject *
979 OSMetaClass::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 *********************************************************************/
990 OSMetaClassBase *
991 OSMetaClass::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 *********************************************************************/
1008 OSMetaClassBase * OSMetaClass::
1009 checkMetaCastWithName(
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 *********************************************************************/
1022 OSMetaClassBase *
1023 OSMetaClass::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 *********************************************************************/
1044 OSMetaClassBase * 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 *********************************************************************/
1064 void
1065 OSMetaClass::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 *********************************************************************/
1073 const
1074 OSMetaClass *
1075 OSMetaClass::getSuperClass() const
1076 {
1077     return superClassLink;
1078 }
1079 
1080 /*********************************************************************
1081 * xxx - I want to rename this :-/
1082 *********************************************************************/
1083 const OSSymbol *
1084 OSMetaClass::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 *********************************************************************/
1095 unsigned int
1096 OSMetaClass::getInstanceCount() const
1097 {
1098     return instanceCount;
1099 }
1100 
1101 /*********************************************************************
1102 *********************************************************************/
1103 /* static */
1104 void
1105 OSMetaClass::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 *********************************************************************/
1133 OSDictionary *
1134 OSMetaClass::getClassDictionary()
1135 {
1136     panic("OSMetaClass::getClassDictionary() is obsoleted.\n");
1137     return 0;
1138 }
1139 
1140 /*********************************************************************
1141 *********************************************************************/
1142 bool
1143 OSMetaClass::serialize(__unused OSSerialize * s) const
1144 {
1145     panic("OSMetaClass::serialize(): Obsoleted\n");
1146     return false;
1147 }
1148 
1149 /*********************************************************************
1150 *********************************************************************/
1151 /* static */
1152 void
1153 OSMetaClass::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 
1189 finish:
1190     OSSafeRelease(classDict);
1191 
1192     IOLockUnlock(sAllClassesLock);
1193 
1194     return;
1195 }
1196