]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSMetaClass.cpp
f7f1e0a3be61d4e3d0ff7f1bdb0cb316b36a22e0
[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 record_kext_unload(ki->id);
656 OSRuntimeUnloadCPP(ki, 0); // call destructors
657 ret = kmod_destroy(host_priv_self(), ki->id);
658 didUnload = true;
659 }
660
661 }
662
663 kmods->release();
664
665 } while (didUnload);
666
667 mutex_unlock(loadLock);
668
669 kmod_unload_cache();
670 }
671
672 void OSMetaClass::considerUnloads()
673 {
674 AbsoluteTime when;
675
676 mutex_lock(loadLock);
677
678 if (!unloadCallout)
679 unloadCallout = thread_call_allocate(&_OSMetaClassConsiderUnloads, 0);
680
681 thread_call_cancel(unloadCallout);
682 clock_interval_to_deadline(sConsiderUnloadDelay, 1000 * 1000 * 1000, &when);
683 thread_call_enter_delayed(unloadCallout, when);
684
685 mutex_unlock(loadLock);
686 }
687
688 const OSMetaClass *OSMetaClass::getMetaClassWithName(const OSSymbol *name)
689 {
690 OSMetaClass *retMeta = 0;
691
692 if (!name)
693 return 0;
694
695 if (sAllClassesDict)
696 retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
697
698 if (!retMeta && sStalled)
699 {
700 // Oh dear we have to scan the stalled list and walk the
701 // the stalled list manually.
702 const char *cName = name->getCStringNoCopy();
703 unsigned int i;
704
705 // find class in stalled list
706 for (i = 0; i < sStalled->count; i++) {
707 retMeta = sStalled->classes[i];
708 if (0 == strcmp(cName, (const char *) retMeta->className))
709 break;
710 }
711
712 if (i < sStalled->count)
713 retMeta = 0;
714 }
715
716 return retMeta;
717 }
718
719 OSObject *OSMetaClass::allocClassWithName(const OSSymbol *name)
720 {
721 OSObject * result;
722 mutex_lock(loadLock);
723
724 const OSMetaClass * const meta = getMetaClassWithName(name);
725
726 if (meta)
727 result = meta->alloc();
728 else
729 result = 0;
730
731 mutex_unlock(loadLock);
732
733 return result;
734 }
735
736 OSObject *OSMetaClass::allocClassWithName(const OSString *name)
737 {
738 const OSSymbol *tmpKey = OSSymbol::withString(name);
739 OSObject *result = allocClassWithName(tmpKey);
740 tmpKey->release();
741 return result;
742 }
743
744 OSObject *OSMetaClass::allocClassWithName(const char *name)
745 {
746 const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
747 OSObject *result = allocClassWithName(tmpKey);
748 tmpKey->release();
749 return result;
750 }
751
752
753 OSMetaClassBase *OSMetaClass::
754 checkMetaCastWithName(const OSSymbol *name, const OSMetaClassBase *in)
755 {
756 OSMetaClassBase * result;
757 mutex_lock(loadLock);
758 const OSMetaClass * const meta = getMetaClassWithName(name);
759
760 if (meta)
761 result = meta->checkMetaCast(in);
762 else
763 result = 0;
764
765 mutex_unlock(loadLock);
766 return result;
767 }
768
769 OSMetaClassBase *OSMetaClass::
770 checkMetaCastWithName(const OSString *name, const OSMetaClassBase *in)
771 {
772 const OSSymbol *tmpKey = OSSymbol::withString(name);
773 OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in);
774 tmpKey->release();
775 return result;
776 }
777
778 OSMetaClassBase *OSMetaClass::
779 checkMetaCastWithName(const char *name, const OSMetaClassBase *in)
780 {
781 const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name);
782 OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in);
783 tmpKey->release();
784 return result;
785 }
786
787 /*
788 OSMetaClass::checkMetaCast
789 checkMetaCast(const OSMetaClassBase *check)
790
791 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.
792
793 Generally this method is not invoked directly but is used to implement the OSMetaClassBase::metaCast member function.
794
795 See also OSMetaClassBase::metaCast
796
797 */
798 OSMetaClassBase *OSMetaClass::checkMetaCast(const OSMetaClassBase *check) const
799 {
800 const OSMetaClass * const toMeta = this;
801 const OSMetaClass *fromMeta;
802
803 for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) {
804 if (toMeta == fromMeta)
805 return (OSMetaClassBase *) check; // Discard const
806
807 if (!fromMeta->superClassLink)
808 break;
809 }
810
811 return 0;
812 }
813
814 void OSMetaClass::reservedCalled(int ind) const
815 {
816 const char *cname = className->getCStringNoCopy();
817 panic("%s::_RESERVED%s%d called\n", cname, cname, ind);
818 }
819
820 const OSMetaClass *OSMetaClass::getSuperClass() const
821 {
822 return superClassLink;
823 }
824
825 const OSSymbol *OSMetaClass::getKmodName() const
826 {
827 return (const OSSymbol *)sSortedByClassesDict->getObject((OSSymbol *)this);
828 }
829
830 unsigned int OSMetaClass::getInstanceCount() const
831 {
832 return instanceCount;
833 }
834
835 void OSMetaClass::printInstanceCounts()
836 {
837 OSCollectionIterator *classes;
838 OSSymbol *className;
839 OSMetaClass *meta;
840
841 classes = OSCollectionIterator::withCollection(sAllClassesDict);
842 if (!classes)
843 return;
844
845 while( (className = (OSSymbol *)classes->getNextObject())) {
846 meta = (OSMetaClass *) sAllClassesDict->getObject(className);
847 assert(meta);
848
849 printf("%24s count: %03d x 0x%03x = 0x%06x\n",
850 className->getCStringNoCopy(),
851 meta->getInstanceCount(),
852 meta->getClassSize(),
853 meta->getInstanceCount() * meta->getClassSize() );
854 }
855 printf("\n");
856 classes->release();
857 }
858
859 OSDictionary * OSMetaClass::getClassDictionary()
860 {
861 panic("OSMetaClass::getClassDictionary(): Obsoleted\n");
862 return 0;
863 }
864
865 bool OSMetaClass::serialize(__unused OSSerialize *s) const
866 {
867 panic("OSMetaClass::serialize(): Obsoleted\n");
868 return false;
869 }
870
871 void OSMetaClass::serializeClassDictionary(OSDictionary *serializeDictionary)
872 {
873 OSDictionary *classDict;
874
875 classDict = OSDictionary::withCapacity(sAllClassesDict->getCount());
876 if (!classDict)
877 return;
878
879 mutex_lock(loadLock);
880 do {
881 OSCollectionIterator *classes;
882 const OSSymbol *className;
883
884 classes = OSCollectionIterator::withCollection(sAllClassesDict);
885 if (!classes)
886 break;
887
888 while ((className = (const OSSymbol *) classes->getNextObject())) {
889 const OSMetaClass *meta;
890 OSNumber *count;
891
892 meta = (OSMetaClass *) sAllClassesDict->getObject(className);
893 count = OSNumber::withNumber(meta->getInstanceCount(), 32);
894 if (count) {
895 classDict->setObject(className, count);
896 count->release();
897 }
898 }
899 classes->release();
900
901 serializeDictionary->setObject("Classes", classDict);
902 } while (0);
903
904 mutex_unlock(loadLock);
905
906 classDict->release();
907 }