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, 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, sizeof(cstr), "%s is not serializable", getClassName(this)); 270 271 OSString * str; 272 str = OSString::withCStringNoCopy(cstr); 273 if (!str) { 274 return false; 275 } 276 277 ok = str->serialize(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(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(ktv, 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(ktv->kt_size)) { 378 kern_os_typed_free(ktv, mem, 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