]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
37839358 A |
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. | |
1c79356b | 11 | * |
37839358 A |
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 | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
37839358 A |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
1c79356b A |
19 | * |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* OSMetaClass.cpp created by gvdl on Fri 1998-11-17 */ | |
23 | ||
24 | #include <string.h> | |
1c79356b A |
25 | |
26 | #include <libkern/OSReturn.h> | |
27 | ||
28 | #include <libkern/c++/OSMetaClass.h> | |
29 | ||
30 | #include <libkern/c++/OSObject.h> | |
31 | #include <libkern/c++/OSCollectionIterator.h> | |
32 | #include <libkern/c++/OSDictionary.h> | |
33 | #include <libkern/c++/OSArray.h> | |
34 | #include <libkern/c++/OSSet.h> | |
35 | #include <libkern/c++/OSSymbol.h> | |
36 | #include <libkern/c++/OSNumber.h> | |
37 | #include <libkern/c++/OSSerialize.h> | |
38 | #include <libkern/c++/OSLib.h> | |
39 | #include <libkern/OSAtomic.h> | |
40 | ||
41 | __BEGIN_DECLS | |
42 | ||
91447636 | 43 | #include <sys/systm.h> |
1c79356b | 44 | #include <mach/mach_types.h> |
1c79356b A |
45 | #include <kern/lock.h> |
46 | #include <kern/clock.h> | |
47 | #include <kern/thread_call.h> | |
9bccf70c | 48 | #include <kern/host.h> |
1c79356b A |
49 | #include <mach/kmod.h> |
50 | #include <mach/mach_interface.h> | |
51 | ||
52 | extern void OSRuntimeUnloadCPP(kmod_info_t *ki, void *); | |
53 | ||
54 | #if OSALLOCDEBUG | |
55 | extern int debug_container_malloc_size; | |
56 | #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0) | |
57 | #else | |
58 | #define ACCUMSIZE(s) | |
59 | #endif /* OSALLOCDEBUG */ | |
60 | ||
61 | __END_DECLS | |
62 | ||
63 | static enum { | |
64 | kCompletedBootstrap = 0, | |
65 | kNoDictionaries = 1, | |
66 | kMakingDictionaries = 2 | |
67 | } sBootstrapState = kNoDictionaries; | |
68 | ||
69 | static const int kClassCapacityIncrement = 40; | |
70 | static const int kKModCapacityIncrement = 10; | |
91447636 | 71 | static OSDictionary *sAllClassesDict, *sKModClassesDict, *sSortedByClassesDict; |
1c79356b A |
72 | |
73 | static mutex_t *loadLock; | |
74 | static struct StalledData { | |
75 | const char *kmodName; | |
76 | OSReturn result; | |
77 | unsigned int capacity; | |
78 | unsigned int count; | |
79 | OSMetaClass **classes; | |
80 | } *sStalled; | |
81 | ||
82 | static unsigned int sConsiderUnloadDelay = 60; /* secs */ | |
83 | ||
84 | static const char OSMetaClassBasePanicMsg[] = | |
85 | "OSMetaClassBase::_RESERVEDOSMetaClassBase%d called\n"; | |
86 | ||
9bccf70c | 87 | #if SLOT_USED |
1c79356b A |
88 | void OSMetaClassBase::_RESERVEDOSMetaClassBase0() |
89 | { panic(OSMetaClassBasePanicMsg, 0); } | |
90 | void OSMetaClassBase::_RESERVEDOSMetaClassBase1() | |
91 | { panic(OSMetaClassBasePanicMsg, 1); } | |
92 | void OSMetaClassBase::_RESERVEDOSMetaClassBase2() | |
93 | { panic(OSMetaClassBasePanicMsg, 2); } | |
9bccf70c A |
94 | #endif /* SLOT_USED */ |
95 | ||
96 | // As these slots are used move them up inside the #if above | |
1c79356b A |
97 | void OSMetaClassBase::_RESERVEDOSMetaClassBase3() |
98 | { panic(OSMetaClassBasePanicMsg, 3); } | |
99 | void OSMetaClassBase::_RESERVEDOSMetaClassBase4() | |
100 | { panic(OSMetaClassBasePanicMsg, 4); } | |
101 | void OSMetaClassBase::_RESERVEDOSMetaClassBase5() | |
102 | { panic(OSMetaClassBasePanicMsg, 5); } | |
103 | void OSMetaClassBase::_RESERVEDOSMetaClassBase6() | |
104 | { panic(OSMetaClassBasePanicMsg, 6); } | |
9bccf70c A |
105 | |
106 | /* | |
107 | * These used to be inline in the header but gcc didn't believe us | |
108 | * Now we MUST pull the inline out at least until the compiler is | |
109 | * repaired. | |
110 | */ | |
111 | // Helper inlines for runtime type preprocessor macros | |
112 | OSMetaClassBase *OSMetaClassBase:: | |
113 | safeMetaCast(const OSMetaClassBase *me, const OSMetaClass *toType) | |
114 | { return (me)? me->metaCast(toType) : 0; } | |
115 | ||
116 | bool OSMetaClassBase:: | |
117 | checkTypeInst(const OSMetaClassBase *inst, const OSMetaClassBase *typeinst) | |
118 | { | |
119 | const OSMetaClass *toType = OSTypeIDInst(typeinst); | |
120 | return typeinst && inst && (0 != inst->metaCast(toType)); | |
121 | } | |
122 | ||
123 | ||
124 | // If you need this slot you had better setup an IOCTL style interface. | |
125 | // 'Cause the whole kernel world depends on OSMetaClassBase and YOU | |
126 | // CANT change the VTABLE size ever. | |
1c79356b A |
127 | void OSMetaClassBase::_RESERVEDOSMetaClassBase7() |
128 | { panic(OSMetaClassBasePanicMsg, 7); } | |
129 | ||
130 | OSMetaClassBase::OSMetaClassBase() | |
131 | { | |
132 | } | |
133 | ||
134 | OSMetaClassBase::~OSMetaClassBase() | |
135 | { | |
136 | void **thisVTable; | |
137 | ||
138 | thisVTable = (void **) this; | |
139 | *thisVTable = (void *) -1UL; | |
140 | } | |
141 | ||
142 | bool OSMetaClassBase::isEqualTo(const OSMetaClassBase *anObj) const | |
143 | { | |
144 | return this == anObj; | |
145 | } | |
146 | ||
147 | OSMetaClassBase *OSMetaClassBase::metaCast(const OSMetaClass *toMeta) const | |
148 | { | |
149 | return toMeta->checkMetaCast(this); | |
150 | } | |
151 | ||
152 | OSMetaClassBase *OSMetaClassBase::metaCast(const OSSymbol *toMetaSymb) const | |
153 | { | |
154 | return OSMetaClass::checkMetaCastWithName(toMetaSymb, this); | |
155 | } | |
156 | ||
157 | OSMetaClassBase *OSMetaClassBase::metaCast(const OSString *toMetaStr) const | |
158 | { | |
159 | const OSSymbol *tempSymb = OSSymbol::withString(toMetaStr); | |
160 | OSMetaClassBase *ret = 0; | |
161 | if (tempSymb) { | |
162 | ret = metaCast(tempSymb); | |
163 | tempSymb->release(); | |
164 | } | |
165 | return ret; | |
166 | } | |
167 | ||
168 | OSMetaClassBase *OSMetaClassBase::metaCast(const char *toMetaCStr) const | |
169 | { | |
9bccf70c | 170 | const OSSymbol *tempSymb = OSSymbol::withCString(toMetaCStr); |
1c79356b A |
171 | OSMetaClassBase *ret = 0; |
172 | if (tempSymb) { | |
173 | ret = metaCast(tempSymb); | |
174 | tempSymb->release(); | |
175 | } | |
176 | return ret; | |
177 | } | |
178 | ||
179 | class OSMetaClassMeta : public OSMetaClass | |
180 | { | |
181 | public: | |
182 | OSMetaClassMeta(); | |
183 | OSObject *alloc() const; | |
184 | }; | |
185 | OSMetaClassMeta::OSMetaClassMeta() | |
186 | : OSMetaClass("OSMetaClass", 0, sizeof(OSMetaClass)) | |
187 | { } | |
188 | OSObject *OSMetaClassMeta::alloc() const { return 0; } | |
189 | ||
190 | static OSMetaClassMeta sOSMetaClassMeta; | |
191 | ||
192 | const OSMetaClass * const OSMetaClass::metaClass = &sOSMetaClassMeta; | |
193 | const OSMetaClass * OSMetaClass::getMetaClass() const | |
194 | { return &sOSMetaClassMeta; } | |
195 | ||
196 | static const char OSMetaClassPanicMsg[] = | |
197 | "OSMetaClass::_RESERVEDOSMetaClass%d called\n"; | |
198 | ||
199 | void OSMetaClass::_RESERVEDOSMetaClass0() | |
200 | { panic(OSMetaClassPanicMsg, 0); } | |
201 | void OSMetaClass::_RESERVEDOSMetaClass1() | |
202 | { panic(OSMetaClassPanicMsg, 1); } | |
203 | void OSMetaClass::_RESERVEDOSMetaClass2() | |
204 | { panic(OSMetaClassPanicMsg, 2); } | |
205 | void OSMetaClass::_RESERVEDOSMetaClass3() | |
206 | { panic(OSMetaClassPanicMsg, 3); } | |
207 | void OSMetaClass::_RESERVEDOSMetaClass4() | |
208 | { panic(OSMetaClassPanicMsg, 4); } | |
209 | void OSMetaClass::_RESERVEDOSMetaClass5() | |
210 | { panic(OSMetaClassPanicMsg, 5); } | |
211 | void OSMetaClass::_RESERVEDOSMetaClass6() | |
212 | { panic(OSMetaClassPanicMsg, 6); } | |
213 | void OSMetaClass::_RESERVEDOSMetaClass7() | |
214 | { panic(OSMetaClassPanicMsg, 7); } | |
215 | ||
216 | void OSMetaClass::logError(OSReturn result) | |
217 | { | |
218 | const char *msg; | |
219 | ||
220 | switch (result) { | |
221 | case kOSMetaClassNoInit: | |
222 | msg="OSMetaClass::preModLoad wasn't called, runtime internal error"; | |
223 | break; | |
224 | case kOSMetaClassNoDicts: | |
225 | msg="Allocation failure for Metaclass internal dictionaries"; break; | |
226 | case kOSMetaClassNoKModSet: | |
227 | msg="Allocation failure for internal kmodule set"; break; | |
228 | case kOSMetaClassNoInsKModSet: | |
229 | msg="Can't insert the KMod set into the module dictionary"; break; | |
230 | case kOSMetaClassDuplicateClass: | |
231 | msg="Duplicate class"; break; | |
232 | case kOSMetaClassNoSuper: | |
233 | msg="Can't associate a class with its super class"; break; | |
234 | case kOSMetaClassInstNoSuper: | |
235 | msg="Instance construction, unknown super class."; break; | |
236 | default: | |
237 | case kOSMetaClassInternal: | |
238 | msg="runtime internal error"; break; | |
239 | case kOSReturnSuccess: | |
240 | return; | |
241 | } | |
242 | printf("%s\n", msg); | |
243 | } | |
244 | ||
245 | OSMetaClass::OSMetaClass(const char *inClassName, | |
246 | const OSMetaClass *inSuperClass, | |
247 | unsigned int inClassSize) | |
248 | { | |
249 | instanceCount = 0; | |
250 | classSize = inClassSize; | |
251 | superClassLink = inSuperClass; | |
252 | ||
253 | className = (const OSSymbol *) inClassName; | |
254 | ||
255 | if (!sStalled) { | |
256 | printf("OSMetaClass::preModLoad wasn't called for %s, " | |
257 | "runtime internal error\n", inClassName); | |
258 | } else if (!sStalled->result) { | |
259 | // Grow stalled array if neccessary | |
260 | if (sStalled->count >= sStalled->capacity) { | |
261 | OSMetaClass **oldStalled = sStalled->classes; | |
262 | int oldSize = sStalled->capacity * sizeof(OSMetaClass *); | |
263 | int newSize = oldSize | |
264 | + kKModCapacityIncrement * sizeof(OSMetaClass *); | |
265 | ||
266 | sStalled->classes = (OSMetaClass **) kalloc(newSize); | |
267 | if (!sStalled->classes) { | |
268 | sStalled->classes = oldStalled; | |
269 | sStalled->result = kOSMetaClassNoTempData; | |
270 | return; | |
271 | } | |
272 | ||
273 | sStalled->capacity += kKModCapacityIncrement; | |
274 | memmove(sStalled->classes, oldStalled, oldSize); | |
275 | kfree((vm_offset_t)oldStalled, oldSize); | |
276 | ACCUMSIZE(newSize - oldSize); | |
277 | } | |
278 | ||
279 | sStalled->classes[sStalled->count++] = this; | |
280 | } | |
281 | } | |
282 | ||
283 | OSMetaClass::~OSMetaClass() | |
284 | { | |
285 | do { | |
286 | OSCollectionIterator *iter; | |
287 | ||
91447636 | 288 | if (sAllClassesDict) { |
1c79356b | 289 | sAllClassesDict->removeObject(className); |
91447636 A |
290 | className->release(); |
291 | } | |
1c79356b A |
292 | |
293 | iter = OSCollectionIterator::withCollection(sKModClassesDict); | |
294 | if (!iter) | |
295 | break; | |
296 | ||
297 | OSSymbol *iterKey; | |
298 | while ( (iterKey = (OSSymbol *) iter->getNextObject()) ) { | |
299 | OSSet *kmodClassSet; | |
300 | kmodClassSet = (OSSet *) sKModClassesDict->getObject(iterKey); | |
301 | if (kmodClassSet && kmodClassSet->containsObject(this)) { | |
302 | kmodClassSet->removeObject(this); | |
303 | break; | |
304 | } | |
305 | } | |
306 | iter->release(); | |
307 | } while (false); | |
308 | ||
309 | if (sStalled) { | |
310 | unsigned int i; | |
311 | ||
312 | // First pass find class in stalled list | |
313 | for (i = 0; i < sStalled->count; i++) | |
314 | if (this == sStalled->classes[i]) | |
315 | break; | |
316 | ||
317 | if (i < sStalled->count) { | |
318 | sStalled->count--; | |
319 | if (i < sStalled->count) | |
320 | memmove(&sStalled->classes[i], &sStalled->classes[i+1], | |
321 | (sStalled->count - i) * sizeof(OSMetaClass *)); | |
322 | } | |
1c79356b A |
323 | } |
324 | } | |
325 | ||
1c79356b | 326 | void *OSMetaClass::operator new(size_t size) { return 0; } |
1c79356b A |
327 | void OSMetaClass::retain() const { } |
328 | void OSMetaClass::release() const { } | |
9bccf70c A |
329 | void OSMetaClass::release(int when) const { } |
330 | void OSMetaClass::taggedRetain(const void *tag) const { } | |
331 | void OSMetaClass::taggedRelease(const void *tag) const { } | |
332 | void OSMetaClass::taggedRelease(const void *tag, const int when) const { } | |
1c79356b A |
333 | int OSMetaClass::getRetainCount() const { return 0; } |
334 | ||
335 | const char *OSMetaClass::getClassName() const | |
336 | { | |
337 | return className->getCStringNoCopy(); | |
338 | } | |
339 | ||
340 | unsigned int OSMetaClass::getClassSize() const | |
341 | { | |
342 | return classSize; | |
343 | } | |
344 | ||
345 | void *OSMetaClass::preModLoad(const char *kmodName) | |
346 | { | |
347 | if (!loadLock) { | |
91447636 | 348 | loadLock = mutex_alloc(0); |
0b4e3aa0 | 349 | mutex_lock(loadLock); |
1c79356b A |
350 | } |
351 | else | |
0b4e3aa0 | 352 | mutex_lock(loadLock); |
1c79356b A |
353 | |
354 | sStalled = (StalledData *) kalloc(sizeof(*sStalled)); | |
355 | if (sStalled) { | |
356 | sStalled->classes = (OSMetaClass **) | |
357 | kalloc(kKModCapacityIncrement * sizeof(OSMetaClass *)); | |
358 | if (!sStalled->classes) { | |
359 | kfree((vm_offset_t) sStalled, sizeof(*sStalled)); | |
360 | return 0; | |
361 | } | |
362 | ACCUMSIZE((kKModCapacityIncrement * sizeof(OSMetaClass *)) + sizeof(*sStalled)); | |
363 | ||
364 | sStalled->result = kOSReturnSuccess; | |
365 | sStalled->capacity = kKModCapacityIncrement; | |
366 | sStalled->count = 0; | |
367 | sStalled->kmodName = kmodName; | |
368 | bzero(sStalled->classes, kKModCapacityIncrement * sizeof(OSMetaClass *)); | |
369 | } | |
370 | ||
371 | return sStalled; | |
372 | } | |
373 | ||
374 | bool OSMetaClass::checkModLoad(void *loadHandle) | |
375 | { | |
376 | return sStalled && loadHandle == sStalled | |
377 | && sStalled->result == kOSReturnSuccess; | |
378 | } | |
379 | ||
380 | OSReturn OSMetaClass::postModLoad(void *loadHandle) | |
381 | { | |
382 | OSReturn result = kOSReturnSuccess; | |
383 | OSSet *kmodSet = 0; | |
91447636 | 384 | OSSymbol *myname = 0; |
1c79356b A |
385 | |
386 | if (!sStalled || loadHandle != sStalled) { | |
387 | logError(kOSMetaClassInternal); | |
388 | return kOSMetaClassInternal; | |
389 | } | |
390 | ||
391 | if (sStalled->result) | |
392 | result = sStalled->result; | |
393 | else switch (sBootstrapState) { | |
394 | case kNoDictionaries: | |
395 | sBootstrapState = kMakingDictionaries; | |
396 | // No break; fall through | |
397 | ||
398 | case kMakingDictionaries: | |
399 | sKModClassesDict = OSDictionary::withCapacity(kKModCapacityIncrement); | |
400 | sAllClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement); | |
91447636 A |
401 | sSortedByClassesDict = OSDictionary::withCapacity(kClassCapacityIncrement); |
402 | if (!sAllClassesDict || !sKModClassesDict || !sSortedByClassesDict) { | |
1c79356b A |
403 | result = kOSMetaClassNoDicts; |
404 | break; | |
405 | } | |
406 | // No break; fall through | |
407 | ||
408 | case kCompletedBootstrap: | |
409 | { | |
410 | unsigned int i; | |
91447636 | 411 | myname = OSSymbol::withCStringNoCopy(sStalled->kmodName); |
1c79356b A |
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 | ||
91447636 | 435 | if (!sKModClassesDict->setObject(myname, kmodSet)) { |
1c79356b A |
436 | result = kOSMetaClassNoInsKModSet; |
437 | break; | |
438 | } | |
439 | ||
440 | // Second pass symbolling strings and inserting classes in dictionary | |
91447636 | 441 | for (i = 0; i < sStalled->count; i++) { |
1c79356b A |
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); | |
91447636 | 448 | sSortedByClassesDict->setObject((const OSSymbol *)me, myname); |
1c79356b A |
449 | } |
450 | sBootstrapState = kCompletedBootstrap; | |
451 | break; | |
452 | } | |
453 | ||
454 | default: | |
455 | result = kOSMetaClassInternal; | |
456 | break; | |
457 | } | |
458 | ||
459 | if (kmodSet) | |
460 | kmodSet->release(); | |
461 | ||
91447636 A |
462 | if (myname) |
463 | myname->release(); | |
464 | ||
1c79356b A |
465 | if (sStalled) { |
466 | ACCUMSIZE(-(sStalled->capacity * sizeof(OSMetaClass *) | |
467 | + sizeof(*sStalled))); | |
468 | kfree((vm_offset_t) sStalled->classes, | |
469 | sStalled->capacity * sizeof(OSMetaClass *)); | |
470 | kfree((vm_offset_t) sStalled, sizeof(*sStalled)); | |
471 | sStalled = 0; | |
472 | } | |
473 | ||
474 | logError(result); | |
475 | mutex_unlock(loadLock); | |
476 | return result; | |
477 | } | |
478 | ||
479 | ||
480 | void OSMetaClass::instanceConstructed() const | |
481 | { | |
482 | // if ((0 == OSIncrementAtomic((SInt32 *)&(((OSMetaClass *) this)->instanceCount))) && superClassLink) | |
483 | if ((0 == OSIncrementAtomic((SInt32 *) &instanceCount)) && superClassLink) | |
484 | superClassLink->instanceConstructed(); | |
485 | } | |
486 | ||
487 | void OSMetaClass::instanceDestructed() const | |
488 | { | |
489 | if ((1 == OSDecrementAtomic((SInt32 *) &instanceCount)) && superClassLink) | |
490 | superClassLink->instanceDestructed(); | |
491 | ||
492 | if( ((int) instanceCount) < 0) | |
493 | printf("%s: bad retain(%d)", getClassName(), instanceCount); | |
494 | } | |
495 | ||
496 | bool OSMetaClass::modHasInstance(const char *kmodName) | |
497 | { | |
498 | bool result = false; | |
499 | ||
500 | if (!loadLock) { | |
91447636 | 501 | loadLock = mutex_alloc(0); |
0b4e3aa0 | 502 | mutex_lock(loadLock); |
1c79356b A |
503 | } |
504 | else | |
0b4e3aa0 | 505 | mutex_lock(loadLock); |
1c79356b A |
506 | |
507 | do { | |
508 | OSSet *kmodClasses; | |
509 | OSCollectionIterator *iter; | |
510 | OSMetaClass *checkClass; | |
511 | ||
512 | kmodClasses = OSDynamicCast(OSSet, | |
513 | sKModClassesDict->getObject(kmodName)); | |
514 | if (!kmodClasses) | |
515 | break; | |
516 | ||
517 | iter = OSCollectionIterator::withCollection(kmodClasses); | |
518 | if (!iter) | |
519 | break; | |
520 | ||
521 | while ( (checkClass = (OSMetaClass *) iter->getNextObject()) ) | |
522 | if (checkClass->getInstanceCount()) { | |
523 | result = true; | |
524 | break; | |
525 | } | |
526 | ||
527 | iter->release(); | |
528 | } while (false); | |
529 | ||
530 | mutex_unlock(loadLock); | |
531 | ||
532 | return result; | |
533 | } | |
534 | ||
535 | void OSMetaClass::reportModInstances(const char *kmodName) | |
536 | { | |
537 | OSSet *kmodClasses; | |
538 | OSCollectionIterator *iter; | |
539 | OSMetaClass *checkClass; | |
540 | ||
541 | kmodClasses = OSDynamicCast(OSSet, | |
542 | sKModClassesDict->getObject(kmodName)); | |
543 | if (!kmodClasses) | |
544 | return; | |
545 | ||
546 | iter = OSCollectionIterator::withCollection(kmodClasses); | |
547 | if (!iter) | |
548 | return; | |
549 | ||
550 | while ( (checkClass = (OSMetaClass *) iter->getNextObject()) ) | |
551 | if (checkClass->getInstanceCount()) { | |
552 | printf("%s: %s has %d instance(s)\n", | |
553 | kmodName, | |
554 | checkClass->getClassName(), | |
555 | checkClass->getInstanceCount()); | |
556 | } | |
557 | ||
558 | iter->release(); | |
559 | } | |
560 | ||
55e303ae A |
561 | extern "C" kern_return_t kmod_unload_cache(void); |
562 | ||
1c79356b A |
563 | static void _OSMetaClassConsiderUnloads(thread_call_param_t p0, |
564 | thread_call_param_t p1) | |
565 | { | |
566 | OSSet *kmodClasses; | |
567 | OSSymbol *kmodName; | |
568 | OSCollectionIterator *kmods; | |
569 | OSCollectionIterator *classes; | |
570 | OSMetaClass *checkClass; | |
9bccf70c | 571 | kmod_info_t *ki = 0; |
1c79356b A |
572 | kern_return_t ret; |
573 | bool didUnload; | |
574 | ||
0b4e3aa0 | 575 | mutex_lock(loadLock); |
1c79356b A |
576 | |
577 | do { | |
578 | ||
579 | kmods = OSCollectionIterator::withCollection(sKModClassesDict); | |
580 | if (!kmods) | |
581 | break; | |
582 | ||
583 | didUnload = false; | |
584 | while ( (kmodName = (OSSymbol *) kmods->getNextObject()) ) { | |
585 | ||
9bccf70c | 586 | if (ki) { |
55e303ae | 587 | kfree((vm_offset_t) ki, sizeof(kmod_info_t)); |
9bccf70c A |
588 | ki = 0; |
589 | } | |
590 | ||
591 | ki = kmod_lookupbyname_locked((char *)kmodName->getCStringNoCopy()); | |
1c79356b A |
592 | if (!ki) |
593 | continue; | |
594 | ||
9bccf70c A |
595 | if (ki->reference_count) { |
596 | continue; | |
597 | } | |
1c79356b A |
598 | |
599 | kmodClasses = OSDynamicCast(OSSet, | |
600 | sKModClassesDict->getObject(kmodName)); | |
601 | classes = OSCollectionIterator::withCollection(kmodClasses); | |
602 | if (!classes) | |
603 | continue; | |
604 | ||
605 | while ((checkClass = (OSMetaClass *) classes->getNextObject()) | |
606 | && (0 == checkClass->getInstanceCount())) | |
607 | {} | |
608 | classes->release(); | |
609 | ||
610 | if (0 == checkClass) { | |
611 | OSRuntimeUnloadCPP(ki, 0); // call destructors | |
612 | ret = kmod_destroy(host_priv_self(), ki->id); | |
613 | didUnload = true; | |
614 | } | |
615 | ||
9bccf70c | 616 | } |
1c79356b A |
617 | |
618 | kmods->release(); | |
619 | ||
620 | } while (didUnload); | |
621 | ||
622 | mutex_unlock(loadLock); | |
55e303ae A |
623 | |
624 | kmod_unload_cache(); | |
1c79356b A |
625 | } |
626 | ||
627 | void OSMetaClass::considerUnloads() | |
628 | { | |
629 | static thread_call_t unloadCallout; | |
630 | AbsoluteTime when; | |
631 | ||
0b4e3aa0 | 632 | mutex_lock(loadLock); |
1c79356b A |
633 | |
634 | if (!unloadCallout) | |
635 | unloadCallout = thread_call_allocate(&_OSMetaClassConsiderUnloads, 0); | |
636 | ||
637 | thread_call_cancel(unloadCallout); | |
638 | clock_interval_to_deadline(sConsiderUnloadDelay, 1000 * 1000 * 1000, &when); | |
639 | thread_call_enter_delayed(unloadCallout, when); | |
640 | ||
641 | mutex_unlock(loadLock); | |
642 | } | |
643 | ||
644 | const OSMetaClass *OSMetaClass::getMetaClassWithName(const OSSymbol *name) | |
645 | { | |
646 | OSMetaClass *retMeta = 0; | |
647 | ||
648 | if (!name) | |
649 | return 0; | |
650 | ||
651 | if (sAllClassesDict) | |
652 | retMeta = (OSMetaClass *) sAllClassesDict->getObject(name); | |
653 | ||
654 | if (!retMeta && sStalled) | |
655 | { | |
656 | // Oh dear we have to scan the stalled list and walk the | |
657 | // the stalled list manually. | |
658 | const char *cName = name->getCStringNoCopy(); | |
659 | unsigned int i; | |
660 | ||
661 | // find class in stalled list | |
662 | for (i = 0; i < sStalled->count; i++) { | |
663 | retMeta = sStalled->classes[i]; | |
664 | if (0 == strcmp(cName, (const char *) retMeta->className)) | |
665 | break; | |
666 | } | |
667 | ||
668 | if (i < sStalled->count) | |
669 | retMeta = 0; | |
670 | } | |
671 | ||
672 | return retMeta; | |
673 | } | |
674 | ||
675 | OSObject *OSMetaClass::allocClassWithName(const OSSymbol *name) | |
676 | { | |
677 | OSObject * result; | |
0b4e3aa0 | 678 | mutex_lock(loadLock); |
1c79356b A |
679 | |
680 | const OSMetaClass * const meta = getMetaClassWithName(name); | |
681 | ||
682 | if (meta) | |
683 | result = meta->alloc(); | |
684 | else | |
685 | result = 0; | |
686 | ||
687 | mutex_unlock(loadLock); | |
688 | ||
689 | return result; | |
690 | } | |
691 | ||
692 | OSObject *OSMetaClass::allocClassWithName(const OSString *name) | |
693 | { | |
694 | const OSSymbol *tmpKey = OSSymbol::withString(name); | |
695 | OSObject *result = allocClassWithName(tmpKey); | |
696 | tmpKey->release(); | |
697 | return result; | |
698 | } | |
699 | ||
700 | OSObject *OSMetaClass::allocClassWithName(const char *name) | |
701 | { | |
702 | const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name); | |
703 | OSObject *result = allocClassWithName(tmpKey); | |
704 | tmpKey->release(); | |
705 | return result; | |
706 | } | |
707 | ||
708 | ||
709 | OSMetaClassBase *OSMetaClass:: | |
710 | checkMetaCastWithName(const OSSymbol *name, const OSMetaClassBase *in) | |
711 | { | |
712 | OSMetaClassBase * result; | |
0b4e3aa0 | 713 | mutex_lock(loadLock); |
1c79356b A |
714 | const OSMetaClass * const meta = getMetaClassWithName(name); |
715 | ||
716 | if (meta) | |
717 | result = meta->checkMetaCast(in); | |
718 | else | |
719 | result = 0; | |
720 | ||
721 | mutex_unlock(loadLock); | |
722 | return result; | |
723 | } | |
724 | ||
725 | OSMetaClassBase *OSMetaClass:: | |
726 | checkMetaCastWithName(const OSString *name, const OSMetaClassBase *in) | |
727 | { | |
728 | const OSSymbol *tmpKey = OSSymbol::withString(name); | |
729 | OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in); | |
730 | tmpKey->release(); | |
731 | return result; | |
732 | } | |
733 | ||
734 | OSMetaClassBase *OSMetaClass:: | |
735 | checkMetaCastWithName(const char *name, const OSMetaClassBase *in) | |
736 | { | |
737 | const OSSymbol *tmpKey = OSSymbol::withCStringNoCopy(name); | |
738 | OSMetaClassBase *result = checkMetaCastWithName(tmpKey, in); | |
739 | tmpKey->release(); | |
740 | return result; | |
741 | } | |
742 | ||
743 | /* | |
744 | OSMetaClass::checkMetaCast | |
745 | checkMetaCast(const OSMetaClassBase *check) | |
746 | ||
747 | 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. | |
748 | ||
749 | Generally this method is not invoked directly but is used to implement the OSMetaClassBase::metaCast member function. | |
750 | ||
751 | See also OSMetaClassBase::metaCast | |
752 | ||
753 | */ | |
754 | OSMetaClassBase *OSMetaClass::checkMetaCast(const OSMetaClassBase *check) const | |
755 | { | |
756 | const OSMetaClass * const toMeta = this; | |
757 | const OSMetaClass *fromMeta; | |
758 | ||
759 | for (fromMeta = check->getMetaClass(); ; fromMeta = fromMeta->superClassLink) { | |
760 | if (toMeta == fromMeta) | |
761 | return (OSMetaClassBase *) check; // Discard const | |
762 | ||
763 | if (!fromMeta->superClassLink) | |
764 | break; | |
765 | } | |
766 | ||
767 | return 0; | |
768 | } | |
769 | ||
770 | void OSMetaClass::reservedCalled(int ind) const | |
771 | { | |
772 | const char *cname = className->getCStringNoCopy(); | |
773 | panic("%s::_RESERVED%s%d called\n", cname, cname, ind); | |
774 | } | |
775 | ||
776 | const OSMetaClass *OSMetaClass::getSuperClass() const | |
777 | { | |
778 | return superClassLink; | |
779 | } | |
780 | ||
91447636 A |
781 | const OSSymbol *OSMetaClass::getKmodName() const |
782 | { | |
783 | return sSortedByClassesDict->getObject((const OSSymbol *)this); | |
784 | } | |
785 | ||
1c79356b A |
786 | unsigned int OSMetaClass::getInstanceCount() const |
787 | { | |
788 | return instanceCount; | |
789 | } | |
790 | ||
791 | void OSMetaClass::printInstanceCounts() | |
792 | { | |
793 | OSCollectionIterator *classes; | |
794 | OSSymbol *className; | |
795 | OSMetaClass *meta; | |
796 | ||
797 | classes = OSCollectionIterator::withCollection(sAllClassesDict); | |
798 | if (!classes) | |
799 | return; | |
800 | ||
801 | while( (className = (OSSymbol *)classes->getNextObject())) { | |
802 | meta = (OSMetaClass *) sAllClassesDict->getObject(className); | |
803 | assert(meta); | |
804 | ||
805 | printf("%24s count: %03d x 0x%03x = 0x%06x\n", | |
806 | className->getCStringNoCopy(), | |
807 | meta->getInstanceCount(), | |
808 | meta->getClassSize(), | |
809 | meta->getInstanceCount() * meta->getClassSize() ); | |
810 | } | |
811 | printf("\n"); | |
812 | classes->release(); | |
813 | } | |
814 | ||
815 | OSDictionary * OSMetaClass::getClassDictionary() | |
816 | { | |
55e303ae A |
817 | panic("OSMetaClass::getClassDictionary(): Obsoleted\n"); |
818 | return 0; | |
1c79356b A |
819 | } |
820 | ||
821 | bool OSMetaClass::serialize(OSSerialize *s) const | |
822 | { | |
55e303ae A |
823 | panic("OSMetaClass::serialize(): Obsoleted\n"); |
824 | return false; | |
825 | } | |
826 | ||
827 | void OSMetaClass::serializeClassDictionary(OSDictionary *serializeDictionary) | |
828 | { | |
829 | OSDictionary *classDict; | |
830 | ||
831 | classDict = OSDictionary::withCapacity(sAllClassesDict->getCount()); | |
832 | if (!classDict) | |
833 | return; | |
1c79356b | 834 | |
55e303ae A |
835 | mutex_lock(loadLock); |
836 | do { | |
837 | OSCollectionIterator *classes; | |
838 | const OSSymbol *className; | |
1c79356b | 839 | |
55e303ae A |
840 | classes = OSCollectionIterator::withCollection(sAllClassesDict); |
841 | if (!classes) | |
842 | break; | |
843 | ||
844 | while ((className = (const OSSymbol *) classes->getNextObject())) { | |
845 | const OSMetaClass *meta; | |
846 | OSNumber *count; | |
847 | ||
848 | meta = (OSMetaClass *) sAllClassesDict->getObject(className); | |
849 | count = OSNumber::withNumber(meta->getInstanceCount(), 32); | |
850 | if (count) { | |
851 | classDict->setObject(className, count); | |
852 | count->release(); | |
853 | } | |
854 | } | |
855 | classes->release(); | |
1c79356b | 856 | |
55e303ae A |
857 | serializeDictionary->setObject("Classes", classDict); |
858 | } while (0); | |
1c79356b | 859 | |
55e303ae | 860 | mutex_unlock(loadLock); |
1c79356b | 861 | |
55e303ae | 862 | classDict->release(); |
1c79356b | 863 | } |