2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
22 /* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */
25 #include <sys/systm.h>
27 #include <libkern/OSReturn.h>
29 #include <libkern/c++/OSMetaClass.h>
31 #include <libkern/c++/OSObject.h>
32 #include <libkern/c++/OSCollectionIterator.h>
33 #include <libkern/c++/OSDictionary.h>
34 #include <libkern/c++/OSArray.h>
35 #include <libkern/c++/OSSet.h>
36 #include <libkern/c++/OSSymbol.h>
37 #include <libkern/c++/OSNumber.h>
38 #include <libkern/c++/OSSerialize.h>
39 #include <libkern/c++/OSLib.h>
40 #include <libkern/OSAtomic.h>
44 #include <mach/mach_types.h>
45 #include <mach/etap_events.h>
46 #include <kern/lock.h>
47 #include <kern/clock.h>
48 #include <kern/thread_call.h>
49 #include <mach/kmod.h>
50 #include <mach/mach_interface.h>
52 extern void OSRuntimeUnloadCPP(kmod_info_t
*ki
, void *);
55 extern int debug_container_malloc_size
;
56 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
59 #endif /* OSALLOCDEBUG */
64 kCompletedBootstrap
= 0,
66 kMakingDictionaries
= 2
67 } sBootstrapState
= kNoDictionaries
;
69 static const int kClassCapacityIncrement
= 40;
70 static const int kKModCapacityIncrement
= 10;
71 static OSDictionary
*sAllClassesDict
, *sKModClassesDict
;
73 static mutex_t
*loadLock
;
74 static struct StalledData
{
77 unsigned int capacity
;
79 OSMetaClass
**classes
;
82 static unsigned int sConsiderUnloadDelay
= 60; /* secs */
84 static const char OSMetaClassBasePanicMsg
[] =
85 "OSMetaClassBase::_RESERVEDOSMetaClassBase%d called\n";
87 void OSMetaClassBase::_RESERVEDOSMetaClassBase0()
88 { panic(OSMetaClassBasePanicMsg
, 0); }
89 void OSMetaClassBase::_RESERVEDOSMetaClassBase1()
90 { panic(OSMetaClassBasePanicMsg
, 1); }
91 void OSMetaClassBase::_RESERVEDOSMetaClassBase2()
92 { panic(OSMetaClassBasePanicMsg
, 2); }
93 void OSMetaClassBase::_RESERVEDOSMetaClassBase3()
94 { panic(OSMetaClassBasePanicMsg
, 3); }
95 void OSMetaClassBase::_RESERVEDOSMetaClassBase4()
96 { panic(OSMetaClassBasePanicMsg
, 4); }
97 void OSMetaClassBase::_RESERVEDOSMetaClassBase5()
98 { panic(OSMetaClassBasePanicMsg
, 5); }
99 void OSMetaClassBase::_RESERVEDOSMetaClassBase6()
100 { panic(OSMetaClassBasePanicMsg
, 6); }
101 void OSMetaClassBase::_RESERVEDOSMetaClassBase7()
102 { panic(OSMetaClassBasePanicMsg
, 7); }
104 OSMetaClassBase::OSMetaClassBase()
108 OSMetaClassBase::~OSMetaClassBase()
112 thisVTable
= (void **) this;
113 *thisVTable
= (void *) -1UL;
116 bool OSMetaClassBase::isEqualTo(const OSMetaClassBase
*anObj
) const
118 return this == anObj
;
121 OSMetaClassBase
*OSMetaClassBase::metaCast(const OSMetaClass
*toMeta
) const
123 return toMeta
->checkMetaCast(this);
126 OSMetaClassBase
*OSMetaClassBase::metaCast(const OSSymbol
*toMetaSymb
) const
128 return OSMetaClass::checkMetaCastWithName(toMetaSymb
, this);
131 OSMetaClassBase
*OSMetaClassBase::metaCast(const OSString
*toMetaStr
) const
133 const OSSymbol
*tempSymb
= OSSymbol::withString(toMetaStr
);
134 OSMetaClassBase
*ret
= 0;
136 ret
= metaCast(tempSymb
);
142 OSMetaClassBase
*OSMetaClassBase::metaCast(const char *toMetaCStr
) const
144 const OSSymbol
*tempSymb
= OSSymbol::withCStringNoCopy(toMetaCStr
);
145 OSMetaClassBase
*ret
= 0;
147 ret
= metaCast(tempSymb
);
153 class OSMetaClassMeta
: public OSMetaClass
157 OSObject
*alloc() const;
159 OSMetaClassMeta::OSMetaClassMeta()
160 : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass
))
162 OSObject
*OSMetaClassMeta::alloc() const { return 0; }
164 static OSMetaClassMeta sOSMetaClassMeta
;
166 const OSMetaClass
* const OSMetaClass::metaClass
= &sOSMetaClassMeta
;
167 const OSMetaClass
* OSMetaClass::getMetaClass() const
168 { return &sOSMetaClassMeta
; }
170 static const char OSMetaClassPanicMsg
[] =
171 "OSMetaClass::_RESERVEDOSMetaClass%d called\n";
173 void OSMetaClass::_RESERVEDOSMetaClass0()
174 { panic(OSMetaClassPanicMsg
, 0); }
175 void OSMetaClass::_RESERVEDOSMetaClass1()
176 { panic(OSMetaClassPanicMsg
, 1); }
177 void OSMetaClass::_RESERVEDOSMetaClass2()
178 { panic(OSMetaClassPanicMsg
, 2); }
179 void OSMetaClass::_RESERVEDOSMetaClass3()
180 { panic(OSMetaClassPanicMsg
, 3); }
181 void OSMetaClass::_RESERVEDOSMetaClass4()
182 { panic(OSMetaClassPanicMsg
, 4); }
183 void OSMetaClass::_RESERVEDOSMetaClass5()
184 { panic(OSMetaClassPanicMsg
, 5); }
185 void OSMetaClass::_RESERVEDOSMetaClass6()
186 { panic(OSMetaClassPanicMsg
, 6); }
187 void OSMetaClass::_RESERVEDOSMetaClass7()
188 { panic(OSMetaClassPanicMsg
, 7); }
190 void OSMetaClass::logError(OSReturn result
)
195 case kOSMetaClassNoInit
:
196 msg
="OSMetaClass::preModLoad wasn't called, runtime internal error";
198 case kOSMetaClassNoDicts
:
199 msg
="Allocation failure for Metaclass internal dictionaries"; break;
200 case kOSMetaClassNoKModSet
:
201 msg
="Allocation failure for internal kmodule set"; break;
202 case kOSMetaClassNoInsKModSet
:
203 msg
="Can't insert the KMod set into the module dictionary"; break;
204 case kOSMetaClassDuplicateClass
:
205 msg
="Duplicate class"; break;
206 case kOSMetaClassNoSuper
:
207 msg
="Can't associate a class with its super class"; break;
208 case kOSMetaClassInstNoSuper
:
209 msg
="Instance construction, unknown super class."; break;
211 case kOSMetaClassInternal
:
212 msg
="runtime internal error"; break;
213 case kOSReturnSuccess
:
219 OSMetaClass::OSMetaClass(const char *inClassName
,
220 const OSMetaClass
*inSuperClass
,
221 unsigned int inClassSize
)
224 classSize
= inClassSize
;
225 superClassLink
= inSuperClass
;
227 className
= (const OSSymbol
*) inClassName
;
230 printf("OSMetaClass::preModLoad wasn't called for %s, "
231 "runtime internal error\n", inClassName
);
232 } else if (!sStalled
->result
) {
233 // Grow stalled array if neccessary
234 if (sStalled
->count
>= sStalled
->capacity
) {
235 OSMetaClass
**oldStalled
= sStalled
->classes
;
236 int oldSize
= sStalled
->capacity
* sizeof(OSMetaClass
*);
237 int newSize
= oldSize
238 + kKModCapacityIncrement
* sizeof(OSMetaClass
*);
240 sStalled
->classes
= (OSMetaClass
**) kalloc(newSize
);
241 if (!sStalled
->classes
) {
242 sStalled
->classes
= oldStalled
;
243 sStalled
->result
= kOSMetaClassNoTempData
;
247 sStalled
->capacity
+= kKModCapacityIncrement
;
248 memmove(sStalled
->classes
, oldStalled
, oldSize
);
249 kfree((vm_offset_t
)oldStalled
, oldSize
);
250 ACCUMSIZE(newSize
- oldSize
);
253 sStalled
->classes
[sStalled
->count
++] = this;
257 OSMetaClass::~OSMetaClass()
260 OSCollectionIterator
*iter
;
263 sAllClassesDict
->removeObject(className
);
265 iter
= OSCollectionIterator::withCollection(sKModClassesDict
);
270 while ( (iterKey
= (OSSymbol
*) iter
->getNextObject()) ) {
272 kmodClassSet
= (OSSet
*) sKModClassesDict
->getObject(iterKey
);
273 if (kmodClassSet
&& kmodClassSet
->containsObject(this)) {
274 kmodClassSet
->removeObject(this);
284 // First pass find class in stalled list
285 for (i
= 0; i
< sStalled
->count
; i
++)
286 if (this == sStalled
->classes
[i
])
289 if (i
< sStalled
->count
) {
291 if (i
< sStalled
->count
)
292 memmove(&sStalled
->classes
[i
], &sStalled
->classes
[i
+1],
293 (sStalled
->count
- i
) * sizeof(OSMetaClass
*));
299 // Don't do anything as these classes must be statically allocated
300 void *OSMetaClass::operator new(size_t size
) { return 0; }
301 void OSMetaClass::operator delete(void *mem
, size_t size
) { }
302 void OSMetaClass::retain() const { }
303 void OSMetaClass::release() const { }
304 void OSMetaClass::release(int when
) const { };
305 int OSMetaClass::getRetainCount() const { return 0; }
307 const char *OSMetaClass::getClassName() const
309 return className
->getCStringNoCopy();
312 unsigned int OSMetaClass::getClassSize() const
317 void *OSMetaClass::preModLoad(const char *kmodName
)
320 loadLock
= mutex_alloc(ETAP_IO_AHA
);
321 _mutex_lock(loadLock
);
324 _mutex_lock(loadLock
);
326 sStalled
= (StalledData
*) kalloc(sizeof(*sStalled
));
328 sStalled
->classes
= (OSMetaClass
**)
329 kalloc(kKModCapacityIncrement
* sizeof(OSMetaClass
*));
330 if (!sStalled
->classes
) {
331 kfree((vm_offset_t
) sStalled
, sizeof(*sStalled
));
334 ACCUMSIZE((kKModCapacityIncrement
* sizeof(OSMetaClass
*)) + sizeof(*sStalled
));
336 sStalled
->result
= kOSReturnSuccess
;
337 sStalled
->capacity
= kKModCapacityIncrement
;
339 sStalled
->kmodName
= kmodName
;
340 bzero(sStalled
->classes
, kKModCapacityIncrement
* sizeof(OSMetaClass
*));
346 bool OSMetaClass::checkModLoad(void *loadHandle
)
348 return sStalled
&& loadHandle
== sStalled
349 && sStalled
->result
== kOSReturnSuccess
;
352 OSReturn
OSMetaClass::postModLoad(void *loadHandle
)
354 OSReturn result
= kOSReturnSuccess
;
357 if (!sStalled
|| loadHandle
!= sStalled
) {
358 logError(kOSMetaClassInternal
);
359 return kOSMetaClassInternal
;
362 if (sStalled
->result
)
363 result
= sStalled
->result
;
364 else switch (sBootstrapState
) {
365 case kNoDictionaries
:
366 sBootstrapState
= kMakingDictionaries
;
367 // No break; fall through
369 case kMakingDictionaries
:
370 sKModClassesDict
= OSDictionary::withCapacity(kKModCapacityIncrement
);
371 sAllClassesDict
= OSDictionary::withCapacity(kClassCapacityIncrement
);
372 if (!sAllClassesDict
|| !sKModClassesDict
) {
373 result
= kOSMetaClassNoDicts
;
376 // No break; fall through
378 case kCompletedBootstrap
:
382 if (!sStalled
->count
)
383 break; // Nothing to do so just get out
385 // First pass checking classes aren't already loaded
386 for (i
= 0; i
< sStalled
->count
; i
++) {
387 OSMetaClass
*me
= sStalled
->classes
[i
];
389 if (0 != sAllClassesDict
->getObject((const char *) me
->className
)) {
390 printf("Class \"%s\" is duplicate\n", (const char *) me
->className
);
391 result
= kOSMetaClassDuplicateClass
;
395 if (i
!= sStalled
->count
)
398 kmodSet
= OSSet::withCapacity(sStalled
->count
);
400 result
= kOSMetaClassNoKModSet
;
404 if (!sKModClassesDict
->setObject(sStalled
->kmodName
, kmodSet
)) {
405 result
= kOSMetaClassNoInsKModSet
;
409 // Second pass symbolling strings and inserting classes in dictionary
410 for (unsigned int i
= 0; i
< sStalled
->count
; i
++) {
411 OSMetaClass
*me
= sStalled
->classes
[i
];
413 OSSymbol::withCStringNoCopy((const char *) me
->className
);
415 sAllClassesDict
->setObject(me
->className
, me
);
416 kmodSet
->setObject(me
);
418 sBootstrapState
= kCompletedBootstrap
;
423 result
= kOSMetaClassInternal
;
431 ACCUMSIZE(-(sStalled
->capacity
* sizeof(OSMetaClass
*)
432 + sizeof(*sStalled
)));
433 kfree((vm_offset_t
) sStalled
->classes
,
434 sStalled
->capacity
* sizeof(OSMetaClass
*));
435 kfree((vm_offset_t
) sStalled
, sizeof(*sStalled
));
440 mutex_unlock(loadLock
);
445 void OSMetaClass::instanceConstructed() const
447 // if ((0 == OSIncrementAtomic((SInt32 *)&(((OSMetaClass *) this)->instanceCount))) && superClassLink)
448 if ((0 == OSIncrementAtomic((SInt32
*) &instanceCount
)) && superClassLink
)
449 superClassLink
->instanceConstructed();
452 void OSMetaClass::instanceDestructed() const
454 if ((1 == OSDecrementAtomic((SInt32
*) &instanceCount
)) && superClassLink
)
455 superClassLink
->instanceDestructed();
457 if( ((int) instanceCount
) < 0)
458 printf("%s: bad retain(%d)", getClassName(), instanceCount
);
461 bool OSMetaClass::modHasInstance(const char *kmodName
)
466 loadLock
= mutex_alloc(ETAP_IO_AHA
);
467 _mutex_lock(loadLock
);
470 _mutex_lock(loadLock
);
474 OSCollectionIterator
*iter
;
475 OSMetaClass
*checkClass
;
477 kmodClasses
= OSDynamicCast(OSSet
,
478 sKModClassesDict
->getObject(kmodName
));
482 iter
= OSCollectionIterator::withCollection(kmodClasses
);
486 while ( (checkClass
= (OSMetaClass
*) iter
->getNextObject()) )
487 if (checkClass
->getInstanceCount()) {
495 mutex_unlock(loadLock
);
500 void OSMetaClass::reportModInstances(const char *kmodName
)
503 OSCollectionIterator
*iter
;
504 OSMetaClass
*checkClass
;
506 kmodClasses
= OSDynamicCast(OSSet
,
507 sKModClassesDict
->getObject(kmodName
));
511 iter
= OSCollectionIterator::withCollection(kmodClasses
);
515 while ( (checkClass
= (OSMetaClass
*) iter
->getNextObject()) )
516 if (checkClass
->getInstanceCount()) {
517 printf("%s: %s has %d instance(s)\n",
519 checkClass
->getClassName(),
520 checkClass
->getInstanceCount());
526 static void _OSMetaClassConsiderUnloads(thread_call_param_t p0
,
527 thread_call_param_t p1
)
531 OSCollectionIterator
*kmods
;
532 OSCollectionIterator
*classes
;
533 OSMetaClass
*checkClass
;
538 _mutex_lock(loadLock
);
542 kmods
= OSCollectionIterator::withCollection(sKModClassesDict
);
547 while ( (kmodName
= (OSSymbol
*) kmods
->getNextObject()) ) {
549 ki
= kmod_lookupbyname((char *)kmodName
->getCStringNoCopy());
553 if (ki
->reference_count
)
556 kmodClasses
= OSDynamicCast(OSSet
,
557 sKModClassesDict
->getObject(kmodName
));
558 classes
= OSCollectionIterator::withCollection(kmodClasses
);
562 while ((checkClass
= (OSMetaClass
*) classes
->getNextObject())
563 && (0 == checkClass
->getInstanceCount()))
567 if (0 == checkClass
) {
568 OSRuntimeUnloadCPP(ki
, 0); // call destructors
569 ret
= kmod_destroy(host_priv_self(), ki
->id
);
579 mutex_unlock(loadLock
);
582 void OSMetaClass::considerUnloads()
584 static thread_call_t unloadCallout
;
587 _mutex_lock(loadLock
);
590 unloadCallout
= thread_call_allocate(&_OSMetaClassConsiderUnloads
, 0);
592 thread_call_cancel(unloadCallout
);
593 clock_interval_to_deadline(sConsiderUnloadDelay
, 1000 * 1000 * 1000, &when
);
594 thread_call_enter_delayed(unloadCallout
, when
);
596 mutex_unlock(loadLock
);
599 const OSMetaClass
*OSMetaClass::getMetaClassWithName(const OSSymbol
*name
)
601 OSMetaClass
*retMeta
= 0;
607 retMeta
= (OSMetaClass
*) sAllClassesDict
->getObject(name
);
609 if (!retMeta
&& sStalled
)
611 // Oh dear we have to scan the stalled list and walk the
612 // the stalled list manually.
613 const char *cName
= name
->getCStringNoCopy();
616 // find class in stalled list
617 for (i
= 0; i
< sStalled
->count
; i
++) {
618 retMeta
= sStalled
->classes
[i
];
619 if (0 == strcmp(cName
, (const char *) retMeta
->className
))
623 if (i
< sStalled
->count
)
630 OSObject
*OSMetaClass::allocClassWithName(const OSSymbol
*name
)
633 _mutex_lock(loadLock
);
635 const OSMetaClass
* const meta
= getMetaClassWithName(name
);
638 result
= meta
->alloc();
642 mutex_unlock(loadLock
);
647 OSObject
*OSMetaClass::allocClassWithName(const OSString
*name
)
649 const OSSymbol
*tmpKey
= OSSymbol::withString(name
);
650 OSObject
*result
= allocClassWithName(tmpKey
);
655 OSObject
*OSMetaClass::allocClassWithName(const char *name
)
657 const OSSymbol
*tmpKey
= OSSymbol::withCStringNoCopy(name
);
658 OSObject
*result
= allocClassWithName(tmpKey
);
664 OSMetaClassBase
*OSMetaClass::
665 checkMetaCastWithName(const OSSymbol
*name
, const OSMetaClassBase
*in
)
667 OSMetaClassBase
* result
;
668 _mutex_lock(loadLock
);
669 const OSMetaClass
* const meta
= getMetaClassWithName(name
);
672 result
= meta
->checkMetaCast(in
);
676 mutex_unlock(loadLock
);
680 OSMetaClassBase
*OSMetaClass::
681 checkMetaCastWithName(const OSString
*name
, const OSMetaClassBase
*in
)
683 const OSSymbol
*tmpKey
= OSSymbol::withString(name
);
684 OSMetaClassBase
*result
= checkMetaCastWithName(tmpKey
, in
);
689 OSMetaClassBase
*OSMetaClass::
690 checkMetaCastWithName(const char *name
, const OSMetaClassBase
*in
)
692 const OSSymbol
*tmpKey
= OSSymbol::withCStringNoCopy(name
);
693 OSMetaClassBase
*result
= checkMetaCastWithName(tmpKey
, in
);
699 OSMetaClass::checkMetaCast
700 checkMetaCast(const OSMetaClassBase *check)
702 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.
704 Generally this method is not invoked directly but is used to implement the OSMetaClassBase::metaCast member function.
706 See also OSMetaClassBase::metaCast
709 OSMetaClassBase
*OSMetaClass::checkMetaCast(const OSMetaClassBase
*check
) const
711 const OSMetaClass
* const toMeta
= this;
712 const OSMetaClass
*fromMeta
;
714 for (fromMeta
= check
->getMetaClass(); ; fromMeta
= fromMeta
->superClassLink
) {
715 if (toMeta
== fromMeta
)
716 return (OSMetaClassBase
*) check
; // Discard const
718 if (!fromMeta
->superClassLink
)
725 void OSMetaClass::reservedCalled(int ind
) const
727 const char *cname
= className
->getCStringNoCopy();
728 panic("%s::_RESERVED%s%d called\n", cname
, cname
, ind
);
731 const OSMetaClass
*OSMetaClass::getSuperClass() const
733 return superClassLink
;
736 unsigned int OSMetaClass::getInstanceCount() const
738 return instanceCount
;
741 void OSMetaClass::printInstanceCounts()
743 OSCollectionIterator
*classes
;
747 classes
= OSCollectionIterator::withCollection(sAllClassesDict
);
751 while( (className
= (OSSymbol
*)classes
->getNextObject())) {
752 meta
= (OSMetaClass
*) sAllClassesDict
->getObject(className
);
755 printf("%24s count: %03d x 0x%03x = 0x%06x\n",
756 className
->getCStringNoCopy(),
757 meta
->getInstanceCount(),
758 meta
->getClassSize(),
759 meta
->getInstanceCount() * meta
->getClassSize() );
765 OSDictionary
* OSMetaClass::getClassDictionary()
767 return sAllClassesDict
;
770 bool OSMetaClass::serialize(OSSerialize
*s
) const
776 if (s
->previouslySerialized(this)) return true;
778 dict
= 0;// IODictionary::withCapacity(2);
779 off
= OSNumber::withNumber(getInstanceCount(), 32);
782 dict
->setObject("InstanceCount", off
);
783 ok
= dict
->serialize(s
);
785 ok
= off
->serialize(s
);