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