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 int 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 = kalloc_tag_bt(size, VM_KERN_MEMORY_LIBKERN); 293 assert(mem); 294 bzero(mem, size); 295 OSIVAR_ACCUMSIZE(size); 296 297 return (void *) mem; 298 } 299 300 void 301 OSObject::operator delete(void * mem, size_t size) 302 { 303 if (!mem) { 304 return; 305 } 306 307 #if IOTRACKING 308 if (kIOTracking & gIOKitDebug) { 309 return OSMetaClass::trackedDelete(mem, size); 310 } 311 #endif 312 313 kfree(mem, size); 314 OSIVAR_ACCUMSIZE(-size); 315 } 316 317 bool 318 OSObject::init() 319 { 320 #if IOTRACKING 321 if (kIOTracking & gIOKitDebug) { 322 getMetaClass()->trackedInstance(this); 323 } 324 #endif 325 return true; 326 } 327 328 void 329 OSObject::free() 330 { 331 const OSMetaClass *meta = getMetaClass(); 332 333 if (meta) { 334 meta->instanceDestructed(); 335 #if IOTRACKING 336 if (kIOTracking & gIOKitDebug) { 337 getMetaClass()->trackedFree(this); 338 } 339 #endif 340 } 341 delete this; 342 } 343 344 #if IOTRACKING 345 void 346 OSObject::trackingAccumSize(size_t size) 347 { 348 if (kIOTracking & gIOKitDebug) { 349 getMetaClass()->trackedAccumSize(this, size); 350 } 351 } 352 #endif 353 354 /* Class member functions - Can't use defaults */ 355 /* During constructor vtable is always OSObject's - can't call any subclass */ 356 357 OSObject::OSObject() 358 { 359 retainCount = 1; 360 // if (kIOTracking & gIOKitDebug) getMetaClass()->trackedInstance(this); 361 } 362 363 OSObject::OSObject(const OSMetaClass *) 364 { 365 retainCount = 1; 366 // if (kIOTracking & gIOKitDebug) getMetaClass()->trackedInstance(this); 367 } 368 369 370 bool 371 OSObject::iterateObjects(void * refcon, bool (*callback)(void * refcon, OSObject * object)) 372 { 373 OSCollection * col; 374 if ((col = OSDynamicCast(OSCollection, this))) { 375 return col->iterateObjects(refcon, callback); 376 } 377 return callback(refcon, this); 378 } 379 380 bool 381 OSObject::iterateObjects(bool (^block)(OSObject * object)) 382 { 383 OSCollection * col; 384 if ((col = OSDynamicCast(OSCollection, this))) { 385 return col->iterateObjects(block); 386 } 387 return block(this); 388 } 389