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