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(KHEAP_DEFAULT, size, 293 Z_VM_TAG_BT(Z_WAITOK_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, Z_WAITOK_ZERO); 325 } else { 326 mem = kheap_alloc(KHEAP_DEFAULT, size, 327 Z_VM_TAG_BT(Z_WAITOK_ZERO, VM_KERN_MEMORY_LIBKERN)); 328 } 329 assert(mem); 330 OSIVAR_ACCUMSIZE(size); 331 332 return (void *) mem; 333 } 334 335 void 336 OSObject::operator delete(void * mem, size_t size) 337 { 338 if (!mem) { 339 return; 340 } 341 342 #if IOTRACKING 343 if (kIOTracking & gIOKitDebug) { 344 return OSMetaClass::trackedDelete(mem, size); 345 } 346 #endif 347 348 kern_os_kfree(mem, size); 349 OSIVAR_ACCUMSIZE(-size); 350 } 351 352 void 353 OSObject_typed_operator_delete(kalloc_type_view_t ktv, void * mem, 354 vm_size_t size) 355 { 356 if (!mem) { 357 return; 358 } 359 360 #if IOTRACKING 361 if (kIOTracking & gIOKitDebug) { 362 return OSMetaClass::trackedDelete(mem, size); 363 } 364 #endif 365 366 if (size <= kalloc_type_get_size(ktv->kt_size)) { 367 kern_os_typed_free(ktv, mem, size); 368 } else { 369 kern_os_kfree(mem, size); 370 } 371 OSIVAR_ACCUMSIZE(-size); 372 } 373 374 extern "C" void * 375 OSObject_operator_new_external(size_t size); 376 void * 377 OSObject_operator_new_external(size_t size) 378 { 379 #if IOTRACKING 380 if (kIOTracking & gIOKitDebug) { 381 return OSMetaClass::trackedNew(size); 382 } 383 #endif 384 385 void * mem = kheap_alloc(KHEAP_KEXT, size, 386 Z_VM_TAG_BT(Z_WAITOK_ZERO, VM_KERN_MEMORY_LIBKERN)); 387 assert(mem); 388 OSIVAR_ACCUMSIZE(size); 389 390 return (void *) mem; 391 } 392 393 extern "C" void 394 OSObject_operator_delete_external(void * mem, size_t size); 395 void 396 OSObject_operator_delete_external(void * mem, size_t size) 397 { 398 if (!mem) { 399 return; 400 } 401 402 #if IOTRACKING 403 if (kIOTracking & gIOKitDebug) { 404 return OSMetaClass::trackedDelete(mem, size); 405 } 406 #endif 407 408 kheap_free(KHEAP_KEXT, mem, size); 409 OSIVAR_ACCUMSIZE(-size); 410 } 411 412 bool 413 OSObject::init() 414 { 415 #if IOTRACKING 416 if (kIOTracking & gIOKitDebug) { 417 getMetaClass()->trackedInstance(this); 418 } 419 #endif 420 return true; 421 } 422 423 void 424 OSObject::free() 425 { 426 const OSMetaClass *meta = getMetaClass(); 427 428 if (meta) { 429 meta->instanceDestructed(); 430 #if IOTRACKING 431 if (kIOTracking & gIOKitDebug) { 432 getMetaClass()->trackedFree(this); 433 } 434 #endif 435 } 436 delete this; 437 } 438 439 #if IOTRACKING 440 void 441 OSObject::trackingAccumSize(size_t size) 442 { 443 if (kIOTracking & gIOKitDebug) { 444 getMetaClass()->trackedAccumSize(this, size); 445 } 446 } 447 #endif 448 449 /* Class member functions - Can't use defaults */ 450 /* During constructor vtable is always OSObject's - can't call any subclass */ 451 452 OSObject::OSObject() 453 { 454 retainCount = 1; 455 // if (kIOTracking & gIOKitDebug) getMetaClass()->trackedInstance(this); 456 } 457 458 OSObject::OSObject(const OSMetaClass *) 459 { 460 retainCount = 1; 461 // if (kIOTracking & gIOKitDebug) getMetaClass()->trackedInstance(this); 462 } 463 464 465 bool 466 OSObject::iterateObjects(void * refcon, bool (*callback)(void * refcon, OSObject * object)) 467 { 468 OSCollection * col; 469 if ((col = OSDynamicCast(OSCollection, this))) { 470 return col->iterateObjects(refcon, callback); 471 } 472 return callback(refcon, this); 473 } 474 475 bool 476 OSObject::iterateObjects(bool (^block)(OSObject * object)) 477 { 478 OSCollection * col; 479 if ((col = OSDynamicCast(OSCollection, this))) { 480 return col->iterateObjects(block); 481 } 482 return block(this); 483 } 484