1 | /* |
2 | * Copyright (c) 2000 Apple Inc. All rights reserved. |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
5 | * |
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 License |
10 | * may not be used to create, or enable the creation or redistribution of, |
11 | * unlawful or unlicensed copies of an Apple operating system, or to |
12 | * circumvent, violate, or enable the circumvention or violation of, any |
13 | * terms of an Apple operating system software license agreement. |
14 | * |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. |
17 | * |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
23 | * Please see the License for the specific language governing rights and |
24 | * limitations under the License. |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ |
28 | /* OSObject.cpp created by gvdl on Fri 1998-11-17 */ |
29 | |
30 | #include <libkern/c++/OSObject.h> |
31 | #include <libkern/c++/OSString.h> |
32 | #include <libkern/c++/OSArray.h> |
33 | #include <libkern/c++/OSSerialize.h> |
34 | #include <libkern/c++/OSLib.h> |
35 | #include <libkern/OSDebug.h> |
36 | #include <libkern/c++/OSCPPDebug.h> |
37 | #include <IOKit/IOKitDebug.h> |
38 | #include <libkern/OSAtomic.h> |
39 | |
40 | #include <libkern/c++/OSCollection.h> |
41 | |
42 | #include <kern/queue.h> |
43 | |
44 | __BEGIN_DECLS |
45 | size_t debug_ivars_size; |
46 | __END_DECLS |
47 | |
48 | |
49 | // OSDefineMetaClassAndAbstractStructors(OSObject, 0); |
50 | /* Class global data */ |
51 | OSObject::MetaClass OSObject::gMetaClass; |
52 | const OSMetaClass * const OSObject::metaClass = &OSObject::gMetaClass; |
53 | const OSMetaClass * const OSObject::superClass = NULL; |
54 | |
55 | /* Class member functions - Can't use defaults */ |
56 | OSObject::~OSObject() |
57 | { |
58 | } |
59 | const OSMetaClass * |
60 | OSObject::getMetaClass() const |
61 | { |
62 | return &gMetaClass; |
63 | } |
64 | OSObject * |
65 | OSObject::MetaClass::alloc() const |
66 | { |
67 | return NULL; |
68 | } |
69 | |
70 | /* The OSObject::MetaClass constructor */ |
71 | OSObject::MetaClass::MetaClass() |
72 | : OSMetaClass("OSObject" , OSObject::superClass, sizeof(OSObject)) |
73 | { |
74 | } |
75 | |
76 | // Virtual Padding |
77 | OSMetaClassDefineReservedUnused(OSObject, 0); |
78 | OSMetaClassDefineReservedUnused(OSObject, 1); |
79 | OSMetaClassDefineReservedUnused(OSObject, 2); |
80 | OSMetaClassDefineReservedUnused(OSObject, 3); |
81 | OSMetaClassDefineReservedUnused(OSObject, 4); |
82 | OSMetaClassDefineReservedUnused(OSObject, 5); |
83 | OSMetaClassDefineReservedUnused(OSObject, 6); |
84 | OSMetaClassDefineReservedUnused(OSObject, 7); |
85 | OSMetaClassDefineReservedUnused(OSObject, 8); |
86 | OSMetaClassDefineReservedUnused(OSObject, 9); |
87 | OSMetaClassDefineReservedUnused(OSObject, 10); |
88 | OSMetaClassDefineReservedUnused(OSObject, 11); |
89 | OSMetaClassDefineReservedUnused(OSObject, 12); |
90 | OSMetaClassDefineReservedUnused(OSObject, 13); |
91 | OSMetaClassDefineReservedUnused(OSObject, 14); |
92 | OSMetaClassDefineReservedUnused(OSObject, 15); |
93 | |
94 | static const char * |
95 | getClassName(const OSObject *obj) |
96 | { |
97 | const OSMetaClass *meta = obj->getMetaClass(); |
98 | return (meta) ? meta->getClassName() : "unknown class?" ; |
99 | } |
100 | |
101 | int |
102 | OSObject::getRetainCount() const |
103 | { |
104 | return (int) ((UInt16) retainCount); |
105 | } |
106 | |
107 | bool |
108 | OSObject::taggedTryRetain(const void *tag) const |
109 | { |
110 | volatile UInt32 *countP = (volatile UInt32 *) &retainCount; |
111 | UInt32 inc = 1; |
112 | UInt32 origCount; |
113 | UInt32 newCount; |
114 | |
115 | // Increment the collection bucket. |
116 | if ((const void *) OSTypeID(OSCollection) == tag) { |
117 | inc |= (1UL << 16); |
118 | } |
119 | |
120 | do { |
121 | origCount = *countP; |
122 | if (((UInt16) origCount | 0x1) == 0xffff) { |
123 | if (origCount & 0x1) { |
124 | // If count == 0xffff that means we are freeing now so we can |
125 | // just return obviously somebody is cleaning up dangling |
126 | // references. |
127 | return false; |
128 | } else { |
129 | // If count == 0xfffe then we have wrapped our reference count. |
130 | // We should stop counting now as this reference must be |
131 | // leaked rather than accidently wrapping around the clock and |
132 | // freeing a very active object later. |
133 | |
134 | #if !DEBUG |
135 | break; // Break out of update loop which pegs the reference |
136 | #else /* DEBUG */ |
137 | // @@@ gvdl: eventually need to make this panic optional |
138 | // based on a boot argument i.e. debug= boot flag |
139 | panic("OSObject::refcount: " |
140 | "About to wrap the reference count, reference leak?" ); |
141 | #endif /* !DEBUG */ |
142 | } |
143 | } |
144 | |
145 | newCount = origCount + inc; |
146 | } while (!OSCompareAndSwap(origCount, newCount, const_cast<UInt32 *>(countP))); |
147 | |
148 | return true; |
149 | } |
150 | |
151 | void |
152 | OSObject::taggedRetain(const void *tag) const |
153 | { |
154 | if (!taggedTryRetain(tag)) { |
155 | panic("OSObject::refcount: Attempting to retain a freed object" ); |
156 | } |
157 | } |
158 | |
159 | void |
160 | OSObject::taggedRelease(const void *tag) const |
161 | { |
162 | taggedRelease(tag, freeWhen: 1); |
163 | } |
164 | |
165 | void |
166 | OSObject::taggedRelease(const void *tag, const int when) const |
167 | { |
168 | volatile UInt32 *countP = (volatile UInt32 *) &retainCount; |
169 | UInt32 dec = 1; |
170 | UInt32 origCount; |
171 | UInt32 newCount; |
172 | UInt32 actualCount; |
173 | |
174 | // Increment the collection bucket. |
175 | if ((const void *) OSTypeID(OSCollection) == tag) { |
176 | dec |= (1UL << 16); |
177 | } |
178 | |
179 | do { |
180 | origCount = *countP; |
181 | |
182 | if (((UInt16) origCount | 0x1) == 0xffff) { |
183 | if (origCount & 0x1) { |
184 | // If count == 0xffff that means we are freeing now so we can |
185 | // just return obviously somebody is cleaning up some dangling |
186 | // references. So we blow out immediately. |
187 | return; |
188 | } else { |
189 | // If count == 0xfffe then we have wrapped our reference |
190 | // count. We should stop counting now as this reference must be |
191 | // leaked rather than accidently freeing an active object later. |
192 | |
193 | #if !DEBUG |
194 | return; // return out of function which pegs the reference |
195 | #else /* DEBUG */ |
196 | // @@@ gvdl: eventually need to make this panic optional |
197 | // based on a boot argument i.e. debug= boot flag |
198 | panic("OSObject::refcount: %s" , |
199 | "About to unreference a pegged object, reference leak?" ); |
200 | #endif /* !DEBUG */ |
201 | } |
202 | } |
203 | actualCount = origCount - dec; |
204 | if ((UInt16) actualCount < when) { |
205 | newCount = 0xffff; |
206 | } else { |
207 | newCount = actualCount; |
208 | } |
209 | } while (!OSCompareAndSwap(origCount, newCount, const_cast<UInt32 *>(countP))); |
210 | |
211 | // |
212 | // This panic means that we have just attempted to release an object |
213 | // whose retain count has gone to less than the number of collections |
214 | // it is a member off. Take a panic immediately. |
215 | // In fact the panic MAY not be a registry corruption but it is |
216 | // ALWAYS the wrong thing to do. I call it a registry corruption 'cause |
217 | // the registry is the biggest single use of a network of collections. |
218 | // |
219 | // xxx - this error message is overly-specific; |
220 | // xxx - any code in the kernel could trip this, |
221 | // xxx - and it applies as noted to all collections, not just the registry |
222 | if ((UInt16) actualCount < (actualCount >> 16)) { |
223 | panic("A kext releasing a(n) %s has corrupted the registry." , |
224 | getClassName(this)); |
225 | } |
226 | |
227 | // Check for a 'free' condition and that if we are first through |
228 | if (newCount == 0xffff) { |
229 | (const_cast<OSObject *>(this))->free(); |
230 | } |
231 | } |
232 | |
233 | void |
234 | OSObject::release() const |
235 | { |
236 | taggedRelease(NULL); |
237 | } |
238 | |
239 | void |
240 | OSObject::retain() const |
241 | { |
242 | taggedRetain(NULL); |
243 | } |
244 | |
245 | extern "C" void |
246 | osobject_retain(void * object) |
247 | { |
248 | ((OSObject *)object)->retain(); |
249 | } |
250 | |
251 | extern "C" void |
252 | osobject_release(void * object) |
253 | { |
254 | ((OSObject *)object)->release(); |
255 | } |
256 | |
257 | void |
258 | OSObject::release(int when) const |
259 | { |
260 | taggedRelease(NULL, when); |
261 | } |
262 | |
263 | bool |
264 | OSObject::serialize(OSSerialize *s) const |
265 | { |
266 | char cstr[128]; |
267 | bool ok; |
268 | |
269 | snprintf(cstr, count: sizeof(cstr), "%s is not serializable" , getClassName(obj: this)); |
270 | |
271 | OSString * str; |
272 | str = OSString::withCStringNoCopy(cString: cstr); |
273 | if (!str) { |
274 | return false; |
275 | } |
276 | |
277 | ok = str->serialize(serializer: s); |
278 | str->release(); |
279 | |
280 | return ok; |
281 | } |
282 | |
283 | /* |
284 | * Ignore -Wxnu-typed-allocators for the operator new/delete implementations |
285 | */ |
286 | __typed_allocators_ignore_push |
287 | |
288 | /* |
289 | * Given that all OSObjects have been transitioned to use |
290 | * OSObject_typed_operator_new/OSObject_typed_operator_delete, this should |
291 | * only be called from kexts that havent recompiled to use the new |
292 | * definitions. |
293 | */ |
294 | void * |
295 | OSObject::operator new(size_t size) |
296 | { |
297 | #if IOTRACKING |
298 | if (kIOTracking & gIOKitDebug) { |
299 | return OSMetaClass::trackedNew(size); |
300 | } |
301 | #endif |
302 | |
303 | void *mem = kheap_alloc(KHEAP_DEFAULT, size, |
304 | Z_VM_TAG_BT(Z_WAITOK_ZERO, VM_KERN_MEMORY_LIBKERN)); |
305 | assert(mem); |
306 | OSIVAR_ACCUMSIZE(size); |
307 | |
308 | return (void *) mem; |
309 | } |
310 | |
311 | void * |
312 | OSObject_typed_operator_new(kalloc_type_view_t ktv, vm_size_t size) |
313 | { |
314 | #if IOTRACKING |
315 | if (kIOTracking & gIOKitDebug) { |
316 | return OSMetaClass::trackedNew(size); |
317 | } |
318 | #endif |
319 | |
320 | /* |
321 | * Some classes in kexts that subclass from iokit classes |
322 | * don't use OSDeclare/OSDefine to declare/define structors. |
323 | * When operator new is called on such objects they end up |
324 | * using the parent's operator new/delete. If we detect such |
325 | * a case we default to using kalloc rather than kalloc_type |
326 | */ |
327 | void *mem = NULL; |
328 | if (size <= kalloc_type_get_size(kt_size: ktv->kt_size)) { |
329 | /* |
330 | * OSObject_typed_operator_new can be called from kexts, |
331 | * use the external symbol for kalloc_type_impl as |
332 | * kalloc_type_views generated at some external callsites |
333 | * many not have been processed during boot. |
334 | */ |
335 | mem = kalloc_type_impl_external(kt_view: ktv, flags: Z_WAITOK_ZERO); |
336 | } else { |
337 | mem = kheap_alloc(KHEAP_DEFAULT, size, |
338 | Z_VM_TAG_BT(Z_WAITOK_ZERO, VM_KERN_MEMORY_LIBKERN)); |
339 | } |
340 | assert(mem); |
341 | OSIVAR_ACCUMSIZE(size); |
342 | |
343 | return (void *) mem; |
344 | } |
345 | |
346 | void |
347 | OSObject::operator delete(void * mem, size_t size) |
348 | { |
349 | if (!mem) { |
350 | return; |
351 | } |
352 | |
353 | #if IOTRACKING |
354 | if (kIOTracking & gIOKitDebug) { |
355 | return OSMetaClass::trackedDelete(mem, size); |
356 | } |
357 | #endif |
358 | |
359 | kheap_free(KHEAP_DEFAULT, mem, size); |
360 | OSIVAR_ACCUMSIZE(-size); |
361 | } |
362 | |
363 | void |
364 | OSObject_typed_operator_delete(kalloc_type_view_t ktv, void * mem, |
365 | vm_size_t size) |
366 | { |
367 | if (!mem) { |
368 | return; |
369 | } |
370 | |
371 | #if IOTRACKING |
372 | if (kIOTracking & gIOKitDebug) { |
373 | return OSMetaClass::trackedDelete(mem, size); |
374 | } |
375 | #endif |
376 | |
377 | if (size <= kalloc_type_get_size(kt_size: ktv->kt_size)) { |
378 | kern_os_typed_free(ktv, addr: mem, esize: size); |
379 | } else { |
380 | kheap_free(KHEAP_DEFAULT, mem, size); |
381 | } |
382 | OSIVAR_ACCUMSIZE(-size); |
383 | } |
384 | |
385 | __typed_allocators_ignore_pop |
386 | |
387 | bool |
388 | OSObject::init() |
389 | { |
390 | #if IOTRACKING |
391 | if (kIOTracking & gIOKitDebug) { |
392 | getMetaClass()->trackedInstance(this); |
393 | } |
394 | #endif |
395 | return true; |
396 | } |
397 | |
398 | void |
399 | OSObject::free() |
400 | { |
401 | const OSMetaClass *meta = getMetaClass(); |
402 | |
403 | if (meta) { |
404 | meta->instanceDestructed(); |
405 | #if IOTRACKING |
406 | if (kIOTracking & gIOKitDebug) { |
407 | getMetaClass()->trackedFree(this); |
408 | } |
409 | #endif |
410 | } |
411 | delete this; |
412 | } |
413 | |
414 | #if IOTRACKING |
415 | void |
416 | OSObject::trackingAccumSize(size_t size) |
417 | { |
418 | if (kIOTracking & gIOKitDebug) { |
419 | getMetaClass()->trackedAccumSize(this, size); |
420 | } |
421 | } |
422 | #endif |
423 | |
424 | /* Class member functions - Can't use defaults */ |
425 | /* During constructor vtable is always OSObject's - can't call any subclass */ |
426 | |
427 | OSObject::OSObject() |
428 | { |
429 | retainCount = 1; |
430 | // if (kIOTracking & gIOKitDebug) getMetaClass()->trackedInstance(this); |
431 | } |
432 | |
433 | OSObject::OSObject(const OSMetaClass *) |
434 | { |
435 | retainCount = 1; |
436 | // if (kIOTracking & gIOKitDebug) getMetaClass()->trackedInstance(this); |
437 | } |
438 | |
439 | |
440 | bool |
441 | OSObject::iterateObjects(void * refcon, bool (*callback)(void * refcon, OSObject * object)) |
442 | { |
443 | OSCollection * col; |
444 | if ((col = OSDynamicCast(OSCollection, this))) { |
445 | return col->iterateObjects(refcon, callback); |
446 | } |
447 | return callback(refcon, this); |
448 | } |
449 | |
450 | bool |
451 | OSObject::iterateObjects(bool (^block)(OSObject * object)) |
452 | { |
453 | OSCollection * col; |
454 | if ((col = OSDynamicCast(OSCollection, this))) { |
455 | return col->iterateObjects(block); |
456 | } |
457 | return block(this); |
458 | } |
459 | |