2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
25 /* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */
28 #include <sys/systm.h>
30 #include <libkern/OSReturn.h>
32 #include <libkern/c++/OSMetaClass.h>
34 #include <libkern/c++/OSObject.h>
35 #include <libkern/c++/OSCollectionIterator.h>
36 #include <libkern/c++/OSDictionary.h>
37 #include <libkern/c++/OSArray.h>
38 #include <libkern/c++/OSSet.h>
39 #include <libkern/c++/OSSymbol.h>
40 #include <libkern/c++/OSNumber.h>
41 #include <libkern/c++/OSSerialize.h>
42 #include <libkern/c++/OSLib.h>
43 #include <libkern/OSAtomic.h>
47 #include <mach/mach_types.h>
48 #include <mach/etap_events.h>
49 #include <kern/lock.h>
50 #include <kern/clock.h>
51 #include <kern/thread_call.h>
52 #include <kern/host.h>
53 #include <mach/kmod.h>
54 #include <mach/mach_interface.h>
56 extern void OSRuntimeUnloadCPP(kmod_info_t
*ki
, void *);
59 extern int debug_container_malloc_size
;
60 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
63 #endif /* OSALLOCDEBUG */
68 kCompletedBootstrap
= 0,
70 kMakingDictionaries
= 2
71 } sBootstrapState
= kNoDictionaries
;
73 static const int kClassCapacityIncrement
= 40;
74 static const int kKModCapacityIncrement
= 10;
75 static OSDictionary
*sAllClassesDict
, *sKModClassesDict
;
77 static mutex_t
*loadLock
;
78 static struct StalledData
{
81 unsigned int capacity
;
83 OSMetaClass
**classes
;
86 static unsigned int sConsiderUnloadDelay
= 60; /* secs */
88 static const char OSMetaClassBasePanicMsg
[] =
89 "OSMetaClassBase::_RESERVEDOSMetaClassBase%d called\n";
92 void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
93 { panic(OSMetaClassBasePanicMsg
, 0); }
94 void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
95 { panic(OSMetaClassBasePanicMsg
, 1); }
96 void OSMetaClassBase::_RESERVEDOSMetaClassBase2()
97 { panic(OSMetaClassBasePanicMsg
, 2); }
98 #endif /* SLOT_USED */
100 // As these slots are used move them up inside the #if above
101 void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
102 { panic(OSMetaClassBasePanicMsg
, 3); }
103 void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
104 { panic(OSMetaClassBasePanicMsg
, 4); }
105 void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
106 { panic(OSMetaClassBasePanicMsg
, 5); }
107 void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
108 { panic(OSMetaClassBasePanicMsg
, 6); }
111 * These used to be inline in the header but gcc didn't believe us
112 * Now we MUST pull the inline out at least until the compiler is
115 // Helper inlines for runtime type preprocessor macros
116 OSMetaClassBase
*OSMetaClassBase::
117 safeMetaCast(const OSMetaClassBase
*me
, const OSMetaClass
*toType
)
118 { return (me
)? me
->metaCast(toType
) : 0; }
120 bool OSMetaClassBase::
121 checkTypeInst(const OSMetaClassBase
*inst
, const OSMetaClassBase
*typeinst
)
123 const OSMetaClass
*toType
= OSTypeIDInst(typeinst
);
124 return typeinst
&& inst
&& (0 != inst
->metaCast(toType
));
128 // If you need this slot you had better setup an IOCTL style interface.
129 // 'Cause the whole kernel world depends on OSMetaClassBase and YOU
130 // CANT change the VTABLE size ever.
131 void OSMetaClassBase::_RESERVEDOSMetaClassBase7()
132 { panic(OSMetaClassBasePanicMsg
, 7); }
134 OSMetaClassBase::OSMetaClassBase()
138 OSMetaClassBase::~OSMetaClassBase()
142 thisVTable
= (void **) this;
143 *thisVTable
= (void *) -1UL;
146 bool OSMetaClassBase::isEqualTo(const OSMetaClassBase
*anObj
) const
148 return this == anObj
;
151 OSMetaClassBase
*OSMetaClassBase::metaCast(const OSMetaClass
*toMeta
) const
153 return toMeta
->checkMetaCast(this);
156 OSMetaClassBase
*OSMetaClassBase::metaCast(const OSSymbol
*toMetaSymb
) const
158 return OSMetaClass::checkMetaCastWithName(toMetaSymb
, this);
161 OSMetaClassBase
*OSMetaClassBase::metaCast(const OSString
*toMetaStr
) const
163 const OSSymbol
*tempSymb
= OSSymbol::withString(toMetaStr
);
164 OSMetaClassBase
*ret
= 0;
166 ret
= metaCast(tempSymb
);
172 OSMetaClassBase
*OSMetaClassBase::metaCast(const char *toMetaCStr
) const
174 const OSSymbol
*tempSymb
= OSSymbol::withCString(toMetaCStr
);
175 OSMetaClassBase
*ret
= 0;
177 ret
= metaCast(tempSymb
);
183 class OSMetaClassMeta
: public OSMetaClass
187 OSObject
*alloc() const;
189 OSMetaClassMeta::OSMetaClassMeta()
190 : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass
))
192 OSObject
*OSMetaClassMeta::alloc() const { return 0; }
194 static OSMetaClassMeta sOSMetaClassMeta
;
196 const OSMetaClass
* const OSMetaClass::metaClass
= &sOSMetaClassMeta
;
197 const OSMetaClass
* OSMetaClass::getMetaClass() const
198 { return &sOSMetaClassMeta
; }
200 static const char OSMetaClassPanicMsg
[] =
201 "OSMetaClass::_RESERVEDOSMetaClass%d called\n";
203 void OSMetaClass::_RESERVEDOSMetaClass0()
204 { panic(OSMetaClassPanicMsg
, 0); }
205 void OSMetaClass::_RESERVEDOSMetaClass1()
206 { panic(OSMetaClassPanicMsg
, 1); }
207 void OSMetaClass::_RESERVEDOSMetaClass2()
208 { panic(OSMetaClassPanicMsg
, 2); }
209 void OSMetaClass::_RESERVEDOSMetaClass3()
210 { panic(OSMetaClassPanicMsg
, 3); }
211 void OSMetaClass::_RESERVEDOSMetaClass4()
212 { panic(OSMetaClassPanicMsg
, 4); }
213 void OSMetaClass::_RESERVEDOSMetaClass5()
214 { panic(OSMetaClassPanicMsg
, 5); }
215 void OSMetaClass::_RESERVEDOSMetaClass6()
216 { panic(OSMetaClassPanicMsg
, 6); }
217 void OSMetaClass::_RESERVEDOSMetaClass7()
218 { panic(OSMetaClassPanicMsg
, 7); }
220 void OSMetaClass::logError(OSReturn result
)
225 case kOSMetaClassNoInit
:
226 msg
="OSMetaClass::preModLoad wasn't called, runtime internal error";
228 case kOSMetaClassNoDicts
:
229 msg
="Allocation failure for Metaclass internal dictionaries"; break;
230 case kOSMetaClassNoKModSet
:
231 msg
="Allocation failure for internal kmodule set"; break;
232 case kOSMetaClassNoInsKModSet
:
233 msg
="Can't insert the KMod set into the module dictionary"; break;
234 case kOSMetaClassDuplicateClass
:
235 msg
="Duplicate class"; break;
236 case kOSMetaClassNoSuper
:
237 msg
="Can't associate a class with its super class"; break;
238 case kOSMetaClassInstNoSuper
:
239 msg
="Instance construction, unknown super class."; break;
241 case kOSMetaClassInternal
:
242 msg
="runtime internal error"; break;
243 case kOSReturnSuccess
:
249 OSMetaClass::OSMetaClass(const char *inClassName
,
250 const OSMetaClass
*inSuperClass
,
251 unsigned int inClassSize
)
254 classSize
= inClassSize
;
255 superClassLink
= inSuperClass
;
257 className
= (const OSSymbol
*) inClassName
;
260 printf("OSMetaClass::preModLoad wasn't called for %s, "
261 "runtime internal error\n", inClassName
);
262 } else if (!sStalled
->result
) {
263 // Grow stalled array if neccessary
264 if (sStalled
->count
>= sStalled
->capacity
) {
265 OSMetaClass
**oldStalled
= sStalled
->classes
;
266 int oldSize
= sStalled
->capacity
* sizeof(OSMetaClass
*);
267 int newSize
= oldSize
268 + kKModCapacityIncrement
* sizeof(OSMetaClass
*);
270 sStalled
->classes
= (OSMetaClass
**) kalloc(newSize
);
271 if (!sStalled
->classes
) {
272 sStalled
->classes
= oldStalled
;
273 sStalled
->result
= kOSMetaClassNoTempData
;
277 sStalled
->capacity
+= kKModCapacityIncrement
;
278 memmove(sStalled
->classes
, oldStalled
, oldSize
);
279 kfree((vm_offset_t
)oldStalled
, oldSize
);
280 ACCUMSIZE(newSize
- oldSize
);
283 sStalled
->classes
[sStalled
->count
++] = this;
287 OSMetaClass::~OSMetaClass()
290 OSCollectionIterator
*iter
;
293 sAllClassesDict
->removeObject(className
);
295 iter
= OSCollectionIterator::withCollection(sKModClassesDict
);
300 while ( (iterKey
= (OSSymbol
*) iter
->getNextObject()) ) {
302 kmodClassSet
= (OSSet
*) sKModClassesDict
->getObject(iterKey
);
303 if (kmodClassSet
&& kmodClassSet
->containsObject(this)) {
304 kmodClassSet
->removeObject(this);
314 // First pass find class in stalled list
315 for (i
= 0; i
< sStalled
->count
; i
++)
316 if (this == sStalled
->classes
[i
])
319 if (i
< sStalled
->count
) {
321 if (i
< sStalled
->count
)
322 memmove(&sStalled
->classes
[i
], &sStalled
->classes
[i
+1],
323 (sStalled
->count
- i
) * sizeof(OSMetaClass
*));
329 void *OSMetaClass::operator new(size_t size
) { return 0; }
330 void OSMetaClass::retain() const { }
331 void OSMetaClass::release() const { }
332 void OSMetaClass::release(int when
) const { }
333 void OSMetaClass::taggedRetain(const void *tag
) const { }
334 void OSMetaClass::taggedRelease(const void *tag
) const { }
335 void OSMetaClass::taggedRelease(const void *tag
, const int when
) const { }
336 int OSMetaClass::getRetainCount() const { return 0; }
338 const char *OSMetaClass::getClassName() const
340 return className
->getCStringNoCopy();
343 unsigned int OSMetaClass::getClassSize() const
348 void *OSMetaClass::preModLoad(const char *kmodName
)
351 loadLock
= mutex_alloc(ETAP_IO_AHA
);
352 mutex_lock(loadLock
);
355 mutex_lock(loadLock
);
357 sStalled
= (StalledData
*) kalloc(sizeof(*sStalled
));
359 sStalled
->classes
= (OSMetaClass
**)
360 kalloc(kKModCapacityIncrement
* sizeof(OSMetaClass
*));
361 if (!sStalled
->classes
) {
362 kfree((vm_offset_t
) sStalled
, sizeof(*sStalled
));
365 ACCUMSIZE((kKModCapacityIncrement
* sizeof(OSMetaClass
*)) + sizeof(*sStalled
));
367 sStalled
->result
= kOSReturnSuccess
;
368 sStalled
->capacity
= kKModCapacityIncrement
;
370 sStalled
->kmodName
= kmodName
;
371 bzero(sStalled
->classes
, kKModCapacityIncrement
* sizeof(OSMetaClass
*));
377 bool OSMetaClass::checkModLoad(void *loadHandle
)
379 return sStalled
&& loadHandle
== sStalled
380 && sStalled
->result
== kOSReturnSuccess
;
383 OSReturn
OSMetaClass::postModLoad(void *loadHandle
)
385 OSReturn result
= kOSReturnSuccess
;
388 if (!sStalled
|| loadHandle
!= sStalled
) {
389 logError(kOSMetaClassInternal
);
390 return kOSMetaClassInternal
;
393 if (sStalled
->result
)
394 result
= sStalled
->result
;
395 else switch (sBootstrapState
) {
396 case kNoDictionaries
:
397 sBootstrapState
= kMakingDictionaries
;
398 // No break; fall through
400 case kMakingDictionaries
:
401 sKModClassesDict
= OSDictionary::withCapacity(kKModCapacityIncrement
);
402 sAllClassesDict
= OSDictionary::withCapacity(kClassCapacityIncrement
);
403 if (!sAllClassesDict
|| !sKModClassesDict
) {
404 result
= kOSMetaClassNoDicts
;
407 // No break; fall through
409 case kCompletedBootstrap
:
413 if (!sStalled
->count
)
414 break; // Nothing to do so just get out
416 // First pass checking classes aren't already loaded
417 for (i
= 0; i
< sStalled
->count
; i
++) {
418 OSMetaClass
*me
= sStalled
->classes
[i
];
420 if (0 != sAllClassesDict
->getObject((const char *) me
->className
)) {
421 printf("Class \"%s\" is duplicate\n", (const char *) me
->className
);
422 result
= kOSMetaClassDuplicateClass
;
426 if (i
!= sStalled
->count
)
429 kmodSet
= OSSet::withCapacity(sStalled
->count
);
431 result
= kOSMetaClassNoKModSet
;
435 if (!sKModClassesDict
->setObject(sStalled
->kmodName
, kmodSet
)) {
436 result
= kOSMetaClassNoInsKModSet
;
440 // Second pass symbolling strings and inserting classes in dictionary
441 for (unsigned int i
= 0; i
< sStalled
->count
; i
++) {
442 OSMetaClass
*me
= sStalled
->classes
[i
];
444 OSSymbol::withCStringNoCopy((const char *) me
->className
);
446 sAllClassesDict
->setObject(me
->className
, me
);
447 kmodSet
->setObject(me
);
449 sBootstrapState
= kCompletedBootstrap
;
454 result
= kOSMetaClassInternal
;
462 ACCUMSIZE(-(sStalled
->capacity
* sizeof(OSMetaClass
*)
463 + sizeof(*sStalled
)));
464 kfree((vm_offset_t
) sStalled
->classes
,
465 sStalled
->capacity
* sizeof(OSMetaClass
*));
466 kfree((vm_offset_t
) sStalled
, sizeof(*sStalled
));
471 mutex_unlock(loadLock
);
476 void OSMetaClass::instanceConstructed() const
478 // if ((0 == OSIncrementAtomic((SInt32 *)&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
479 if ((0 == OSIncrementAtomic((SInt32
*) &instanceCount
)) && superClassLink
)
480 superClassLink
->instanceConstructed();
483 void OSMetaClass::instanceDestructed() const
485 if ((1 == OSDecrementAtomic((SInt32
*) &instanceCount
)) && superClassLink
)
486 superClassLink
->instanceDestructed();
488 if( ((int) instanceCount
) < 0)
489 printf("%s: bad retain(%d)", getClassName(), instanceCount
);
492 bool OSMetaClass::modHasInstance(const char *kmodName
)
497 loadLock
= mutex_alloc(ETAP_IO_AHA
);
498 mutex_lock(loadLock
);
501 mutex_lock(loadLock
);
505 OSCollectionIterator
*iter
;
506 OSMetaClass
*checkClass
;
508 kmodClasses
= OSDynamicCast(OSSet
,
509 sKModClassesDict
->getObject(kmodName
));
513 iter
= OSCollectionIterator::withCollection(kmodClasses
);
517 while ( (checkClass
= (OSMetaClass
*) iter
->getNextObject()) )
518 if (checkClass
->getInstanceCount()) {
526 mutex_unlock(loadLock
);
531 void OSMetaClass::reportModInstances(const char *kmodName
)
534 OSCollectionIterator
*iter
;
535 OSMetaClass
*checkClass
;
537 kmodClasses
= OSDynamicCast(OSSet
,
538 sKModClassesDict
->getObject(kmodName
));
542 iter
= OSCollectionIterator::withCollection(kmodClasses
);
546 while ( (checkClass
= (OSMetaClass
*) iter
->getNextObject()) )
547 if (checkClass
->getInstanceCount()) {
548 printf("%s: %s has %d instance(s)\n",
550 checkClass
->getClassName(),
551 checkClass
->getInstanceCount());
557 static void _OSMetaClassConsiderUnloads(thread_call_param_t p0
,
558 thread_call_param_t p1
)
562 OSCollectionIterator
*kmods
;
563 OSCollectionIterator
*classes
;
564 OSMetaClass
*checkClass
;
569 mutex_lock(loadLock
);
573 kmods
= OSCollectionIterator::withCollection(sKModClassesDict
);
578 while ( (kmodName
= (OSSymbol
*) kmods
->getNextObject()) ) {
581 kfree(ki
, sizeof(kmod_info_t
));
585 ki
= kmod_lookupbyname_locked((char *)kmodName
->getCStringNoCopy());
589 if (ki
->reference_count
) {
593 kmodClasses
= OSDynamicCast(OSSet
,
594 sKModClassesDict
->getObject(kmodName
));
595 classes
= OSCollectionIterator::withCollection(kmodClasses
);
599 while ((checkClass
= (OSMetaClass
*) classes
->getNextObject())
600 && (0 == checkClass
->getInstanceCount()))
604 if (0 == checkClass
) {
605 OSRuntimeUnloadCPP(ki
, 0); // call destructors
606 ret
= kmod_destroy(host_priv_self(), ki
->id
);
616 mutex_unlock(loadLock
);
619 void OSMetaClass::considerUnloads()
621 static thread_call_t unloadCallout
;
624 mutex_lock(loadLock
);
627 unloadCallout
= thread_call_allocate(&_OSMetaClassConsiderUnloads
, 0);
629 thread_call_cancel(unloadCallout
);
630 clock_interval_to_deadline(sConsiderUnloadDelay
, 1000 * 1000 * 1000, &when
);
631 thread_call_enter_delayed(unloadCallout
, when
);
633 mutex_unlock(loadLock
);
636 const OSMetaClass
*OSMetaClass::getMetaClassWithName(const OSSymbol
*name
)
638 OSMetaClass
*retMeta
= 0;
644 retMeta
= (OSMetaClass
*) sAllClassesDict
->getObject(name
);
646 if (!retMeta
&& sStalled
)
648 // Oh dear we have to scan the stalled list and walk the
649 // the stalled list manually.
650 const char *cName
= name
->getCStringNoCopy();
653 // find class in stalled list
654 for (i
= 0; i
< sStalled
->count
; i
++) {
655 retMeta
= sStalled
->classes
[i
];
656 if (0 == strcmp(cName
, (const char *) retMeta
->className
))
660 if (i
< sStalled
->count
)
667 OSObject
*OSMetaClass::allocClassWithName(const OSSymbol
*name
)
670 mutex_lock(loadLock
);
672 const OSMetaClass
* const meta
= getMetaClassWithName(name
);
675 result
= meta
->alloc();
679 mutex_unlock(loadLock
);
684 OSObject
*OSMetaClass::allocClassWithName(const OSString
*name
)
686 const OSSymbol
*tmpKey
= OSSymbol::withString(name
);
687 OSObject
*result
= allocClassWithName(tmpKey
);
692 OSObject
*OSMetaClass::allocClassWithName(const char *name
)
694 const OSSymbol
*tmpKey
= OSSymbol::withCStringNoCopy(name
);
695 OSObject
*result
= allocClassWithName(tmpKey
);
701 OSMetaClassBase
*OSMetaClass::
702 checkMetaCastWithName(const OSSymbol
*name
, const OSMetaClassBase
*in
)
704 OSMetaClassBase
* result
;
705 mutex_lock(loadLock
);
706 const OSMetaClass
* const meta
= getMetaClassWithName(name
);
709 result
= meta
->checkMetaCast(in
);
713 mutex_unlock(loadLock
);
717 OSMetaClassBase
*OSMetaClass::
718 checkMetaCastWithName(const OSString
*name
, const OSMetaClassBase
*in
)
720 const OSSymbol
*tmpKey
= OSSymbol::withString(name
);
721 OSMetaClassBase
*result
= checkMetaCastWithName(tmpKey
, in
);
726 OSMetaClassBase
*OSMetaClass::
727 checkMetaCastWithName(const char *name
, const OSMetaClassBase
*in
)
729 const OSSymbol
*tmpKey
= OSSymbol::withCStringNoCopy(name
);
730 OSMetaClassBase
*result
= checkMetaCastWithName(tmpKey
, in
);
736 OSMetaClass::checkMetaCast
737 checkMetaCast(const OSMetaClassBase *check)
739 Check to see if the 'check' object has this object in it's metaclass chain. Returns check if it is indeed a kind of the current meta class, 0 otherwise.
741 Generally this method is not invoked directly but is used to implement the OSMetaClassBase::metaCast member function.
743 See also OSMetaClassBase::metaCast
746 OSMetaClassBase
*OSMetaClass::checkMetaCast(const OSMetaClassBase
*check
) const
748 const OSMetaClass
* const toMeta
= this;
749 const OSMetaClass
*fromMeta
;
751 for (fromMeta
= check
->getMetaClass(); ; fromMeta
= fromMeta
->superClassLink
) {
752 if (toMeta
== fromMeta
)
753 return (OSMetaClassBase
*) check
; // Discard const
755 if (!fromMeta
->superClassLink
)
762 void OSMetaClass::reservedCalled(int ind
) const
764 const char *cname
= className
->getCStringNoCopy();
765 panic("%s::_RESERVED%s%d called\n", cname
, cname
, ind
);
768 const OSMetaClass
*OSMetaClass::getSuperClass() const
770 return superClassLink
;
773 unsigned int OSMetaClass::getInstanceCount() const
775 return instanceCount
;
778 void OSMetaClass::printInstanceCounts()
780 OSCollectionIterator
*classes
;
784 classes
= OSCollectionIterator::withCollection(sAllClassesDict
);
788 while( (className
= (OSSymbol
*)classes
->getNextObject())) {
789 meta
= (OSMetaClass
*) sAllClassesDict
->getObject(className
);
792 printf("%24s count: %03d x 0x%03x = 0x%06x\n",
793 className
->getCStringNoCopy(),
794 meta
->getInstanceCount(),
795 meta
->getClassSize(),
796 meta
->getInstanceCount() * meta
->getClassSize() );
802 OSDictionary
* OSMetaClass::getClassDictionary()
804 return sAllClassesDict
;
807 bool OSMetaClass::serialize(OSSerialize
*s
) const
813 if (s
->previouslySerialized(this)) return true;
815 dict
= 0;// IODictionary::withCapacity(2);
816 off
= OSNumber::withNumber(getInstanceCount(), 32);
819 dict
->setObject("InstanceCount", off
);
820 ok
= dict
->serialize(s
);
822 ok
= off
->serialize(s
);