1/* 2 * Copyright (c) 2000 Apple Computer, 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 90#ifdef __ppc__ 91OSMetaClassDefineReservedUnused(OSObject, 16); 92OSMetaClassDefineReservedUnused(OSObject, 17); 93OSMetaClassDefineReservedUnused(OSObject, 18); 94OSMetaClassDefineReservedUnused(OSObject, 19); 95OSMetaClassDefineReservedUnused(OSObject, 20); 96OSMetaClassDefineReservedUnused(OSObject, 21); 97OSMetaClassDefineReservedUnused(OSObject, 22); 98OSMetaClassDefineReservedUnused(OSObject, 23); 99OSMetaClassDefineReservedUnused(OSObject, 24); 100OSMetaClassDefineReservedUnused(OSObject, 25); 101OSMetaClassDefineReservedUnused(OSObject, 26); 102OSMetaClassDefineReservedUnused(OSObject, 27); 103OSMetaClassDefineReservedUnused(OSObject, 28); 104OSMetaClassDefineReservedUnused(OSObject, 29); 105OSMetaClassDefineReservedUnused(OSObject, 30); 106OSMetaClassDefineReservedUnused(OSObject, 31); 107#endif 108 109static const char *getClassName(const OSObject *obj) 110{ 111 const OSMetaClass *meta = obj->getMetaClass(); 112 return (meta) ? meta->getClassName() : "unknown class?"; 113} 114 115bool 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 124void 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 134int OSObject::getRetainCount() const 135{ 136 return (int) ((UInt16) retainCount); 137} 138 139void 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, (UInt32 *) countP)); 179} 180 181void OSObject::taggedRelease(const void *tag) const 182{ 183 taggedRelease(tag, 1); 184} 185 186void 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, (UInt32 *) countP)); 230 231 // 232 // This panic means that we have just attempted to release an object 233 // who's 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 if ((UInt16) actualCount < (actualCount >> 16)) 240 panic("A driver releasing a(n) %s has corrupted the registry\n", 241 getClassName(this)); 242 243 // Check for a 'free' condition and that if we are first through 244 if (newCount == 0xffff) 245 ((OSObject *) this)->free(); 246} 247 248void OSObject::release() const 249{ 250 taggedRelease(0); 251} 252 253void OSObject::retain() const 254{ 255 taggedRetain(0); 256} 257 258void OSObject::release(int when) const 259{ 260 taggedRelease(0, when); 261} 262 263bool OSObject::serialize(OSSerialize *s) const 264{ 265 if (s->previouslySerialized(this)) return true; 266 267 if (!s->addXMLStartTag(this, "string")) return false; 268 269 if (!s->addString(getClassName(this))) return false; 270 if (!s->addString(" is not serializable")) return false; 271 272 return s->addXMLEndTag("string"); 273} 274 275 276thread_t gOSObjectTrackThread; 277 278queue_head_t gOSObjectTrackList = 279 { (queue_t) &gOSObjectTrackList, (queue_t) &gOSObjectTrackList }; 280 281lck_spin_t gOSObjectTrackLock; 282 283OSArray * OSFlushObjectTrackList(void) 284{ 285 OSArray * array; 286 queue_entry_t next; 287 288 array = OSArray::withCapacity(16); 289 290 lck_spin_lock(&gOSObjectTrackLock); 291 while (!queue_empty(&gOSObjectTrackList)) 292 { 293 next = queue_first(&gOSObjectTrackList); 294 remque(next); 295 lck_spin_unlock(&gOSObjectTrackLock); 296 array->setObject((OSObject *) (next + 1)); 297 lck_spin_lock(&gOSObjectTrackLock); 298 } 299 lck_spin_unlock(&gOSObjectTrackLock); 300 301 return (array); 302} 303 304struct OSObjectTracking 305{ 306 queue_chain_t link; 307 void * bt[14]; 308}; 309 310void *OSObject::operator new(size_t size) 311{ 312 size_t tracking = (gIOKitDebug & kOSTraceObjectAlloc) 313 ? sizeof(OSObjectTracking) : 0; 314 OSObjectTracking * mem = (OSObjectTracking *) kalloc(size + tracking); 315 316 assert(mem); 317 318 if (tracking) 319 { 320 if ((((thread_t) 1) == gOSObjectTrackThread) || (current_thread() == gOSObjectTrackThread)) 321 { 322 (void) OSBacktrace(&mem->bt[0], sizeof(mem->bt) / sizeof(mem->bt[0])); 323 lck_spin_lock(&gOSObjectTrackLock); 324 enqueue_tail(&gOSObjectTrackList, &mem->link); 325 lck_spin_unlock(&gOSObjectTrackLock); 326 } 327 else 328 mem->link.next = 0; 329 mem++; 330 } 331 332 bzero(mem, size); 333 334 ACCUMSIZE(size); 335 336 return (void *) mem; 337} 338 339void OSObject::operator delete(void *_mem, size_t size) 340{ 341 size_t tracking = (gIOKitDebug & kOSTraceObjectAlloc) 342 ? sizeof(OSObjectTracking) : 0; 343 OSObjectTracking * mem = (OSObjectTracking *) _mem; 344 345 if (!mem) 346 return; 347 348 if (tracking) 349 { 350 mem--; 351 if (mem->link.next) 352 { 353 lck_spin_lock(&gOSObjectTrackLock); 354 remque(&mem->link); 355 lck_spin_unlock(&gOSObjectTrackLock); 356 } 357 } 358 359 kfree(mem, size + tracking); 360 361 ACCUMSIZE(-size); 362} 363