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