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