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++/OSArray.h> 32 #include <libkern/c++/OSSerialize.h> 33 #include <libkern/c++/OSLib.h> 34 #include <libkern/OSDebug.h> 35 #include <libkern/c++/OSCPPDebug.h> 36 #include <IOKit/IOKitDebug.h> 37 #include <libkern/OSAtomic.h> 38 39 #include <libkern/c++/OSCollection.h> 40 41 #include <kern/queue.h> 42 43 __BEGIN_DECLS 44 int debug_ivars_size; 45 __END_DECLS 46 47 #if OSALLOCDEBUG 48 #define ACCUMSIZE(s) do { debug_ivars_size += (s); } while(0) 49 #else 50 #define ACCUMSIZE(s) 51 #endif 52 53 // OSDefineMetaClassAndAbstractStructors(OSObject, 0); 54 /* Class global data */ 55 OSObject::MetaClass OSObject::gMetaClass; 56 const OSMetaClass * const OSObject::metaClass = &OSObject::gMetaClass; 57 const OSMetaClass * const OSObject::superClass = 0; 58 59 /* Class member functions - Can't use defaults */ 60 OSObject::OSObject() { retainCount = 1; } 61 OSObject::OSObject(const OSMetaClass *) { retainCount = 1; } 62 OSObject::~OSObject() { } 63 const OSMetaClass * OSObject::getMetaClass() const 64 { return &gMetaClass; } 65 OSObject *OSObject::MetaClass::alloc() const { return 0; } 66 67 /* The OSObject::MetaClass constructor */ 68 OSObject::MetaClass::MetaClass() 69 : OSMetaClass("OSObject", OSObject::superClass, sizeof(OSObject)) 70 { } 71 72 // Virtual Padding 73 OSMetaClassDefineReservedUnused(OSObject, 0); 74 OSMetaClassDefineReservedUnused(OSObject, 1); 75 OSMetaClassDefineReservedUnused(OSObject, 2); 76 OSMetaClassDefineReservedUnused(OSObject, 3); 77 OSMetaClassDefineReservedUnused(OSObject, 4); 78 OSMetaClassDefineReservedUnused(OSObject, 5); 79 OSMetaClassDefineReservedUnused(OSObject, 6); 80 OSMetaClassDefineReservedUnused(OSObject, 7); 81 OSMetaClassDefineReservedUnused(OSObject, 8); 82 OSMetaClassDefineReservedUnused(OSObject, 9); 83 OSMetaClassDefineReservedUnused(OSObject, 10); 84 OSMetaClassDefineReservedUnused(OSObject, 11); 85 OSMetaClassDefineReservedUnused(OSObject, 12); 86 OSMetaClassDefineReservedUnused(OSObject, 13); 87 OSMetaClassDefineReservedUnused(OSObject, 14); 88 OSMetaClassDefineReservedUnused(OSObject, 15); 89 90 #ifdef __ppc__ 91 OSMetaClassDefineReservedUnused(OSObject, 16); 92 OSMetaClassDefineReservedUnused(OSObject, 17); 93 OSMetaClassDefineReservedUnused(OSObject, 18); 94 OSMetaClassDefineReservedUnused(OSObject, 19); 95 OSMetaClassDefineReservedUnused(OSObject, 20); 96 OSMetaClassDefineReservedUnused(OSObject, 21); 97 OSMetaClassDefineReservedUnused(OSObject, 22); 98 OSMetaClassDefineReservedUnused(OSObject, 23); 99 OSMetaClassDefineReservedUnused(OSObject, 24); 100 OSMetaClassDefineReservedUnused(OSObject, 25); 101 OSMetaClassDefineReservedUnused(OSObject, 26); 102 OSMetaClassDefineReservedUnused(OSObject, 27); 103 OSMetaClassDefineReservedUnused(OSObject, 28); 104 OSMetaClassDefineReservedUnused(OSObject, 29); 105 OSMetaClassDefineReservedUnused(OSObject, 30); 106 OSMetaClassDefineReservedUnused(OSObject, 31); 107 #endif 108 109 static const char *getClassName(const OSObject *obj) 110 { 111 const OSMetaClass *meta = obj->getMetaClass(); 112 return (meta) ? meta->getClassName() : "unknown class?"; 113 } 114 115 bool OSObject::init() 116 { return true; } 117 118 #if (!__ppc__) || (__GNUC__ < 3) 119 120 // Implemented in assembler in post gcc 3.x systems as we have a problem 121 // where the destructor in gcc2.95 gets 2 arguments. The second argument 122 // appears to be a flag argument. I have copied the assembler from Puma xnu 123 // to OSRuntimeSupport.c So for 2.95 builds use the C 124 void OSObject::free() 125 { 126 const OSMetaClass *meta = getMetaClass(); 127 128 if (meta) 129 meta->instanceDestructed(); 130 delete this; 131 } 132 #endif /* (!__ppc__) || (__GNUC__ < 3) */ 133 134 int OSObject::getRetainCount() const 135 { 136 return (int) ((UInt16) retainCount); 137 } 138 139 void OSObject::taggedRetain(const void *tag) const 140 { 141 volatile UInt32 *countP = (volatile UInt32 *) &retainCount; 142 UInt32 inc = 1; 143 UInt32 origCount; 144 UInt32 newCount; 145 146 // Increment the collection bucket. 147 if ((const void *) OSTypeID(OSCollection) == tag) 148 inc |= (1UL<<16); 149 150 do { 151 origCount = *countP; 152 if ( ((UInt16) origCount | 0x1) == 0xffff ) { 153 const char *msg; 154 if (origCount & 0x1) { 155 // If count == 0xffff that means we are freeing now so we can 156 // just return obviously somebody is cleaning up dangling 157 // references. 158 msg = "Attempting to retain a freed object"; 159 } 160 else { 161 // If count == 0xfffe then we have wrapped our reference count. 162 // We should stop counting now as this reference must be 163 // leaked rather than accidently wrapping around the clock and 164 // freeing a very active object later. 165 166 #if !DEBUG 167 break; // Break out of update loop which pegs the reference 168 #else /* DEBUG */ 169 // @@@ gvdl: eventually need to make this panic optional 170 // based on a boot argument i.e. debug= boot flag 171 msg = "About to wrap the reference count, reference leak?"; 172 #endif /* !DEBUG */ 173 } 174 panic("OSObject::refcount: %s", msg); 175 } 176 177 newCount = origCount + inc; 178 } while (!OSCompareAndSwap(origCount, newCount, const_cast<UInt32 *>(countP))); 179 } 180 181 void OSObject::taggedRelease(const void *tag) const 182 { 183 taggedRelease(tag, 1); 184 } 185 186 void OSObject::taggedRelease(const void *tag, const int when) const 187 { 188 volatile UInt32 *countP = (volatile UInt32 *) &retainCount; 189 UInt32 dec = 1; 190 UInt32 origCount; 191 UInt32 newCount; 192 UInt32 actualCount; 193 194 // Increment the collection bucket. 195 if ((const void *) OSTypeID(OSCollection) == tag) 196 dec |= (1UL<<16); 197 198 do { 199 origCount = *countP; 200 201 if ( ((UInt16) origCount | 0x1) == 0xffff ) { 202 if (origCount & 0x1) { 203 // If count == 0xffff that means we are freeing now so we can 204 // just return obviously somebody is cleaning up some dangling 205 // references. So we blow out immediately. 206 return; 207 } 208 else { 209 // If count == 0xfffe then we have wrapped our reference 210 // count. We should stop counting now as this reference must be 211 // leaked rather than accidently freeing an active object later. 212 213 #if !DEBUG 214 return; // return out of function which pegs the reference 215 #else /* DEBUG */ 216 // @@@ gvdl: eventually need to make this panic optional 217 // based on a boot argument i.e. debug= boot flag 218 panic("OSObject::refcount: %s", 219 "About to unreference a pegged object, reference leak?"); 220 #endif /* !DEBUG */ 221 } 222 } 223 actualCount = origCount - dec; 224 if ((UInt16) actualCount < when) 225 newCount = 0xffff; 226 else 227 newCount = actualCount; 228 229 } while (!OSCompareAndSwap(origCount, newCount, const_cast<UInt32 *>(countP))); 230 231 // 232 // This panic means that we have just attempted to release an object 233 // whose retain count has gone to less than the number of collections 234 // it is a member off. Take a panic immediately. 235 // In fact the panic MAY not be a registry corruption but it is 236 // ALWAYS the wrong thing to do. I call it a registry corruption 'cause 237 // the registry is the biggest single use of a network of collections. 238 // 239 // xxx - this error message is overly-specific; 240 // xxx - any code in the kernel could trip this, 241 // xxx - and it applies as noted to all collections, not just the registry 242 if ((UInt16) actualCount < (actualCount >> 16)) { 243 panic("A kext releasing a(n) %s has corrupted the registry.", 244 getClassName(this)); 245 } 246 247 // Check for a 'free' condition and that if we are first through 248 if (newCount == 0xffff) { 249 (const_cast<OSObject *>(this))->free(); 250 } 251 } 252 253 void OSObject::release() const 254 { 255 taggedRelease(0); 256 } 257 258 void OSObject::retain() const 259 { 260 taggedRetain(0); 261 } 262 263 void OSObject::release(int when) const 264 { 265 taggedRelease(0, when); 266 } 267 268 bool OSObject::serialize(OSSerialize *s) const 269 { 270 if (s->previouslySerialized(this)) return true; 271 272 if (!s->addXMLStartTag(this, "string")) return false; 273 274 if (!s->addString(getClassName(this))) return false; 275 if (!s->addString(" is not serializable")) return false; 276 277 return s->addXMLEndTag("string"); 278 } 279 280 281 thread_t gOSObjectTrackThread; 282 283 queue_head_t gOSObjectTrackList = 284 { (queue_t) &gOSObjectTrackList, (queue_t) &gOSObjectTrackList }; 285 286 lck_spin_t gOSObjectTrackLock; 287 288 OSArray * OSFlushObjectTrackList(void) 289 { 290 OSArray * array; 291 queue_entry_t next; 292 293 array = OSArray::withCapacity(16); 294 295 lck_spin_lock(&gOSObjectTrackLock); 296 while (!queue_empty(&gOSObjectTrackList)) 297 { 298 next = queue_first(&gOSObjectTrackList); 299 remque(next); 300 lck_spin_unlock(&gOSObjectTrackLock); 301 array->setObject((OSObject *) (next + 1)); 302 lck_spin_lock(&gOSObjectTrackLock); 303 } 304 lck_spin_unlock(&gOSObjectTrackLock); 305 306 return (array); 307 } 308 309 struct OSObjectTracking 310 { 311 queue_chain_t link; 312 void * bt[14]; 313 }; 314 315 void *OSObject::operator new(size_t size) 316 { 317 size_t tracking = (gIOKitDebug & kOSTraceObjectAlloc) 318 ? sizeof(OSObjectTracking) : 0; 319 OSObjectTracking * mem = (OSObjectTracking *) kalloc(size + tracking); 320 321 assert(mem); 322 323 if (tracking) 324 { 325 if ((((thread_t) 1) == gOSObjectTrackThread) || (current_thread() == gOSObjectTrackThread)) 326 { 327 (void) OSBacktrace(&mem->bt[0], sizeof(mem->bt) / sizeof(mem->bt[0])); 328 lck_spin_lock(&gOSObjectTrackLock); 329 enqueue_tail(&gOSObjectTrackList, &mem->link); 330 lck_spin_unlock(&gOSObjectTrackLock); 331 } 332 else 333 mem->link.next = 0; 334 mem++; 335 } 336 337 bzero(mem, size); 338 339 ACCUMSIZE(size); 340 341 return (void *) mem; 342 } 343 344 void OSObject::operator delete(void *_mem, size_t size) 345 { 346 size_t tracking = (gIOKitDebug & kOSTraceObjectAlloc) 347 ? sizeof(OSObjectTracking) : 0; 348 OSObjectTracking * mem = (OSObjectTracking *) _mem; 349 350 if (!mem) 351 return; 352 353 if (tracking) 354 { 355 mem--; 356 if (mem->link.next) 357 { 358 lck_spin_lock(&gOSObjectTrackLock); 359 remque(&mem->link); 360 lck_spin_unlock(&gOSObjectTrackLock); 361 } 362 } 363 364 kfree(mem, size + tracking); 365 366 ACCUMSIZE(-size); 367 } 368