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