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