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