f8ac932d7c5b0c35a74d05e77b0d19013f83b424
[apple/xnu.git] / libkern / c++ / OSMetaClass.cpp
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 }