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