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