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