]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSMetaClass.cpp
xnu-2050.7.9.tar.gz
[apple/xnu.git] / libkern / c++ / OSMetaClass.cpp
1 /*
2 * Copyright (c) 2000-2006 Apple 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 #include <libkern/c++/OSObject.h>
36 #include <libkern/c++/OSKext.h>
37
38 #include <libkern/c++/OSCollectionIterator.h>
39 #include <libkern/c++/OSDictionary.h>
40 #include <libkern/c++/OSArray.h>
41 #include <libkern/c++/OSSet.h>
42 #include <libkern/c++/OSSymbol.h>
43 #include <libkern/c++/OSNumber.h>
44 #include <libkern/c++/OSSerialize.h>
45
46 #include <libkern/c++/OSLib.h>
47 #include <libkern/OSAtomic.h>
48
49 #include <IOKit/pwr_mgt/RootDomain.h>
50 #include <IOKit/IOMessage.h>
51 #include <IOKit/IOLib.h>
52
53 __BEGIN_DECLS
54
55 #include <sys/systm.h>
56 #include <mach/mach_types.h>
57 #include <kern/locks.h>
58 #include <kern/clock.h>
59 #include <kern/thread_call.h>
60 #include <kern/host.h>
61 #include <mach/mach_interface.h>
62
63 #if PRAGMA_MARK
64 #pragma mark Macros
65 #endif /* PRAGMA_MARK */
66 /*********************************************************************
67 * Macros
68 *********************************************************************/
69 #if OSALLOCDEBUG
70 extern int debug_container_malloc_size;
71 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while (0)
72 #else
73 #define ACCUMSIZE(s)
74 #endif /* OSALLOCDEBUG */
75
76 __END_DECLS
77
78 #if PRAGMA_MARK
79 #pragma mark Internal constants & data structs
80 #endif /* PRAGMA_MARK */
81 /*********************************************************************
82 * Internal constants & data structs
83 *********************************************************************/
84 OSKextLogSpec kOSMetaClassLogSpec =
85 kOSKextLogErrorLevel |
86 kOSKextLogLoadFlag |
87 kOSKextLogKextBookkeepingFlag;
88
89 static enum {
90 kCompletedBootstrap = 0,
91 kNoDictionaries = 1,
92 kMakingDictionaries = 2
93 } sBootstrapState = kNoDictionaries;
94
95 static const int kClassCapacityIncrement = 40;
96 static const int kKModCapacityIncrement = 10;
97 static OSDictionary * sAllClassesDict;
98 static unsigned int sDeepestClass;
99 IOLock * sAllClassesLock = NULL;
100 IOLock * sInstancesLock = NULL;
101
102 /*
103 * While loading a kext and running all its constructors to register
104 * all OSMetaClass classes, the classes are queued up here. Only one
105 * kext can be in flight at a time, guarded by sStalledClassesLock
106 */
107 static struct StalledData {
108 const char * kextIdentifier;
109 OSReturn result;
110 unsigned int capacity;
111 unsigned int count;
112 OSMetaClass ** classes;
113 } * sStalled;
114 IOLock * sStalledClassesLock = NULL;
115
116
117 struct ExpansionData {
118 OSOrderedSet * instances;
119 OSKext * kext;
120 };
121
122
123 #if PRAGMA_MARK
124 #pragma mark OSMetaClassBase
125 #endif /* PRAGMA_MARK */
126 /*********************************************************************
127 * OSMetaClassBase.
128 *********************************************************************/
129
130 #if APPLE_KEXT_VTABLE_PADDING
131 /*********************************************************************
132 * Reserved vtable functions.
133 *********************************************************************/
134 #if SLOT_USED
135 void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
136 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 0); }
137 void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
138 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 1); }
139 void OSMetaClassBase::_RESERVEDOSMetaClassBase2()
140 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 2); }
141 #endif /* SLOT_USED */
142
143 // As these slots are used move them up inside the #if above
144 void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
145 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 3); }
146 void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
147 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 4); }
148 void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
149 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 5); }
150 void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
151 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 6); }
152 #endif
153
154 /*********************************************************************
155 * These used to be inline in the header but gcc didn't believe us
156 * Now we MUST pull the inline out at least until the compiler is
157 * repaired.
158 *
159 * Helper inlines for runtime type preprocessor macros
160 *********************************************************************/
161
162 /*********************************************************************
163 *********************************************************************/
164 OSMetaClassBase *
165 OSMetaClassBase::safeMetaCast(
166 const OSMetaClassBase * me,
167 const OSMetaClass * toType)
168 {
169 return (me)? me->metaCast(toType) : 0;
170 }
171
172 /*********************************************************************
173 *********************************************************************/
174 bool
175 OSMetaClassBase::checkTypeInst(
176 const OSMetaClassBase * inst,
177 const OSMetaClassBase * typeinst)
178 {
179 const OSMetaClass * toType = OSTypeIDInst(typeinst);
180 return typeinst && inst && (0 != inst->metaCast(toType));
181 }
182
183 /*********************************************************************
184 *********************************************************************/
185 void OSMetaClassBase::
186 initialize()
187 {
188 sAllClassesLock = IOLockAlloc();
189 sStalledClassesLock = IOLockAlloc();
190 sInstancesLock = IOLockAlloc();
191 }
192
193 #if APPLE_KEXT_VTABLE_PADDING
194 /*********************************************************************
195 * If you need this slot you had better setup an IOCTL style interface.
196 * 'Cause the whole kernel world depends on OSMetaClassBase and YOU
197 * CANT change the VTABLE size ever.
198 *********************************************************************/
199 void
200 OSMetaClassBase::_RESERVEDOSMetaClassBase7()
201 { panic("OSMetaClassBase::_RESERVEDOSMetaClassBase%d called.", 7); }
202 #endif
203
204 /*********************************************************************
205 *********************************************************************/
206 OSMetaClassBase::OSMetaClassBase()
207 {
208 }
209
210 /*********************************************************************
211 *********************************************************************/
212 OSMetaClassBase::~OSMetaClassBase()
213 {
214 void ** thisVTable;
215
216 thisVTable = (void **) this;
217 *thisVTable = (void *) -1UL;
218 }
219
220 /*********************************************************************
221 *********************************************************************/
222 bool
223 OSMetaClassBase::isEqualTo(const OSMetaClassBase * anObj) const
224 {
225 return this == anObj;
226 }
227
228 /*********************************************************************
229 *********************************************************************/
230 OSMetaClassBase *
231 OSMetaClassBase::metaCast(const OSMetaClass * toMeta) const
232 {
233 return toMeta->checkMetaCast(this);
234 }
235
236 /*********************************************************************
237 *********************************************************************/
238 OSMetaClassBase *
239 OSMetaClassBase::metaCast(const OSSymbol * toMetaSymb) const
240 {
241 return OSMetaClass::checkMetaCastWithName(toMetaSymb, this);
242 }
243
244 /*********************************************************************
245 *********************************************************************/
246 OSMetaClassBase *
247 OSMetaClassBase::metaCast(const OSString * toMetaStr) const
248 {
249 const OSSymbol * tempSymb = OSSymbol::withString(toMetaStr);
250 OSMetaClassBase * ret = 0;
251 if (tempSymb) {
252 ret = metaCast(tempSymb);
253 tempSymb->release();
254 }
255 return ret;
256 }
257
258 /*********************************************************************
259 *********************************************************************/
260 OSMetaClassBase *
261 OSMetaClassBase::metaCast(const char * toMetaCStr) const
262 {
263 const OSSymbol * tempSymb = OSSymbol::withCString(toMetaCStr);
264 OSMetaClassBase * ret = 0;
265 if (tempSymb) {
266 ret = metaCast(tempSymb);
267 tempSymb->release();
268 }
269 return ret;
270 }
271
272 #if PRAGMA_MARK
273 #pragma mark OSMetaClassMeta
274 #endif /* PRAGMA_MARK */
275 /*********************************************************************
276 * OSMetaClassMeta - the bootstrap metaclass of OSMetaClass
277 *********************************************************************/
278 class OSMetaClassMeta : public OSMetaClass
279 {
280 public:
281 OSMetaClassMeta();
282 OSObject * alloc() const;
283 };
284 OSMetaClassMeta::OSMetaClassMeta()
285 : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass))
286 { }
287 OSObject * OSMetaClassMeta::alloc() const { return 0; }
288
289 static OSMetaClassMeta sOSMetaClassMeta;
290
291 const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta;
292 const OSMetaClass * OSMetaClass::getMetaClass() const
293 { return &sOSMetaClassMeta; }
294
295 #if PRAGMA_MARK
296 #pragma mark OSMetaClass
297 #endif /* PRAGMA_MARK */
298 /*********************************************************************
299 * OSMetaClass
300 *********************************************************************/
301
302 #if APPLE_KEXT_VTABLE_PADDING
303 /*********************************************************************
304 * Reserved functions.
305 *********************************************************************/
306 void OSMetaClass::_RESERVEDOSMetaClass0()
307 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 0); }
308 void OSMetaClass::_RESERVEDOSMetaClass1()
309 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 1); }
310 void OSMetaClass::_RESERVEDOSMetaClass2()
311 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 2); }
312 void OSMetaClass::_RESERVEDOSMetaClass3()
313 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 3); }
314 void OSMetaClass::_RESERVEDOSMetaClass4()
315 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 4); }
316 void OSMetaClass::_RESERVEDOSMetaClass5()
317 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 5); }
318 void OSMetaClass::_RESERVEDOSMetaClass6()
319 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 6); }
320 void OSMetaClass::_RESERVEDOSMetaClass7()
321 { panic("OSMetaClass::_RESERVEDOSMetaClass%d called", 7); }
322 #endif
323
324 /*********************************************************************
325 *********************************************************************/
326 static void
327 OSMetaClassLogErrorForKext(
328 OSReturn error,
329 OSKext * aKext)
330 {
331 const char * message = NULL;
332
333 switch (error) {
334 case kOSReturnSuccess:
335 return;
336 case kOSMetaClassNoInit: // xxx - never returned; logged at fail site
337 message = "OSMetaClass: preModLoad() wasn't called (runtime internal error).";
338 break;
339 case kOSMetaClassNoDicts:
340 message = "OSMetaClass: Allocation failure for OSMetaClass internal dictionaries.";
341 break;
342 case kOSMetaClassNoKModSet:
343 message = "OSMetaClass: Allocation failure for internal kext recording set/set missing.";
344 break;
345 case kOSMetaClassNoInsKModSet:
346 message = "OSMetaClass: Failed to record class in kext.";
347 break;
348 case kOSMetaClassDuplicateClass:
349 message = "OSMetaClass: Duplicate class encountered.";
350 break;
351 case kOSMetaClassNoSuper: // xxx - never returned
352 message = "OSMetaClass: Can't associate a class with its superclass.";
353 break;
354 case kOSMetaClassInstNoSuper: // xxx - never returned
355 message = "OSMetaClass: Instance construction error; unknown superclass.";
356 break;
357 case kOSMetaClassNoKext:
358 message = "OSMetaClass: Kext not found for metaclass.";
359 break;
360 case kOSMetaClassInternal:
361 default:
362 message = "OSMetaClass: Runtime internal error.";
363 break;
364 }
365
366 if (message) {
367 OSKextLog(aKext, kOSMetaClassLogSpec, "%s", message);
368 }
369 return;
370 }
371
372 void
373 OSMetaClass::logError(OSReturn error)
374 {
375 OSMetaClassLogErrorForKext(error, NULL);
376 }
377
378 /*********************************************************************
379 * The core constructor for a MetaClass (defined with this name always
380 * but within the scope of its represented class).
381 *
382 * MetaClass constructors are invoked in OSRuntimeInitializeCPP(),
383 * in between calls to OSMetaClass::preModLoad(), which sets up for
384 * registration, and OSMetaClass::postModLoad(), which actually
385 * records all the class/kext relationships of the new MetaClasses.
386 *********************************************************************/
387 OSMetaClass::OSMetaClass(
388 const char * inClassName,
389 const OSMetaClass * inSuperClass,
390 unsigned int inClassSize)
391 {
392 instanceCount = 0;
393 classSize = inClassSize;
394 superClassLink = inSuperClass;
395
396 reserved = IONew(ExpansionData, 1);
397 bzero(reserved, sizeof(ExpansionData));
398
399 /* Hack alert: We are just casting inClassName and storing it in
400 * an OSString * instance variable. This may be because you can't
401 * create C++ objects in static constructors, but I really don't know!
402 */
403 className = (const OSSymbol *)inClassName;
404
405 // sStalledClassesLock taken in preModLoad
406 if (!sStalled) {
407 /* There's no way we can look up the kext here, unfortunately.
408 */
409 OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
410 "OSMetaClass: preModLoad() wasn't called for class %s "
411 "(runtime internal error).",
412 inClassName);
413 } else if (!sStalled->result) {
414 // Grow stalled array if neccessary
415 if (sStalled->count >= sStalled->capacity) {
416 OSMetaClass **oldStalled = sStalled->classes;
417 int oldSize = sStalled->capacity * sizeof(OSMetaClass *);
418 int newSize = oldSize
419 + kKModCapacityIncrement * sizeof(OSMetaClass *);
420
421 sStalled->classes = (OSMetaClass **)kalloc(newSize);
422 if (!sStalled->classes) {
423 sStalled->classes = oldStalled;
424 sStalled->result = kOSMetaClassNoTempData;
425 return;
426 }
427
428 sStalled->capacity += kKModCapacityIncrement;
429 memmove(sStalled->classes, oldStalled, oldSize);
430 kfree(oldStalled, oldSize);
431 ACCUMSIZE(newSize - oldSize);
432 }
433
434 sStalled->classes[sStalled->count++] = this;
435 }
436 }
437
438 /*********************************************************************
439 *********************************************************************/
440 OSMetaClass::~OSMetaClass()
441 {
442 OSKext * myKext = reserved ? reserved->kext : 0; // do not release
443
444 /* Hack alert: 'className' is a C string during early C++ init, and
445 * is converted to a real OSSymbol only when we record the OSKext in
446 * OSMetaClass::postModLoad(). So only do this bit if we have an OSKext.
447 * We can't safely cast or check 'className'.
448 *
449 * Also, release className *after* calling into the kext,
450 * as removeClass() may access className.
451 */
452 IOLockLock(sAllClassesLock);
453 if (sAllClassesDict) {
454 if (myKext) {
455 sAllClassesDict->removeObject(className);
456 } else {
457 sAllClassesDict->removeObject((char *)className);
458 }
459 }
460 IOLockUnlock(sAllClassesLock);
461
462 if (myKext) {
463 if (myKext->removeClass(this) != kOSReturnSuccess) {
464 // xxx - what can we do?
465 }
466 className->release();
467 }
468
469 // sStalledClassesLock taken in preModLoad
470 if (sStalled) {
471 unsigned int i;
472
473 /* First pass find class in stalled list. If we find it that means
474 * we started C++ init with constructors but now we're tearing down
475 * because of some failure.
476 */
477 for (i = 0; i < sStalled->count; i++) {
478 if (this == sStalled->classes[i]) {
479 break;
480 }
481 }
482
483 /* Remove this metaclass from the stalled list so postModLoad() doesn't
484 * try to register it.
485 */
486 if (i < sStalled->count) {
487 sStalled->count--;
488 if (i < sStalled->count) {
489 memmove(&sStalled->classes[i], &sStalled->classes[i+1],
490 (sStalled->count - i) * sizeof(OSMetaClass *));
491 }
492 }
493 }
494 }
495
496 /*********************************************************************
497 * Empty overrides.
498 *********************************************************************/
499 void * OSMetaClass::operator new(__unused size_t size) { return 0; }
500 void OSMetaClass::retain() const { }
501 void OSMetaClass::release() const { }
502 void OSMetaClass::release(__unused int when) const { }
503 void OSMetaClass::taggedRetain(__unused const void * tag) const { }
504 void OSMetaClass::taggedRelease(__unused const void * tag) const { }
505 void OSMetaClass::taggedRelease(__unused const void * tag, __unused const int when) const { }
506 int OSMetaClass::getRetainCount() const { return 0; }
507
508 /*********************************************************************
509 *********************************************************************/
510 const char *
511 OSMetaClass::getClassName() const
512 {
513 if (!className) return NULL;
514 return className->getCStringNoCopy();
515 }
516 /*********************************************************************
517 *********************************************************************/
518 const OSSymbol *
519 OSMetaClass::getClassNameSymbol() const
520 {
521 return className;
522 }
523 /*********************************************************************
524 *********************************************************************/
525 unsigned int
526 OSMetaClass::getClassSize() const
527 {
528 return classSize;
529 }
530
531 /*********************************************************************
532 *********************************************************************/
533 void *
534 OSMetaClass::preModLoad(const char * kextIdentifier)
535 {
536 IOLockLock(sStalledClassesLock);
537
538 assert (sStalled == NULL);
539 sStalled = (StalledData *)kalloc(sizeof(* sStalled));
540 if (sStalled) {
541 sStalled->classes = (OSMetaClass **)
542 kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *));
543 if (!sStalled->classes) {
544 kfree(sStalled, sizeof(*sStalled));
545 return 0;
546 }
547 ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) +
548 sizeof(*sStalled));
549
550 sStalled->result = kOSReturnSuccess;
551 sStalled->capacity = kKModCapacityIncrement;
552 sStalled->count = 0;
553 sStalled->kextIdentifier = kextIdentifier;
554 bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *));
555 }
556
557 // keep sStalledClassesLock locked until postModLoad
558
559 return sStalled;
560 }
561
562 /*********************************************************************
563 *********************************************************************/
564 bool
565 OSMetaClass::checkModLoad(void * loadHandle)
566 {
567 return sStalled && loadHandle == sStalled &&
568 sStalled->result == kOSReturnSuccess;
569 }
570
571 /*********************************************************************
572 *********************************************************************/
573 OSReturn
574 OSMetaClass::postModLoad(void * loadHandle)
575 {
576 OSReturn result = kOSReturnSuccess;
577 OSSymbol * myKextName = 0; // must release
578 OSKext * myKext = 0; // must release
579
580 if (!sStalled || loadHandle != sStalled) {
581 result = kOSMetaClassInternal;
582 goto finish;
583 }
584
585 if (sStalled->result) {
586 result = sStalled->result;
587 } else switch (sBootstrapState) {
588
589 case kNoDictionaries:
590 sBootstrapState = kMakingDictionaries;
591 // No break; fall through
592
593 case kMakingDictionaries:
594 sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement);
595 if (!sAllClassesDict) {
596 result = kOSMetaClassNoDicts;
597 break;
598 }
599 sAllClassesDict->setOptions(OSCollection::kSort, OSCollection::kSort);
600
601 // No break; fall through
602
603 case kCompletedBootstrap:
604 {
605 unsigned int i;
606 myKextName = const_cast<OSSymbol *>(OSSymbol::withCStringNoCopy(
607 sStalled->kextIdentifier));
608
609 if (!sStalled->count) {
610 break; // Nothing to do so just get out
611 }
612
613 myKext = OSKext::lookupKextWithIdentifier(myKextName);
614 if (!myKext) {
615 result = kOSMetaClassNoKext;
616
617 /* Log this error here so we can include the kext name.
618 */
619 OSKextLog(/* kext */ NULL, kOSMetaClassLogSpec,
620 "OSMetaClass: Can't record classes for kext %s - kext not found.",
621 sStalled->kextIdentifier);
622 break;
623 }
624
625 /* First pass checking classes aren't already loaded. If any already
626 * exist, we don't register any, and so we don't technically have
627 * to do any C++ teardown.
628 *
629 * Hack alert: me->className has been a C string until now.
630 * We only release the OSSymbol if we store the kext.
631 */
632 IOLockLock(sAllClassesLock);
633 for (i = 0; i < sStalled->count; i++) {
634 const OSMetaClass * me = sStalled->classes[i];
635 OSMetaClass * orig = OSDynamicCast(OSMetaClass,
636 sAllClassesDict->getObject((const char *)me->className));
637
638 if (orig) {
639
640 /* Log this error here so we can include the class name.
641 * xxx - we should look up the other kext that defines the class
642 */
643 OSKextLog(myKext, kOSMetaClassLogSpec,
644 "OSMetaClass: Kext %s class %s is a duplicate;"
645 "kext %s already has a class by that name.",
646 sStalled->kextIdentifier, (const char *)me->className,
647 ((OSKext *)orig->reserved->kext)->getIdentifierCString());
648 result = kOSMetaClassDuplicateClass;
649 break;
650 }
651 unsigned int depth = 1;
652 while ((me = me->superClassLink)) depth++;
653 if (depth > sDeepestClass) sDeepestClass = depth;
654 }
655 IOLockUnlock(sAllClassesLock);
656
657 /* Bail if we didn't go through the entire list of new classes
658 * (if we hit a duplicate).
659 */
660 if (i != sStalled->count) {
661 break;
662 }
663
664 // Second pass symbolling strings and inserting classes in dictionary
665 IOLockLock(sAllClassesLock);
666 for (i = 0; i < sStalled->count; i++) {
667 OSMetaClass * me = sStalled->classes[i];
668
669 /* Hack alert: me->className has been a C string until now.
670 * We only release the OSSymbol in ~OSMetaClass()
671 * if we set the reference to the kext.
672 */
673 me->className =
674 OSSymbol::withCStringNoCopy((const char *)me->className);
675
676 // xxx - I suppose if these fail we're going to panic soon....
677 sAllClassesDict->setObject(me->className, me);
678
679 /* Do not retain the kext object here.
680 */
681 me->reserved->kext = myKext;
682 if (myKext) {
683 result = myKext->addClass(me, sStalled->count);
684 if (result != kOSReturnSuccess) {
685 /* OSKext::addClass() logs with kOSMetaClassNoInsKModSet. */
686 break;
687 }
688 }
689 }
690 IOLockUnlock(sAllClassesLock);
691 sBootstrapState = kCompletedBootstrap;
692 break;
693 }
694
695 default:
696 result = kOSMetaClassInternal;
697 break;
698 }
699
700 finish:
701 /* Don't call logError() for success or the conditions logged above
702 * or by called function.
703 */
704 if (result != kOSReturnSuccess &&
705 result != kOSMetaClassNoInsKModSet &&
706 result != kOSMetaClassDuplicateClass &&
707 result != kOSMetaClassNoKext) {
708
709 OSMetaClassLogErrorForKext(result, myKext);
710 }
711
712 OSSafeRelease(myKextName);
713 OSSafeRelease(myKext);
714
715 if (sStalled) {
716 ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) +
717 sizeof(*sStalled)));
718 kfree(sStalled->classes, sStalled->capacity * sizeof(OSMetaClass *));
719 kfree(sStalled, sizeof(*sStalled));
720 sStalled = 0;
721 }
722
723 IOLockUnlock(sStalledClassesLock);
724
725 return result;
726 }
727
728
729 /*********************************************************************
730 *********************************************************************/
731 void
732 OSMetaClass::instanceConstructed() const
733 {
734 // if ((0 == OSIncrementAtomic(&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
735 if ((0 == OSIncrementAtomic(&instanceCount)) && superClassLink) {
736 superClassLink->instanceConstructed();
737 }
738 }
739
740 /*********************************************************************
741 *********************************************************************/
742 void
743 OSMetaClass::instanceDestructed() const
744 {
745 if ((1 == OSDecrementAtomic(&instanceCount)) && superClassLink) {
746 superClassLink->instanceDestructed();
747 }
748
749 if (((int)instanceCount) < 0) {
750 OSKext * myKext = reserved->kext;
751
752 OSKextLog(myKext, kOSMetaClassLogSpec,
753 // xxx - this phrasing is rather cryptic
754 "OSMetaClass: Class %s - bad retain (%d)",
755 getClassName(), instanceCount);
756 }
757 }
758
759 /*********************************************************************
760 *********************************************************************/
761 bool
762 OSMetaClass::modHasInstance(const char * kextIdentifier)
763 {
764 bool result = false;
765 OSKext * theKext = NULL; // must release
766
767 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
768 if (!theKext) {
769 goto finish;
770 }
771
772 result = theKext->hasOSMetaClassInstances();
773
774 finish:
775 OSSafeRelease(theKext);
776 return result;
777 }
778
779 /*********************************************************************
780 *********************************************************************/
781 void
782 OSMetaClass::reportModInstances(const char * kextIdentifier)
783 {
784 OSKext::reportOSMetaClassInstances(kextIdentifier,
785 kOSKextLogExplicitLevel);
786 return;
787 }
788 /*********************************************************************
789 *********************************************************************/
790
791 void
792 OSMetaClass::addInstance(const OSObject * instance, bool super) const
793 {
794 if (!super) IOLockLock(sInstancesLock);
795
796 if (!reserved->instances) {
797 reserved->instances = OSOrderedSet::withCapacity(16);
798 if (superClassLink) {
799 superClassLink->addInstance(reserved->instances, true);
800 }
801 }
802 reserved->instances->setLastObject(instance);
803
804 if (!super) IOLockUnlock(sInstancesLock);
805 }
806
807 void
808 OSMetaClass::removeInstance(const OSObject * instance, bool super) const
809 {
810 if (!super) IOLockLock(sInstancesLock);
811
812 if (reserved->instances) {
813 reserved->instances->removeObject(instance);
814 if (0 == reserved->instances->getCount()) {
815 if (superClassLink) {
816 superClassLink->removeInstance(reserved->instances, true);
817 }
818 reserved->instances->release();
819 reserved->instances = 0;
820 }
821 }
822
823 if (!super) IOLockUnlock(sInstancesLock);
824 }
825
826 void
827 OSMetaClass::applyToInstances(OSOrderedSet * set,
828 OSMetaClassInstanceApplierFunction applier,
829 void * context)
830 {
831 enum { kLocalDepth = 24 };
832 unsigned int _nextIndex[kLocalDepth];
833 OSOrderedSet * _sets[kLocalDepth];
834 unsigned int * nextIndex = &_nextIndex[0];
835 OSOrderedSet ** sets = &_sets[0];
836 OSObject * obj;
837 OSOrderedSet * childSet;
838 unsigned int maxDepth;
839 unsigned int idx;
840 unsigned int level;
841 bool done;
842
843 maxDepth = sDeepestClass;
844 if (maxDepth > kLocalDepth)
845 {
846 nextIndex = IONew(typeof(nextIndex[0]), maxDepth);
847 sets = IONew(typeof(sets[0]), maxDepth);
848 }
849 done = false;
850 level = 0;
851 idx = 0;
852 do
853 {
854 while (!done && (obj = set->getObject(idx++)))
855 {
856 if ((childSet = OSDynamicCast(OSOrderedSet, obj)))
857 {
858 if (level >= maxDepth) panic(">maxDepth");
859 sets[level] = set;
860 nextIndex[level] = idx;
861 level++;
862 set = childSet;
863 idx = 0;
864 break;
865 }
866 done = (*applier)(obj, context);
867 }
868 if (!obj)
869 {
870 if (!done && level)
871 {
872 level--;
873 set = sets[level];
874 idx = nextIndex[level];
875 } else done = true;
876 }
877 }
878 while (!done);
879 if (maxDepth > kLocalDepth)
880 {
881 IODelete(nextIndex, typeof(nextIndex[0]), maxDepth);
882 IODelete(sets, typeof(sets[0]), maxDepth);
883 }
884 }
885
886 void
887 OSMetaClass::applyToInstances(OSMetaClassInstanceApplierFunction applier,
888 void * context) const
889 {
890 IOLockLock(sInstancesLock);
891 if (reserved->instances) applyToInstances(reserved->instances, applier, context);
892 IOLockUnlock(sInstancesLock);
893 }
894
895 void
896 OSMetaClass::applyToInstancesOfClassName(
897 const OSSymbol * name,
898 OSMetaClassInstanceApplierFunction applier,
899 void * context)
900 {
901 OSMetaClass * meta;
902 OSOrderedSet * set = 0;
903
904 IOLockLock(sAllClassesLock);
905 if (sAllClassesDict
906 && (meta = (OSMetaClass *) sAllClassesDict->getObject(name))
907 && (set = meta->reserved->instances))
908 {
909 set->retain();
910 }
911 IOLockUnlock(sAllClassesLock);
912
913 if (!set) return;
914
915 IOLockLock(sInstancesLock);
916 applyToInstances(set, applier, context);
917 IOLockUnlock(sInstancesLock);
918 set->release();
919 }
920
921 /*********************************************************************
922 *********************************************************************/
923 void
924 OSMetaClass::considerUnloads()
925 {
926 OSKext::considerUnloads();
927 }
928
929 /*********************************************************************
930 *********************************************************************/
931 const OSMetaClass *
932 OSMetaClass::getMetaClassWithName(const OSSymbol * name)
933 {
934 OSMetaClass * retMeta = 0;
935
936 if (!name) {
937 return 0;
938 }
939
940 IOLockLock(sAllClassesLock);
941 if (sAllClassesDict) {
942 retMeta = (OSMetaClass *) sAllClassesDict->getObject(name);
943 }
944 IOLockUnlock(sAllClassesLock);
945
946 return retMeta;
947 }
948
949 /*********************************************************************
950 *********************************************************************/
951 OSObject *
952 OSMetaClass::allocClassWithName(const OSSymbol * name)
953 {
954 OSObject * result = 0;
955
956 const OSMetaClass * const meta = getMetaClassWithName(name);
957
958 if (meta) {
959 result = meta->alloc();
960 }
961
962 return result;
963 }
964
965 /*********************************************************************
966 *********************************************************************/
967 OSObject *
968 OSMetaClass::allocClassWithName(const OSString * name)
969 {
970 const OSSymbol * tmpKey = OSSymbol::withString(name);
971 OSObject * result = allocClassWithName(tmpKey);
972 tmpKey->release();
973 return result;
974 }
975
976 /*********************************************************************
977 *********************************************************************/
978 OSObject *
979 OSMetaClass::allocClassWithName(const char * name)
980 {
981 const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name);
982 OSObject * result = allocClassWithName(tmpKey);
983 tmpKey->release();
984 return result;
985 }
986
987
988 /*********************************************************************
989 *********************************************************************/
990 OSMetaClassBase *
991 OSMetaClass::checkMetaCastWithName(
992 const OSSymbol * name,
993 const OSMetaClassBase * in)
994 {
995 OSMetaClassBase * result = 0;
996
997 const OSMetaClass * const meta = getMetaClassWithName(name);
998
999 if (meta) {
1000 result = meta->checkMetaCast(in);
1001 }
1002
1003 return result;
1004 }
1005
1006 /*********************************************************************
1007 *********************************************************************/
1008 OSMetaClassBase * OSMetaClass::
1009 checkMetaCastWithName(
1010 const OSString * name,
1011 const OSMetaClassBase * in)
1012 {
1013 const OSSymbol * tmpKey = OSSymbol::withString(name);
1014 OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
1015
1016 tmpKey->release();
1017 return result;
1018 }
1019
1020 /*********************************************************************
1021 *********************************************************************/
1022 OSMetaClassBase *
1023 OSMetaClass::checkMetaCastWithName(
1024 const char * name,
1025 const OSMetaClassBase * in)
1026 {
1027 const OSSymbol * tmpKey = OSSymbol::withCStringNoCopy(name);
1028 OSMetaClassBase * result = checkMetaCastWithName(tmpKey, in);
1029
1030 tmpKey->release();
1031 return result;
1032 }
1033
1034 /*********************************************************************
1035 * OSMetaClass::checkMetaCast()
1036 * Check to see if the 'check' object has this object in its metaclass chain.
1037 * Returns check if it is indeed a kind of the current meta class, 0 otherwise.
1038 *
1039 * Generally this method is not invoked directly but is used to implement
1040 * the OSMetaClassBase::metaCast member function.
1041 *
1042 * See also OSMetaClassBase::metaCast
1043 *********************************************************************/
1044 OSMetaClassBase * OSMetaClass::checkMetaCast(
1045 const OSMetaClassBase * check) const
1046 {
1047 const OSMetaClass * const toMeta = this;
1048 const OSMetaClass * fromMeta;
1049
1050 for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) {
1051 if (toMeta == fromMeta) {
1052 return const_cast<OSMetaClassBase *>(check); // Discard const
1053 }
1054 if (!fromMeta->superClassLink) {
1055 break;
1056 }
1057 }
1058
1059 return 0;
1060 }
1061
1062 /*********************************************************************
1063 *********************************************************************/
1064 void
1065 OSMetaClass::reservedCalled(int ind) const
1066 {
1067 const char * cname = className->getCStringNoCopy();
1068 panic("%s::_RESERVED%s%d called.", cname, cname, ind);
1069 }
1070
1071 /*********************************************************************
1072 *********************************************************************/
1073 const
1074 OSMetaClass *
1075 OSMetaClass::getSuperClass() const
1076 {
1077 return superClassLink;
1078 }
1079
1080 /*********************************************************************
1081 * xxx - I want to rename this :-/
1082 *********************************************************************/
1083 const OSSymbol *
1084 OSMetaClass::getKmodName() const
1085 {
1086 OSKext * myKext = reserved ? reserved->kext : 0;
1087 if (myKext) {
1088 return myKext->getIdentifier();
1089 }
1090 return OSSymbol::withCStringNoCopy("unknown");
1091 }
1092
1093 /*********************************************************************
1094 *********************************************************************/
1095 unsigned int
1096 OSMetaClass::getInstanceCount() const
1097 {
1098 return instanceCount;
1099 }
1100
1101 /*********************************************************************
1102 *********************************************************************/
1103 /* static */
1104 void
1105 OSMetaClass::printInstanceCounts()
1106 {
1107 OSCollectionIterator * classes;
1108 OSSymbol * className;
1109 OSMetaClass * meta;
1110
1111 IOLockLock(sAllClassesLock);
1112 classes = OSCollectionIterator::withCollection(sAllClassesDict);
1113 assert(classes);
1114
1115 while( (className = (OSSymbol *)classes->getNextObject())) {
1116 meta = (OSMetaClass *)sAllClassesDict->getObject(className);
1117 assert(meta);
1118
1119 printf("%24s count: %03d x 0x%03x = 0x%06x\n",
1120 className->getCStringNoCopy(),
1121 meta->getInstanceCount(),
1122 meta->getClassSize(),
1123 meta->getInstanceCount() * meta->getClassSize() );
1124 }
1125 printf("\n");
1126 classes->release();
1127 IOLockUnlock(sAllClassesLock);
1128 return;
1129 }
1130
1131 /*********************************************************************
1132 *********************************************************************/
1133 OSDictionary *
1134 OSMetaClass::getClassDictionary()
1135 {
1136 panic("OSMetaClass::getClassDictionary() is obsoleted.\n");
1137 return 0;
1138 }
1139
1140 /*********************************************************************
1141 *********************************************************************/
1142 bool
1143 OSMetaClass::serialize(__unused OSSerialize * s) const
1144 {
1145 panic("OSMetaClass::serialize(): Obsoleted\n");
1146 return false;
1147 }
1148
1149 /*********************************************************************
1150 *********************************************************************/
1151 /* static */
1152 void
1153 OSMetaClass::serializeClassDictionary(OSDictionary * serializeDictionary)
1154 {
1155 OSDictionary * classDict = NULL;
1156
1157 IOLockLock(sAllClassesLock);
1158
1159 classDict = OSDictionary::withCapacity(sAllClassesDict->getCount());
1160 if (!classDict) {
1161 goto finish;
1162 }
1163
1164 do {
1165 OSCollectionIterator * classes;
1166 const OSSymbol * className;
1167
1168 classes = OSCollectionIterator::withCollection(sAllClassesDict);
1169 if (!classes) {
1170 break;
1171 }
1172
1173 while ((className = (const OSSymbol *)classes->getNextObject())) {
1174 const OSMetaClass * meta;
1175 OSNumber * count;
1176
1177 meta = (OSMetaClass *)sAllClassesDict->getObject(className);
1178 count = OSNumber::withNumber(meta->getInstanceCount(), 32);
1179 if (count) {
1180 classDict->setObject(className, count);
1181 count->release();
1182 }
1183 }
1184 classes->release();
1185
1186 serializeDictionary->setObject("Classes", classDict);
1187 } while (0);
1188
1189 finish:
1190 OSSafeRelease(classDict);
1191
1192 IOLockUnlock(sAllClassesLock);
1193
1194 return;
1195 }