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 void * 284 OSObject::operator new(size_t size) 285 { 286 #if IOTRACKING 287 if (kIOTracking & gIOKitDebug) { 288 return OSMetaClass::trackedNew(size); 289 } 290 #endif 291 292 void *mem = kheap_alloc_tag_bt(KHEAP_DEFAULT, size, 293 (zalloc_flags_t) (Z_WAITOK | Z_ZERO), VM_KERN_MEMORY_LIBKERN); 294 assert(mem); 295 OSIVAR_ACCUMSIZE(size); 296 297 return (void *) mem; 298 } 299 300 void * 301 OSObject_typed_operator_new(kalloc_type_view_t ktv, vm_size_t size) 302 { 303 #if IOTRACKING 304 if (kIOTracking & gIOKitDebug) { 305 return OSMetaClass::trackedNew(size); 306 } 307 #endif 308 309 /* 310 * Some classes in kexts that subclass from iokit classes 311 * don't use OSDeclare/OSDefine to declare/define structors. 312 * When operator new is called on such objects they end up 313 * using the parent's operator new/delete. If we detect such 314 * a case we default to using kalloc rather than kalloc_type 315 */ 316 void *mem = NULL; 317 if (size <= kalloc_type_get_size(ktv->kt_size)) { 318 /* 319 * OSObject_typed_operator_new can be called from kexts, 320 * use the external symbol for kalloc_type_impl as 321 * kalloc_type_views generated at some external callsites 322 * many not have been processed during boot. 323 */ 324 mem = kalloc_type_impl_external(ktv, (zalloc_flags_t) 325 (Z_WAITOK | Z_ZERO)); 326 } else { 327 mem = kheap_alloc_tag_bt(KHEAP_DEFAULT, size, 328 (zalloc_flags_t) (Z_WAITOK | Z_ZERO), VM_KERN_MEMORY_LIBKERN); 329 } 330 assert(mem); 331 OSIVAR_ACCUMSIZE(size); 332 333 return (void *) mem; 334 } 335 336 void 337 OSObject::operator delete(void * mem, size_t size) 338 { 339 if (!mem) { 340 return; 341 } 342 343 #if IOTRACKING 344 if (kIOTracking & gIOKitDebug) { 345 return OSMetaClass::trackedDelete(mem, size); 346 } 347 #endif 348 349 kern_os_kfree(mem, size); 350 OSIVAR_ACCUMSIZE(-size); 351 } 352 353 void 354 OSObject_typed_operator_delete(kalloc_type_view_t ktv, void * mem, 355 vm_size_t size) 356 { 357 if (!mem) { 358 return; 359 } 360 361 #if IOTRACKING 362 if (kIOTracking & gIOKitDebug) { 363 return OSMetaClass::trackedDelete(mem, size); 364 } 365 #endif 366 367 if (size <= kalloc_type_get_size(ktv->kt_size)) { 368 kern_os_typed_free(ktv, mem, size); 369 } else { 370 kern_os_kfree(mem, size); 371 } 372 OSIVAR_ACCUMSIZE(-size); 373 } 374 375 extern "C" void * 376 OSObject_operator_new_external(size_t size); 377 void * 378 OSObject_operator_new_external(size_t size) 379 { 380 #if IOTRACKING 381 if (kIOTracking & gIOKitDebug) { 382 return OSMetaClass::trackedNew(size); 383 } 384 #endif 385 386 void * mem = kheap_alloc_tag_bt(KHEAP_KEXT, size, 387 (zalloc_flags_t) (Z_WAITOK | Z_ZERO), VM_KERN_MEMORY_LIBKERN); 388 assert(mem); 389 OSIVAR_ACCUMSIZE(size); 390 391 return (void *) mem; 392 } 393 394 extern "C" void 395 OSObject_operator_delete_external(void * mem, size_t size); 396 void 397 OSObject_operator_delete_external(void * mem, size_t size) 398 { 399 if (!mem) { 400 return; 401 } 402 403 #if IOTRACKING 404 if (kIOTracking & gIOKitDebug) { 405 return OSMetaClass::trackedDelete(mem, size); 406 } 407 #endif 408 409 kheap_free(KHEAP_KEXT, mem, size); 410 OSIVAR_ACCUMSIZE(-size); 411 } 412 413 bool 414 OSObject::init() 415 { 416 #if IOTRACKING 417 if (kIOTracking & gIOKitDebug) { 418 getMetaClass()->trackedInstance(this); 419 } 420 #endif 421 return true; 422 } 423 424 void 425 OSObject::free() 426 { 427 const OSMetaClass *meta = getMetaClass(); 428 429 if (meta) { 430 meta->instanceDestructed(); 431 #if IOTRACKING 432 if (kIOTracking & gIOKitDebug) { 433 getMetaClass()->trackedFree(this); 434 } 435 #endif 436 } 437 delete this; 438 } 439 440 #if IOTRACKING 441 void 442 OSObject::trackingAccumSize(size_t size) 443 { 444 if (kIOTracking & gIOKitDebug) { 445 getMetaClass()->trackedAccumSize(this, size); 446 } 447 } 448 #endif 449 450 /* Class member functions - Can't use defaults */ 451 /* During constructor vtable is always OSObject's - can't call any subclass */ 452 453 OSObject::OSObject() 454 { 455 retainCount = 1; 456 // if (kIOTracking & gIOKitDebug) getMetaClass()->trackedInstance(this); 457 } 458 459 OSObject::OSObject(const OSMetaClass *) 460 { 461 retainCount = 1; 462 // if (kIOTracking & gIOKitDebug) getMetaClass()->trackedInstance(this); 463 } 464 465 466 bool 467 OSObject::iterateObjects(void * refcon, bool (*callback)(void * refcon, OSObject * object)) 468 { 469 OSCollection * col; 470 if ((col = OSDynamicCast(OSCollection, this))) { 471 return col->iterateObjects(refcon, callback); 472 } 473 return callback(refcon, this); 474 } 475 476 bool 477 OSObject::iterateObjects(bool (^block)(OSObject * object)) 478 { 479 OSCollection * col; 480 if ((col = OSDynamicCast(OSCollection, this))) { 481 return col->iterateObjects(block); 482 } 483 return block(this); 484 } 485