xref: /xnu-11215/libkern/c++/OSMetaClass.cpp (revision fad439e7)
1 /*
2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_LICENSE_HEADER_START@
5  *
6  * The contents of this file constitute Original Code as defined in and
7  * are subject to the Apple Public Source License Version 1.1 (the
8  * "License").  You may not use this file except in compliance with the
9  * License.  Please obtain a copy of the License at
10  * http://www.apple.com/publicsource and read it before using this file.
11  *
12  * This Original Code and all software distributed under the License are
13  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
17  * License for the specific language governing rights and limitations
18  * under the License.
19  *
20  * @APPLE_LICENSE_HEADER_END@
21  */
22 /* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */
23 
24 #include <string.h>
25 #include <sys/systm.h>
26 
27 #include <libkern/OSReturn.h>
28 
29 #include <libkern/c++/OSMetaClass.h>
30 
31 #include <libkern/c++/OSObject.h>
32 #include <libkern/c++/OSCollectionIterator.h>
33 #include <libkern/c++/OSDictionary.h>
34 #include <libkern/c++/OSArray.h>
35 #include <libkern/c++/OSSet.h>
36 #include <libkern/c++/OSSymbol.h>
37 #include <libkern/c++/OSNumber.h>
38 #include <libkern/c++/OSSerialize.h>
39 #include <libkern/c++/OSLib.h>
40 #include <libkern/OSAtomic.h>
41 
42 __BEGIN_DECLS
43 
44 #include <mach/mach_types.h>
45 #include <mach/etap_events.h>
46 #include <kern/lock.h>
47 #include <kern/clock.h>
48 #include <kern/thread_call.h>
49 #include <kern/host.h>
50 #include <mach/kmod.h>
51 #include <mach/mach_interface.h>
52 
53 extern void OSRuntimeUnloadCPP(kmod_info_t *ki, void *);
54 
55 #if OSALLOCDEBUG
56 extern int debug_container_malloc_size;
57 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
58 #else
59 #define ACCUMSIZE(s)
60 #endif /* OSALLOCDEBUG */
61 
62 __END_DECLS
63 
64 static enum {
65     kCompletedBootstrap = 0,
66     kNoDictionaries = 1,
67     kMakingDictionaries = 2
68 } sBootstrapState = kNoDictionaries;
69 
70 static const int kClassCapacityIncrement = 40;
71 static const int kKModCapacityIncrement = 10;
72 static OSDictionary *sAllClassesDict, *sKModClassesDict;
73 
74 static mutex_t *loadLock;
75 static struct StalledData {
76     const char *kmodName;
77     OSReturn result;
78     unsigned int capacity;
79     unsigned int count;
80     OSMetaClass **classes;
81 } *sStalled;
82 
83 static unsigned int sConsiderUnloadDelay = 60;	/* secs */
84 
85 static const char OSMetaClassBasePanicMsg[] =
86     "OSMetaClassBase::_RESERVEDOSMetaClassBase%d called\n";
87 
88 #if SLOT_USED
89 void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
90     { panic(OSMetaClassBasePanicMsg, 0); }
91 void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
92     { panic(OSMetaClassBasePanicMsg, 1); }
93 void OSMetaClassBase::_RESERVEDOSMetaClassBase2()
94     { panic(OSMetaClassBasePanicMsg, 2); }
95 #endif /* SLOT_USED */
96 
97 // As these slots are used move them up inside the #if above
98 void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
99     { panic(OSMetaClassBasePanicMsg, 3); }
100 void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
101     { panic(OSMetaClassBasePanicMsg, 4); }
102 void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
103     { panic(OSMetaClassBasePanicMsg, 5); }
104 void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
105     { panic(OSMetaClassBasePanicMsg, 6); }
106 
107 /*
108  * These used to be inline in the header but gcc didn't believe us
109  * Now we MUST pull the inline out at least until the compiler is
110  * repaired.
111  */
112 // Helper inlines for runtime type preprocessor macros
113 OSMetaClassBase *OSMetaClassBase::
114 safeMetaCast(const OSMetaClassBase *me, const OSMetaClass *toType)
115     { return (me)? me->metaCast(toType) : 0; }
116 
117 bool OSMetaClassBase::
118 checkTypeInst(const OSMetaClassBase *inst, const OSMetaClassBase *typeinst)
119 {
120     const OSMetaClass *toType = OSTypeIDInst(typeinst);
121     return typeinst && inst && (0 != inst->metaCast(toType));
122 }
123 
124 
125 // If you need this slot you had better setup an IOCTL style interface.
126 // 'Cause the whole kernel world depends on OSMetaClassBase and YOU
127 // CANT change the VTABLE size ever.
128 void OSMetaClassBase::_RESERVEDOSMetaClassBase7()
129     { panic(OSMetaClassBasePanicMsg, 7); }
130 
131 OSMetaClassBase::OSMetaClassBase()
132 {
133 }
134 
135 OSMetaClassBase::~OSMetaClassBase()
136 {
137     void **thisVTable;
138 
139     thisVTable = (void **) this;
140     *thisVTable = (void *) -1UL;
141 }
142 
143 bool OSMetaClassBase::isEqualTo(const OSMetaClassBase *anObj) const
144 {
145     return this == anObj;
146 }
147 
148 OSMetaClassBase *OSMetaClassBase::metaCast(const OSMetaClass *toMeta) const
149 {
150     return toMeta->checkMetaCast(this);
151 }
152 
153 OSMetaClassBase *OSMetaClassBase::metaCast(const OSSymbol *toMetaSymb) const
154 {
155     return OSMetaClass::checkMetaCastWithName(toMetaSymb, this);
156 }
157 
158 OSMetaClassBase *OSMetaClassBase::metaCast(const OSString *toMetaStr) const
159 {
160     const OSSymbol *tempSymb = OSSymbol::withString(toMetaStr);
161     OSMetaClassBase *ret = 0;
162     if (tempSymb) {
163         ret = metaCast(tempSymb);
164         tempSymb->release();
165     }
166     return ret;
167 }
168 
169 OSMetaClassBase *OSMetaClassBase::metaCast(const char *toMetaCStr) const
170 {
171     const OSSymbol *tempSymb = OSSymbol::withCString(toMetaCStr);
172     OSMetaClassBase *ret = 0;
173     if (tempSymb) {
174         ret = metaCast(tempSymb);
175         tempSymb->release();
176     }
177     return ret;
178 }
179 
180 class OSMetaClassMeta : public OSMetaClass
181 {
182 public:
183     OSMetaClassMeta();
184     OSObject *alloc() const;
185 };
186 OSMetaClassMeta::OSMetaClassMeta()
187     : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass))
188     { }
189 OSObject *OSMetaClassMeta::alloc() const { return 0; }
190 
191 static OSMetaClassMeta sOSMetaClassMeta;
192 
193 const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta;
194 const OSMetaClass * OSMetaClass::getMetaClass() const
195     { return &sOSMetaClassMeta; }
196 
197 static const char OSMetaClassPanicMsg[] =
198     "OSMetaClass::_RESERVEDOSMetaClass%d called\n";
199 
200 void OSMetaClass::_RESERVEDOSMetaClass0()
201     { panic(OSMetaClassPanicMsg, 0); }
202 void OSMetaClass::_RESERVEDOSMetaClass1()
203     { panic(OSMetaClassPanicMsg, 1); }
204 void OSMetaClass::_RESERVEDOSMetaClass2()
205     { panic(OSMetaClassPanicMsg, 2); }
206 void OSMetaClass::_RESERVEDOSMetaClass3()
207     { panic(OSMetaClassPanicMsg, 3); }
208 void OSMetaClass::_RESERVEDOSMetaClass4()
209     { panic(OSMetaClassPanicMsg, 4); }
210 void OSMetaClass::_RESERVEDOSMetaClass5()
211     { panic(OSMetaClassPanicMsg, 5); }
212 void OSMetaClass::_RESERVEDOSMetaClass6()
213     { panic(OSMetaClassPanicMsg, 6); }
214 void OSMetaClass::_RESERVEDOSMetaClass7()
215     { panic(OSMetaClassPanicMsg, 7); }
216 
217 void OSMetaClass::logError(OSReturn result)
218 {
219     const char *msg;
220 
221     switch (result) {
222     case kOSMetaClassNoInit:
223 	msg="OSMetaClass::preModLoad wasn't called, runtime internal error";
224 	break;
225     case kOSMetaClassNoDicts:
226 	msg="Allocation failure for Metaclass internal dictionaries"; break;
227     case kOSMetaClassNoKModSet:
228 	msg="Allocation failure for internal kmodule set"; break;
229     case kOSMetaClassNoInsKModSet:
230 	msg="Can't insert the KMod set into the module dictionary"; break;
231     case kOSMetaClassDuplicateClass:
232 	msg="Duplicate class"; break;
233     case kOSMetaClassNoSuper:
234 	msg="Can't associate a class with its super class"; break;
235     case kOSMetaClassInstNoSuper:
236 	msg="Instance construction, unknown super class."; break;
237     default:
238     case kOSMetaClassInternal:
239 	msg="runtime internal error"; break;
240     case kOSReturnSuccess:
241 	return;
242     }
243     printf("%s\n", msg);
244 }
245 
246 OSMetaClass::OSMetaClass(const char *inClassName,
247                          const OSMetaClass *inSuperClass,
248                          unsigned int inClassSize)
249 {
250     instanceCount = 0;
251     classSize = inClassSize;
252     superClassLink = inSuperClass;
253 
254     className = (const OSSymbol *) inClassName;
255 
256     if (!sStalled) {
257 	printf("OSMetaClass::preModLoad wasn't called for %s, "
258 	       "runtime internal error\n", inClassName);
259     } else if (!sStalled->result) {
260 	// Grow stalled array if neccessary
261 	if (sStalled->count >= sStalled->capacity) {
262 	    OSMetaClass **oldStalled = sStalled->classes;
263 	    int oldSize = sStalled->capacity * sizeof(OSMetaClass *);
264 	    int newSize = oldSize
265 			+ kKModCapacityIncrement * sizeof(OSMetaClass *);
266 
267 	    sStalled->classes = (OSMetaClass **) kalloc(newSize);
268 	    if (!sStalled->classes) {
269 		sStalled->classes = oldStalled;
270 		sStalled->result = kOSMetaClassNoTempData;
271 		return;
272 	    }
273 
274 	    sStalled->capacity += kKModCapacityIncrement;
275 	    memmove(sStalled->classes, oldStalled, oldSize);
276 	    kfree((vm_offset_t)oldStalled, oldSize);
277 	    ACCUMSIZE(newSize - oldSize);
278 	}
279 
280 	sStalled->classes[sStalled->count++] = this;
281     }
282 }
283 
284 OSMetaClass::~OSMetaClass()
285 {
286     do {
287 	OSCollectionIterator *iter;
288 
289 	if (sAllClassesDict)
290 	    sAllClassesDict->removeObject(className);
291 
292 	iter = OSCollectionIterator::withCollection(sKModClassesDict);
293 	if (!iter)
294 	    break;
295 
296 	OSSymbol *iterKey;
297 	while ( (iterKey = (OSSymbol *) iter->getNextObject()) ) {
298 	    OSSet *kmodClassSet;
299 	    kmodClassSet = (OSSet *) sKModClassesDict->getObject(iterKey);
300 	    if (kmodClassSet && kmodClassSet->containsObject(this)) {
301 		kmodClassSet->removeObject(this);
302 		break;
303 	    }
304 	}
305 	iter->release();
306     } while (false);
307 
308     if (sStalled) {
309 	unsigned int i;
310 
311 	// First pass find class in stalled list
312 	for (i = 0; i < sStalled->count; i++)
313 	    if (this == sStalled->classes[i])
314 		break;
315 
316 	if (i < sStalled->count) {
317 	    sStalled->count--;
318 	    if (i < sStalled->count)
319 		memmove(&sStalled->classes[i], &sStalled->classes[i+1],
320 			    (sStalled->count - i) * sizeof(OSMetaClass *));
321 	}
322 	return;
323     }
324 }
325 
326 void *OSMetaClass::operator new(size_t size) { return 0; }
327 void OSMetaClass::retain() const { }
328 void OSMetaClass::release() const { }
329 void OSMetaClass::release(int when) const { }
330 void OSMetaClass::taggedRetain(const void *tag) const { }
331 void OSMetaClass::taggedRelease(const void *tag) const { }
332 void OSMetaClass::taggedRelease(const void *tag, const int when) const { }
333 int  OSMetaClass::getRetainCount() const { return 0; }
334 
335 const char *OSMetaClass::getClassName() const
336 {
337     return className->getCStringNoCopy();
338 }
339 
340 unsigned int OSMetaClass::getClassSize() const
341 {
342     return classSize;
343 }
344 
345 void *OSMetaClass::preModLoad(const char *kmodName)
346 {
347     if (!loadLock) {
348         loadLock = mutex_alloc(ETAP_IO_AHA);
349 	mutex_lock(loadLock);
350     }
351     else
352 	mutex_lock(loadLock);
353 
354     sStalled = (StalledData *) kalloc(sizeof(*sStalled));
355     if (sStalled) {
356 	sStalled->classes  = (OSMetaClass **)
357 			kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
358 	if (!sStalled->classes) {
359 	    kfree((vm_offset_t) sStalled, sizeof(*sStalled));
360 	    return 0;
361 	}
362 	ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + sizeof(*sStalled));
363 
364         sStalled->result   = kOSReturnSuccess;
365 	sStalled->capacity = kKModCapacityIncrement;
366 	sStalled->count	   = 0;
367 	sStalled->kmodName = kmodName;
368 	bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *));
369     }
370 
371     return sStalled;
372 }
373 
374 bool OSMetaClass::checkModLoad(void *loadHandle)
375 {
376     return sStalled && loadHandle == sStalled
377 	&& sStalled->result == kOSReturnSuccess;
378 }
379 
380 OSReturn OSMetaClass::postModLoad(void *loadHandle)
381 {
382     OSReturn result = kOSReturnSuccess;
383     OSSet *kmodSet = 0;
384 
385     if (!sStalled || loadHandle != sStalled) {
386 	logError(kOSMetaClassInternal);
387 	return kOSMetaClassInternal;
388     }
389 
390     if (sStalled->result)
391 	result = sStalled->result;
392     else switch (sBootstrapState) {
393     case kNoDictionaries:
394 	sBootstrapState = kMakingDictionaries;
395 	// No break; fall through
396 
397     case kMakingDictionaries:
398 	sKModClassesDict = OSDictionary::withCapacity(kKModCapacityIncrement);
399 	sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
400 	if (!sAllClassesDict || !sKModClassesDict) {
401 	    result = kOSMetaClassNoDicts;
402 	    break;
403 	}
404 	// No break; fall through
405 
406     case kCompletedBootstrap:
407     {
408         unsigned int i;
409 
410 	if (!sStalled->count)
411 	    break;	// Nothing to do so just get out
412 
413 	// First pass checking classes aren't already loaded
414 	for (i = 0; i < sStalled->count; i++) {
415 	    OSMetaClass *me = sStalled->classes[i];
416 
417 	    if (0 != sAllClassesDict->getObject((const char *) me->className)) {
418                 printf("Class \"%s\" is duplicate\n", (const char *) me->className);
419                 result = kOSMetaClassDuplicateClass;
420                 break;
421             }
422 	}
423         if (i != sStalled->count)
424 	    break;
425 
426 	kmodSet = OSSet::withCapacity(sStalled->count);
427 	if (!kmodSet) {
428 	    result = kOSMetaClassNoKModSet;
429 	    break;
430 	}
431 
432 	if (!sKModClassesDict->setObject(sStalled->kmodName, kmodSet)) {
433 	    result = kOSMetaClassNoInsKModSet;
434 	    break;
435 	}
436 
437 	// Second pass symbolling strings and inserting classes in dictionary
438 	for (unsigned int i = 0; i < sStalled->count; i++) {
439 	    OSMetaClass *me = sStalled->classes[i];
440 	    me->className =
441                 OSSymbol::withCStringNoCopy((const char *) me->className);
442 
443 	    sAllClassesDict->setObject(me->className, me);
444 	    kmodSet->setObject(me);
445 	}
446 	sBootstrapState = kCompletedBootstrap;
447 	break;
448     }
449 
450     default:
451 	result = kOSMetaClassInternal;
452 	break;
453     }
454 
455     if (kmodSet)
456 	kmodSet->release();
457 
458     if (sStalled) {
459 	ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *)
460 		     + sizeof(*sStalled)));
461 	kfree((vm_offset_t) sStalled->classes,
462 	      sStalled->capacity * sizeof(OSMetaClass *));
463 	kfree((vm_offset_t) sStalled, sizeof(*sStalled));
464 	sStalled = 0;
465     }
466 
467     logError(result);
468     mutex_unlock(loadLock);
469     return result;
470 }
471 
472 
473 void OSMetaClass::instanceConstructed() const
474 {
475     // if ((0 == OSIncrementAtomic((SInt32 *)&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
476     if ((0 == OSIncrementAtomic((SInt32 *) &instanceCount)) && superClassLink)
477 	superClassLink->instanceConstructed();
478 }
479 
480 void OSMetaClass::instanceDestructed() const
481 {
482     if ((1 == OSDecrementAtomic((SInt32 *) &instanceCount)) && superClassLink)
483 	superClassLink->instanceDestructed();
484 
485     if( ((int) instanceCount) < 0)
486 	printf("%s: bad retain(%d)", getClassName(), instanceCount);
487 }
488 
489 bool OSMetaClass::modHasInstance(const char *kmodName)
490 {
491     bool result = false;
492 
493     if (!loadLock) {
494         loadLock = mutex_alloc(ETAP_IO_AHA);
495 	mutex_lock(loadLock);
496     }
497     else
498 	mutex_lock(loadLock);
499 
500     do {
501 	OSSet *kmodClasses;
502 	OSCollectionIterator *iter;
503 	OSMetaClass *checkClass;
504 
505 	kmodClasses = OSDynamicCast(OSSet,
506 				    sKModClassesDict->getObject(kmodName));
507 	if (!kmodClasses)
508 	    break;
509 
510 	iter = OSCollectionIterator::withCollection(kmodClasses);
511 	if (!iter)
512 	    break;
513 
514 	while ( (checkClass = (OSMetaClass *) iter->getNextObject()) )
515 	    if (checkClass->getInstanceCount()) {
516 		result = true;
517 		break;
518 	    }
519 
520 	iter->release();
521     } while (false);
522 
523     mutex_unlock(loadLock);
524 
525     return result;
526 }
527 
528 void OSMetaClass::reportModInstances(const char *kmodName)
529 {
530     OSSet *kmodClasses;
531     OSCollectionIterator *iter;
532     OSMetaClass *checkClass;
533 
534     kmodClasses = OSDynamicCast(OSSet,
535 				 sKModClassesDict->getObject(kmodName));
536     if (!kmodClasses)
537 	return;
538 
539     iter = OSCollectionIterator::withCollection(kmodClasses);
540     if (!iter)
541 	return;
542 
543     while ( (checkClass = (OSMetaClass *) iter->getNextObject()) )
544 	if (checkClass->getInstanceCount()) {
545 	    printf("%s: %s has %d instance(s)\n",
546 		  kmodName,
547 		  checkClass->getClassName(),
548 		  checkClass->getInstanceCount());
549 	}
550 
551     iter->release();
552 }
553 
554 static void _OSMetaClassConsiderUnloads(thread_call_param_t p0,
555                                         thread_call_param_t p1)
556 {
557     OSSet *kmodClasses;
558     OSSymbol *kmodName;
559     OSCollectionIterator *kmods;
560     OSCollectionIterator *classes;
561     OSMetaClass *checkClass;
562     kmod_info_t *ki = 0;
563     kern_return_t ret;
564     bool didUnload;
565 
566     mutex_lock(loadLock);
567 
568     do {
569 
570 	kmods = OSCollectionIterator::withCollection(sKModClassesDict);
571 	if (!kmods)
572 	    break;
573 
574         didUnload = false;
575         while ( (kmodName = (OSSymbol *) kmods->getNextObject()) ) {
576 
577             if (ki) {
578                 kfree(ki, sizeof(kmod_info_t));
579                 ki = 0;
580             }
581 
582             ki = kmod_lookupbyname_locked((char *)kmodName->getCStringNoCopy());
583             if (!ki)
584                 continue;
585 
586             if (ki->reference_count) {
587                  continue;
588             }
589 
590             kmodClasses = OSDynamicCast(OSSet,
591                                 sKModClassesDict->getObject(kmodName));
592             classes = OSCollectionIterator::withCollection(kmodClasses);
593             if (!classes)
594                 continue;
595 
596             while ((checkClass = (OSMetaClass *) classes->getNextObject())
597               && (0 == checkClass->getInstanceCount()))
598                 {}
599             classes->release();
600 
601             if (0 == checkClass) {
602                 OSRuntimeUnloadCPP(ki, 0);	// call destructors
603                 ret = kmod_destroy(host_priv_self(), ki->id);
604                 didUnload = true;
605             }
606 
607         }
608 
609         kmods->release();
610 
611     } while (didUnload);
612 
613     mutex_unlock(loadLock);
614 }
615 
616 void OSMetaClass::considerUnloads()
617 {
618     static thread_call_t unloadCallout;
619     AbsoluteTime when;
620 
621     mutex_lock(loadLock);
622 
623     if (!unloadCallout)
624         unloadCallout = thread_call_allocate(&_OSMetaClassConsiderUnloads, 0);
625 
626     thread_call_cancel(unloadCallout);
627     clock_interval_to_deadline(sConsiderUnloadDelay, 1000 * 1000 * 1000, &when);
628     thread_call_enter_delayed(unloadCallout, when);
629 
630     mutex_unlock(loadLock);
631 }
632 
633 const OSMetaClass *OSMetaClass::getMetaClassWithName(const OSSymbol *name)
634 {
635     OSMetaClass *retMeta = 0;
636 
637     if (!name)
638 	return 0;
639 
640     if (sAllClassesDict)
641 	retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
642 
643     if (!retMeta && sStalled)
644     {
645 	// Oh dear we have to scan the stalled list and walk the
646 	// the stalled list manually.
647 	const char *cName = name->getCStringNoCopy();
648 	unsigned int i;
649 
650 	// find class in stalled list
651 	for (i = 0; i < sStalled->count; i++) {
652 	    retMeta = sStalled->classes[i];
653 	    if (0 == strcmp(cName, (const char *) retMeta->className))
654 		break;
655 	}
656 
657 	if (i < sStalled->count)
658 	    retMeta = 0;
659     }
660 
661     return retMeta;
662 }
663 
664 OSObject *OSMetaClass::allocClassWithName(const OSSymbol *name)
665 {
666     OSObject * result;
667     mutex_lock(loadLock);
668 
669     const OSMetaClass * const meta = getMetaClassWithName(name);
670 
671     if (meta)
672 	result = meta->alloc();
673     else
674         result = 0;
675 
676     mutex_unlock(loadLock);
677 
678     return result;
679 }
680 
681 OSObject *OSMetaClass::allocClassWithName(const OSString *name)
682 {
683     const OSSymbol *tmpKey = OSSymbol::withString(name);
684     OSObject *result = allocClassWithName(tmpKey);
685     tmpKey->release();
686     return result;
687 }
688 
689 OSObject *OSMetaClass::allocClassWithName(const char *name)
690 {
691     const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
692     OSObject *result = allocClassWithName(tmpKey);
693     tmpKey->release();
694     return result;
695 }
696 
697 
698 OSMetaClassBase *OSMetaClass::
699 checkMetaCastWithName(const OSSymbol *name, const OSMetaClassBase *in)
700 {
701     OSMetaClassBase * result;
702     mutex_lock(loadLock);
703     const OSMetaClass * const meta = getMetaClassWithName(name);
704 
705     if (meta)
706 	result = meta->checkMetaCast(in);
707     else
708         result = 0;
709 
710     mutex_unlock(loadLock);
711     return result;
712 }
713 
714 OSMetaClassBase *OSMetaClass::
715 checkMetaCastWithName(const OSString *name, const OSMetaClassBase *in)
716 {
717     const OSSymbol *tmpKey = OSSymbol::withString(name);
718     OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in);
719     tmpKey->release();
720     return result;
721 }
722 
723 OSMetaClassBase *OSMetaClass::
724 checkMetaCastWithName(const char *name, const OSMetaClassBase *in)
725 {
726     const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
727     OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in);
728     tmpKey->release();
729     return result;
730 }
731 
732 /*
733 OSMetaClass::checkMetaCast
734     checkMetaCast(const OSMetaClassBase *check)
735 
736 Check to see if the 'check' object has this object in it's metaclass chain.  Returns check if it is indeed a kind of the current meta class, 0 otherwise.
737 
738 Generally this method is not invoked directly but is used to implement the OSMetaClassBase::metaCast member function.
739 
740 See also OSMetaClassBase::metaCast
741 
742  */
743 OSMetaClassBase *OSMetaClass::checkMetaCast(const OSMetaClassBase *check) const
744 {
745     const OSMetaClass * const toMeta = this;
746     const OSMetaClass *fromMeta;
747 
748     for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) {
749 	if (toMeta == fromMeta)
750 	    return (OSMetaClassBase *) check; // Discard const
751 
752 	if (!fromMeta->superClassLink)
753 	    break;
754     }
755 
756     return 0;
757 }
758 
759 void OSMetaClass::reservedCalled(int ind) const
760 {
761     const char *cname = className->getCStringNoCopy();
762     panic("%s::_RESERVED%s%d called\n", cname, cname, ind);
763 }
764 
765 const OSMetaClass *OSMetaClass::getSuperClass() const
766 {
767     return superClassLink;
768 }
769 
770 unsigned int OSMetaClass::getInstanceCount() const
771 {
772     return instanceCount;
773 }
774 
775 void OSMetaClass::printInstanceCounts()
776 {
777     OSCollectionIterator *classes;
778     OSSymbol		 *className;
779     OSMetaClass		 *meta;
780 
781     classes = OSCollectionIterator::withCollection(sAllClassesDict);
782     if (!classes)
783 	return;
784 
785     while( (className = (OSSymbol *)classes->getNextObject())) {
786 	meta = (OSMetaClass *) sAllClassesDict->getObject(className);
787 	assert(meta);
788 
789 	printf("%24s count: %03d x 0x%03x = 0x%06x\n",
790 	    className->getCStringNoCopy(),
791 	    meta->getInstanceCount(),
792 	    meta->getClassSize(),
793 	    meta->getInstanceCount() * meta->getClassSize() );
794     }
795     printf("\n");
796     classes->release();
797 }
798 
799 OSDictionary * OSMetaClass::getClassDictionary()
800 {
801     return sAllClassesDict;
802 }
803 
804 bool OSMetaClass::serialize(OSSerialize *s) const
805 {
806     OSDictionary *	dict;
807     OSNumber *		off;
808     bool		ok = false;
809 
810     if (s->previouslySerialized(this)) return true;
811 
812     dict = 0;// IODictionary::withCapacity(2);
813     off = OSNumber::withNumber(getInstanceCount(), 32);
814 
815     if (dict) {
816 	dict->setObject("InstanceCount", off );
817 	ok = dict->serialize(s);
818     } else if( off)
819 	ok = off->serialize(s);
820 
821     if (dict)
822 	dict->release();
823     if (off)
824 	off->release();
825 
826     return ok;
827 }
828 
829