]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
d7e50217 | 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
1c79356b | 7 | * |
d7e50217 A |
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 | |
13 | * file. | |
14 | * | |
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 | |
1c79356b A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
d7e50217 A |
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. | |
1c79356b A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */ | |
26 | ||
27 | #include <string.h> | |
28 | #include <sys/systm.h> | |
29 | ||
30 | #include <libkern/OSReturn.h> | |
31 | ||
32 | #include <libkern/c++/OSMetaClass.h> | |
33 | ||
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> | |
44 | ||
45 | __BEGIN_DECLS | |
46 | ||
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> | |
9bccf70c | 52 | #include <kern/host.h> |
1c79356b A |
53 | #include <mach/kmod.h> |
54 | #include <mach/mach_interface.h> | |
55 | ||
56 | extern void OSRuntimeUnloadCPP(kmod_info_t *ki, void *); | |
57 | ||
58 | #if OSALLOCDEBUG | |
59 | extern int debug_container_malloc_size; | |
60 | #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0) | |
61 | #else | |
62 | #define ACCUMSIZE(s) | |
63 | #endif /* OSALLOCDEBUG */ | |
64 | ||
65 | __END_DECLS | |
66 | ||
67 | static enum { | |
68 | kCompletedBootstrap = 0, | |
69 | kNoDictionaries = 1, | |
70 | kMakingDictionaries = 2 | |
71 | } sBootstrapState = kNoDictionaries; | |
72 | ||
73 | static const int kClassCapacityIncrement = 40; | |
74 | static const int kKModCapacityIncrement = 10; | |
75 | static OSDictionary *sAllClassesDict, *sKModClassesDict; | |
76 | ||
77 | static mutex_t *loadLock; | |
78 | static struct StalledData { | |
79 | const char *kmodName; | |
80 | OSReturn result; | |
81 | unsigned int capacity; | |
82 | unsigned int count; | |
83 | OSMetaClass **classes; | |
84 | } *sStalled; | |
85 | ||
86 | static unsigned int sConsiderUnloadDelay = 60; /* secs */ | |
87 | ||
88 | static const char OSMetaClassBasePanicMsg[] = | |
89 | "OSMetaClassBase::_RESERVEDOSMetaClassBase%d called\n"; | |
90 | ||
9bccf70c | 91 | #if SLOT_USED |
1c79356b A |
92 | void OSMetaClassBase::_RESERVEDOSMetaClassBase0() |
93 | { panic(OSMetaClassBasePanicMsg, 0); } | |
94 | void OSMetaClassBase::_RESERVEDOSMetaClassBase1() | |
95 | { panic(OSMetaClassBasePanicMsg, 1); } | |
96 | void OSMetaClassBase::_RESERVEDOSMetaClassBase2() | |
97 | { panic(OSMetaClassBasePanicMsg, 2); } | |
9bccf70c A |
98 | #endif /* SLOT_USED */ |
99 | ||
100 | // As these slots are used move them up inside the #if above | |
1c79356b A |
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); } | |
9bccf70c A |
109 | |
110 | /* | |
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 | |
113 | * repaired. | |
114 | */ | |
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; } | |
119 | ||
120 | bool OSMetaClassBase:: | |
121 | checkTypeInst(const OSMetaClassBase *inst, const OSMetaClassBase *typeinst) | |
122 | { | |
123 | const OSMetaClass *toType = OSTypeIDInst(typeinst); | |
124 | return typeinst && inst && (0 != inst->metaCast(toType)); | |
125 | } | |
126 | ||
127 | ||
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. | |
1c79356b A |
131 | void OSMetaClassBase::_RESERVEDOSMetaClassBase7() |
132 | { panic(OSMetaClassBasePanicMsg, 7); } | |
133 | ||
134 | OSMetaClassBase::OSMetaClassBase() | |
135 | { | |
136 | } | |
137 | ||
138 | OSMetaClassBase::~OSMetaClassBase() | |
139 | { | |
140 | void **thisVTable; | |
141 | ||
142 | thisVTable = (void **) this; | |
143 | *thisVTable = (void *) -1UL; | |
144 | } | |
145 | ||
146 | bool OSMetaClassBase::isEqualTo(const OSMetaClassBase *anObj) const | |
147 | { | |
148 | return this == anObj; | |
149 | } | |
150 | ||
151 | OSMetaClassBase *OSMetaClassBase::metaCast(const OSMetaClass *toMeta) const | |
152 | { | |
153 | return toMeta->checkMetaCast(this); | |
154 | } | |
155 | ||
156 | OSMetaClassBase *OSMetaClassBase::metaCast(const OSSymbol *toMetaSymb) const | |
157 | { | |
158 | return OSMetaClass::checkMetaCastWithName(toMetaSymb, this); | |
159 | } | |
160 | ||
161 | OSMetaClassBase *OSMetaClassBase::metaCast(const OSString *toMetaStr) const | |
162 | { | |
163 | const OSSymbol *tempSymb = OSSymbol::withString(toMetaStr); | |
164 | OSMetaClassBase *ret = 0; | |
165 | if (tempSymb) { | |
166 | ret = metaCast(tempSymb); | |
167 | tempSymb->release(); | |
168 | } | |
169 | return ret; | |
170 | } | |
171 | ||
172 | OSMetaClassBase *OSMetaClassBase::metaCast(const char *toMetaCStr) const | |
173 | { | |
9bccf70c | 174 | const OSSymbol *tempSymb = OSSymbol::withCString(toMetaCStr); |
1c79356b A |
175 | OSMetaClassBase *ret = 0; |
176 | if (tempSymb) { | |
177 | ret = metaCast(tempSymb); | |
178 | tempSymb->release(); | |
179 | } | |
180 | return ret; | |
181 | } | |
182 | ||
183 | class OSMetaClassMeta : public OSMetaClass | |
184 | { | |
185 | public: | |
186 | OSMetaClassMeta(); | |
187 | OSObject *alloc() const; | |
188 | }; | |
189 | OSMetaClassMeta::OSMetaClassMeta() | |
190 | : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass)) | |
191 | { } | |
192 | OSObject *OSMetaClassMeta::alloc() const { return 0; } | |
193 | ||
194 | static OSMetaClassMeta sOSMetaClassMeta; | |
195 | ||
196 | const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta; | |
197 | const OSMetaClass * OSMetaClass::getMetaClass() const | |
198 | { return &sOSMetaClassMeta; } | |
199 | ||
200 | static const char OSMetaClassPanicMsg[] = | |
201 | "OSMetaClass::_RESERVEDOSMetaClass%d called\n"; | |
202 | ||
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); } | |
219 | ||
220 | void OSMetaClass::logError(OSReturn result) | |
221 | { | |
222 | const char *msg; | |
223 | ||
224 | switch (result) { | |
225 | case kOSMetaClassNoInit: | |
226 | msg="OSMetaClass::preModLoad wasn't called, runtime internal error"; | |
227 | break; | |
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; | |
240 | default: | |
241 | case kOSMetaClassInternal: | |
242 | msg="runtime internal error"; break; | |
243 | case kOSReturnSuccess: | |
244 | return; | |
245 | } | |
246 | printf("%s\n", msg); | |
247 | } | |
248 | ||
249 | OSMetaClass::OSMetaClass(const char *inClassName, | |
250 | const OSMetaClass *inSuperClass, | |
251 | unsigned int inClassSize) | |
252 | { | |
253 | instanceCount = 0; | |
254 | classSize = inClassSize; | |
255 | superClassLink = inSuperClass; | |
256 | ||
257 | className = (const OSSymbol *) inClassName; | |
258 | ||
259 | if (!sStalled) { | |
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 *); | |
269 | ||
270 | sStalled->classes = (OSMetaClass **) kalloc(newSize); | |
271 | if (!sStalled->classes) { | |
272 | sStalled->classes = oldStalled; | |
273 | sStalled->result = kOSMetaClassNoTempData; | |
274 | return; | |
275 | } | |
276 | ||
277 | sStalled->capacity += kKModCapacityIncrement; | |
278 | memmove(sStalled->classes, oldStalled, oldSize); | |
279 | kfree((vm_offset_t)oldStalled, oldSize); | |
280 | ACCUMSIZE(newSize - oldSize); | |
281 | } | |
282 | ||
283 | sStalled->classes[sStalled->count++] = this; | |
284 | } | |
285 | } | |
286 | ||
287 | OSMetaClass::~OSMetaClass() | |
288 | { | |
289 | do { | |
290 | OSCollectionIterator *iter; | |
291 | ||
292 | if (sAllClassesDict) | |
293 | sAllClassesDict->removeObject(className); | |
294 | ||
295 | iter = OSCollectionIterator::withCollection(sKModClassesDict); | |
296 | if (!iter) | |
297 | break; | |
298 | ||
299 | OSSymbol *iterKey; | |
300 | while ( (iterKey = (OSSymbol *) iter->getNextObject()) ) { | |
301 | OSSet *kmodClassSet; | |
302 | kmodClassSet = (OSSet *) sKModClassesDict->getObject(iterKey); | |
303 | if (kmodClassSet && kmodClassSet->containsObject(this)) { | |
304 | kmodClassSet->removeObject(this); | |
305 | break; | |
306 | } | |
307 | } | |
308 | iter->release(); | |
309 | } while (false); | |
310 | ||
311 | if (sStalled) { | |
312 | unsigned int i; | |
313 | ||
314 | // First pass find class in stalled list | |
315 | for (i = 0; i < sStalled->count; i++) | |
316 | if (this == sStalled->classes[i]) | |
317 | break; | |
318 | ||
319 | if (i < sStalled->count) { | |
320 | sStalled->count--; | |
321 | if (i < sStalled->count) | |
322 | memmove(&sStalled->classes[i], &sStalled->classes[i+1], | |
323 | (sStalled->count - i) * sizeof(OSMetaClass *)); | |
324 | } | |
325 | return; | |
326 | } | |
327 | } | |
328 | ||
1c79356b | 329 | void *OSMetaClass::operator new(size_t size) { return 0; } |
1c79356b A |
330 | void OSMetaClass::retain() const { } |
331 | void OSMetaClass::release() const { } | |
9bccf70c A |
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 { } | |
1c79356b A |
336 | int OSMetaClass::getRetainCount() const { return 0; } |
337 | ||
338 | const char *OSMetaClass::getClassName() const | |
339 | { | |
340 | return className->getCStringNoCopy(); | |
341 | } | |
342 | ||
343 | unsigned int OSMetaClass::getClassSize() const | |
344 | { | |
345 | return classSize; | |
346 | } | |
347 | ||
348 | void *OSMetaClass::preModLoad(const char *kmodName) | |
349 | { | |
350 | if (!loadLock) { | |
351 | loadLock = mutex_alloc(ETAP_IO_AHA); | |
0b4e3aa0 | 352 | mutex_lock(loadLock); |
1c79356b A |
353 | } |
354 | else | |
0b4e3aa0 | 355 | mutex_lock(loadLock); |
1c79356b A |
356 | |
357 | sStalled = (StalledData *) kalloc(sizeof(*sStalled)); | |
358 | if (sStalled) { | |
359 | sStalled->classes = (OSMetaClass **) | |
360 | kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *)); | |
361 | if (!sStalled->classes) { | |
362 | kfree((vm_offset_t) sStalled, sizeof(*sStalled)); | |
363 | return 0; | |
364 | } | |
365 | ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + sizeof(*sStalled)); | |
366 | ||
367 | sStalled->result = kOSReturnSuccess; | |
368 | sStalled->capacity = kKModCapacityIncrement; | |
369 | sStalled->count = 0; | |
370 | sStalled->kmodName = kmodName; | |
371 | bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *)); | |
372 | } | |
373 | ||
374 | return sStalled; | |
375 | } | |
376 | ||
377 | bool OSMetaClass::checkModLoad(void *loadHandle) | |
378 | { | |
379 | return sStalled && loadHandle == sStalled | |
380 | && sStalled->result == kOSReturnSuccess; | |
381 | } | |
382 | ||
383 | OSReturn OSMetaClass::postModLoad(void *loadHandle) | |
384 | { | |
385 | OSReturn result = kOSReturnSuccess; | |
386 | OSSet *kmodSet = 0; | |
387 | ||
388 | if (!sStalled || loadHandle != sStalled) { | |
389 | logError(kOSMetaClassInternal); | |
390 | return kOSMetaClassInternal; | |
391 | } | |
392 | ||
393 | if (sStalled->result) | |
394 | result = sStalled->result; | |
395 | else switch (sBootstrapState) { | |
396 | case kNoDictionaries: | |
397 | sBootstrapState = kMakingDictionaries; | |
398 | // No break; fall through | |
399 | ||
400 | case kMakingDictionaries: | |
401 | sKModClassesDict = OSDictionary::withCapacity(kKModCapacityIncrement); | |
402 | sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement); | |
403 | if (!sAllClassesDict || !sKModClassesDict) { | |
404 | result = kOSMetaClassNoDicts; | |
405 | break; | |
406 | } | |
407 | // No break; fall through | |
408 | ||
409 | case kCompletedBootstrap: | |
410 | { | |
411 | unsigned int i; | |
412 | ||
413 | if (!sStalled->count) | |
414 | break; // Nothing to do so just get out | |
415 | ||
416 | // First pass checking classes aren't already loaded | |
417 | for (i = 0; i < sStalled->count; i++) { | |
418 | OSMetaClass *me = sStalled->classes[i]; | |
419 | ||
420 | if (0 != sAllClassesDict->getObject((const char *) me->className)) { | |
421 | printf("Class \"%s\" is duplicate\n", (const char *) me->className); | |
422 | result = kOSMetaClassDuplicateClass; | |
423 | break; | |
424 | } | |
425 | } | |
426 | if (i != sStalled->count) | |
427 | break; | |
428 | ||
429 | kmodSet = OSSet::withCapacity(sStalled->count); | |
430 | if (!kmodSet) { | |
431 | result = kOSMetaClassNoKModSet; | |
432 | break; | |
433 | } | |
434 | ||
435 | if (!sKModClassesDict->setObject(sStalled->kmodName, kmodSet)) { | |
436 | result = kOSMetaClassNoInsKModSet; | |
437 | break; | |
438 | } | |
439 | ||
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]; | |
443 | me->className = | |
444 | OSSymbol::withCStringNoCopy((const char *) me->className); | |
445 | ||
446 | sAllClassesDict->setObject(me->className, me); | |
447 | kmodSet->setObject(me); | |
448 | } | |
449 | sBootstrapState = kCompletedBootstrap; | |
450 | break; | |
451 | } | |
452 | ||
453 | default: | |
454 | result = kOSMetaClassInternal; | |
455 | break; | |
456 | } | |
457 | ||
458 | if (kmodSet) | |
459 | kmodSet->release(); | |
460 | ||
461 | if (sStalled) { | |
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)); | |
467 | sStalled = 0; | |
468 | } | |
469 | ||
470 | logError(result); | |
471 | mutex_unlock(loadLock); | |
472 | return result; | |
473 | } | |
474 | ||
475 | ||
476 | void OSMetaClass::instanceConstructed() const | |
477 | { | |
478 | // if ((0 == OSIncrementAtomic((SInt32 *)&(((OSMetaClass *) this)->instanceCount))) && superClassLink) | |
479 | if ((0 == OSIncrementAtomic((SInt32 *) &instanceCount)) && superClassLink) | |
480 | superClassLink->instanceConstructed(); | |
481 | } | |
482 | ||
483 | void OSMetaClass::instanceDestructed() const | |
484 | { | |
485 | if ((1 == OSDecrementAtomic((SInt32 *) &instanceCount)) && superClassLink) | |
486 | superClassLink->instanceDestructed(); | |
487 | ||
488 | if( ((int) instanceCount) < 0) | |
489 | printf("%s: bad retain(%d)", getClassName(), instanceCount); | |
490 | } | |
491 | ||
492 | bool OSMetaClass::modHasInstance(const char *kmodName) | |
493 | { | |
494 | bool result = false; | |
495 | ||
496 | if (!loadLock) { | |
497 | loadLock = mutex_alloc(ETAP_IO_AHA); | |
0b4e3aa0 | 498 | mutex_lock(loadLock); |
1c79356b A |
499 | } |
500 | else | |
0b4e3aa0 | 501 | mutex_lock(loadLock); |
1c79356b A |
502 | |
503 | do { | |
504 | OSSet *kmodClasses; | |
505 | OSCollectionIterator *iter; | |
506 | OSMetaClass *checkClass; | |
507 | ||
508 | kmodClasses = OSDynamicCast(OSSet, | |
509 | sKModClassesDict->getObject(kmodName)); | |
510 | if (!kmodClasses) | |
511 | break; | |
512 | ||
513 | iter = OSCollectionIterator::withCollection(kmodClasses); | |
514 | if (!iter) | |
515 | break; | |
516 | ||
517 | while ( (checkClass = (OSMetaClass *) iter->getNextObject()) ) | |
518 | if (checkClass->getInstanceCount()) { | |
519 | result = true; | |
520 | break; | |
521 | } | |
522 | ||
523 | iter->release(); | |
524 | } while (false); | |
525 | ||
526 | mutex_unlock(loadLock); | |
527 | ||
528 | return result; | |
529 | } | |
530 | ||
531 | void OSMetaClass::reportModInstances(const char *kmodName) | |
532 | { | |
533 | OSSet *kmodClasses; | |
534 | OSCollectionIterator *iter; | |
535 | OSMetaClass *checkClass; | |
536 | ||
537 | kmodClasses = OSDynamicCast(OSSet, | |
538 | sKModClassesDict->getObject(kmodName)); | |
539 | if (!kmodClasses) | |
540 | return; | |
541 | ||
542 | iter = OSCollectionIterator::withCollection(kmodClasses); | |
543 | if (!iter) | |
544 | return; | |
545 | ||
546 | while ( (checkClass = (OSMetaClass *) iter->getNextObject()) ) | |
547 | if (checkClass->getInstanceCount()) { | |
548 | printf("%s: %s has %d instance(s)\n", | |
549 | kmodName, | |
550 | checkClass->getClassName(), | |
551 | checkClass->getInstanceCount()); | |
552 | } | |
553 | ||
554 | iter->release(); | |
555 | } | |
556 | ||
557 | static void _OSMetaClassConsiderUnloads(thread_call_param_t p0, | |
558 | thread_call_param_t p1) | |
559 | { | |
560 | OSSet *kmodClasses; | |
561 | OSSymbol *kmodName; | |
562 | OSCollectionIterator *kmods; | |
563 | OSCollectionIterator *classes; | |
564 | OSMetaClass *checkClass; | |
9bccf70c | 565 | kmod_info_t *ki = 0; |
1c79356b A |
566 | kern_return_t ret; |
567 | bool didUnload; | |
568 | ||
0b4e3aa0 | 569 | mutex_lock(loadLock); |
1c79356b A |
570 | |
571 | do { | |
572 | ||
573 | kmods = OSCollectionIterator::withCollection(sKModClassesDict); | |
574 | if (!kmods) | |
575 | break; | |
576 | ||
577 | didUnload = false; | |
578 | while ( (kmodName = (OSSymbol *) kmods->getNextObject()) ) { | |
579 | ||
9bccf70c A |
580 | if (ki) { |
581 | kfree(ki, sizeof(kmod_info_t)); | |
582 | ki = 0; | |
583 | } | |
584 | ||
585 | ki = kmod_lookupbyname_locked((char *)kmodName->getCStringNoCopy()); | |
1c79356b A |
586 | if (!ki) |
587 | continue; | |
588 | ||
9bccf70c A |
589 | if (ki->reference_count) { |
590 | continue; | |
591 | } | |
1c79356b A |
592 | |
593 | kmodClasses = OSDynamicCast(OSSet, | |
594 | sKModClassesDict->getObject(kmodName)); | |
595 | classes = OSCollectionIterator::withCollection(kmodClasses); | |
596 | if (!classes) | |
597 | continue; | |
598 | ||
599 | while ((checkClass = (OSMetaClass *) classes->getNextObject()) | |
600 | && (0 == checkClass->getInstanceCount())) | |
601 | {} | |
602 | classes->release(); | |
603 | ||
604 | if (0 == checkClass) { | |
605 | OSRuntimeUnloadCPP(ki, 0); // call destructors | |
606 | ret = kmod_destroy(host_priv_self(), ki->id); | |
607 | didUnload = true; | |
608 | } | |
609 | ||
9bccf70c | 610 | } |
1c79356b A |
611 | |
612 | kmods->release(); | |
613 | ||
614 | } while (didUnload); | |
615 | ||
616 | mutex_unlock(loadLock); | |
617 | } | |
618 | ||
619 | void OSMetaClass::considerUnloads() | |
620 | { | |
621 | static thread_call_t unloadCallout; | |
622 | AbsoluteTime when; | |
623 | ||
0b4e3aa0 | 624 | mutex_lock(loadLock); |
1c79356b A |
625 | |
626 | if (!unloadCallout) | |
627 | unloadCallout = thread_call_allocate(&_OSMetaClassConsiderUnloads, 0); | |
628 | ||
629 | thread_call_cancel(unloadCallout); | |
630 | clock_interval_to_deadline(sConsiderUnloadDelay, 1000 * 1000 * 1000, &when); | |
631 | thread_call_enter_delayed(unloadCallout, when); | |
632 | ||
633 | mutex_unlock(loadLock); | |
634 | } | |
635 | ||
636 | const OSMetaClass *OSMetaClass::getMetaClassWithName(const OSSymbol *name) | |
637 | { | |
638 | OSMetaClass *retMeta = 0; | |
639 | ||
640 | if (!name) | |
641 | return 0; | |
642 | ||
643 | if (sAllClassesDict) | |
644 | retMeta = (OSMetaClass *) sAllClassesDict->getObject(name); | |
645 | ||
646 | if (!retMeta && sStalled) | |
647 | { | |
648 | // Oh dear we have to scan the stalled list and walk the | |
649 | // the stalled list manually. | |
650 | const char *cName = name->getCStringNoCopy(); | |
651 | unsigned int i; | |
652 | ||
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)) | |
657 | break; | |
658 | } | |
659 | ||
660 | if (i < sStalled->count) | |
661 | retMeta = 0; | |
662 | } | |
663 | ||
664 | return retMeta; | |
665 | } | |
666 | ||
667 | OSObject *OSMetaClass::allocClassWithName(const OSSymbol *name) | |
668 | { | |
669 | OSObject * result; | |
0b4e3aa0 | 670 | mutex_lock(loadLock); |
1c79356b A |
671 | |
672 | const OSMetaClass * const meta = getMetaClassWithName(name); | |
673 | ||
674 | if (meta) | |
675 | result = meta->alloc(); | |
676 | else | |
677 | result = 0; | |
678 | ||
679 | mutex_unlock(loadLock); | |
680 | ||
681 | return result; | |
682 | } | |
683 | ||
684 | OSObject *OSMetaClass::allocClassWithName(const OSString *name) | |
685 | { | |
686 | const OSSymbol *tmpKey = OSSymbol::withString(name); | |
687 | OSObject *result = allocClassWithName(tmpKey); | |
688 | tmpKey->release(); | |
689 | return result; | |
690 | } | |
691 | ||
692 | OSObject *OSMetaClass::allocClassWithName(const char *name) | |
693 | { | |
694 | const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name); | |
695 | OSObject *result = allocClassWithName(tmpKey); | |
696 | tmpKey->release(); | |
697 | return result; | |
698 | } | |
699 | ||
700 | ||
701 | OSMetaClassBase *OSMetaClass:: | |
702 | checkMetaCastWithName(const OSSymbol *name, const OSMetaClassBase *in) | |
703 | { | |
704 | OSMetaClassBase * result; | |
0b4e3aa0 | 705 | mutex_lock(loadLock); |
1c79356b A |
706 | const OSMetaClass * const meta = getMetaClassWithName(name); |
707 | ||
708 | if (meta) | |
709 | result = meta->checkMetaCast(in); | |
710 | else | |
711 | result = 0; | |
712 | ||
713 | mutex_unlock(loadLock); | |
714 | return result; | |
715 | } | |
716 | ||
717 | OSMetaClassBase *OSMetaClass:: | |
718 | checkMetaCastWithName(const OSString *name, const OSMetaClassBase *in) | |
719 | { | |
720 | const OSSymbol *tmpKey = OSSymbol::withString(name); | |
721 | OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in); | |
722 | tmpKey->release(); | |
723 | return result; | |
724 | } | |
725 | ||
726 | OSMetaClassBase *OSMetaClass:: | |
727 | checkMetaCastWithName(const char *name, const OSMetaClassBase *in) | |
728 | { | |
729 | const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name); | |
730 | OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in); | |
731 | tmpKey->release(); | |
732 | return result; | |
733 | } | |
734 | ||
735 | /* | |
736 | OSMetaClass::checkMetaCast | |
737 | checkMetaCast(const OSMetaClassBase *check) | |
738 | ||
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. | |
740 | ||
741 | Generally this method is not invoked directly but is used to implement the OSMetaClassBase::metaCast member function. | |
742 | ||
743 | See also OSMetaClassBase::metaCast | |
744 | ||
745 | */ | |
746 | OSMetaClassBase *OSMetaClass::checkMetaCast(const OSMetaClassBase *check) const | |
747 | { | |
748 | const OSMetaClass * const toMeta = this; | |
749 | const OSMetaClass *fromMeta; | |
750 | ||
751 | for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) { | |
752 | if (toMeta == fromMeta) | |
753 | return (OSMetaClassBase *) check; // Discard const | |
754 | ||
755 | if (!fromMeta->superClassLink) | |
756 | break; | |
757 | } | |
758 | ||
759 | return 0; | |
760 | } | |
761 | ||
762 | void OSMetaClass::reservedCalled(int ind) const | |
763 | { | |
764 | const char *cname = className->getCStringNoCopy(); | |
765 | panic("%s::_RESERVED%s%d called\n", cname, cname, ind); | |
766 | } | |
767 | ||
768 | const OSMetaClass *OSMetaClass::getSuperClass() const | |
769 | { | |
770 | return superClassLink; | |
771 | } | |
772 | ||
773 | unsigned int OSMetaClass::getInstanceCount() const | |
774 | { | |
775 | return instanceCount; | |
776 | } | |
777 | ||
778 | void OSMetaClass::printInstanceCounts() | |
779 | { | |
780 | OSCollectionIterator *classes; | |
781 | OSSymbol *className; | |
782 | OSMetaClass *meta; | |
783 | ||
784 | classes = OSCollectionIterator::withCollection(sAllClassesDict); | |
785 | if (!classes) | |
786 | return; | |
787 | ||
788 | while( (className = (OSSymbol *)classes->getNextObject())) { | |
789 | meta = (OSMetaClass *) sAllClassesDict->getObject(className); | |
790 | assert(meta); | |
791 | ||
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() ); | |
797 | } | |
798 | printf("\n"); | |
799 | classes->release(); | |
800 | } | |
801 | ||
802 | OSDictionary * OSMetaClass::getClassDictionary() | |
803 | { | |
804 | return sAllClassesDict; | |
805 | } | |
806 | ||
807 | bool OSMetaClass::serialize(OSSerialize *s) const | |
808 | { | |
809 | OSDictionary * dict; | |
810 | OSNumber * off; | |
811 | bool ok = false; | |
812 | ||
813 | if (s->previouslySerialized(this)) return true; | |
814 | ||
815 | dict = 0;// IODictionary::withCapacity(2); | |
816 | off = OSNumber::withNumber(getInstanceCount(), 32); | |
817 | ||
818 | if (dict) { | |
819 | dict->setObject("InstanceCount", off ); | |
820 | ok = dict->serialize(s); | |
821 | } else if( off) | |
822 | ok = off->serialize(s); | |
823 | ||
824 | if (dict) | |
825 | dict->release(); | |
826 | if (off) | |
827 | off->release(); | |
828 | ||
829 | return ok; | |
830 | } | |
831 |