xref: /xnu-11215/libkern/c++/OSObject.cpp (revision 855239e5)
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 static const char *getClassName(const OSObject *obj)
91 {
92     const OSMetaClass *meta = obj->getMetaClass();
93     return (meta) ? meta->getClassName() : "unknown class?";
94 }
95 
96 bool OSObject::init()
97     { return true; }
98 
99 void OSObject::free()
100 {
101     const OSMetaClass *meta = getMetaClass();
102 
103     if (meta)
104 	meta->instanceDestructed();
105     delete this;
106 }
107 
108 int OSObject::getRetainCount() const
109 {
110     return (int) ((UInt16) retainCount);
111 }
112 
113 void 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 
155 void OSObject::taggedRelease(const void *tag) const
156 {
157     taggedRelease(tag, 1);
158 }
159 
160 void 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 
227 void OSObject::release() const
228 {
229     taggedRelease(0);
230 }
231 
232 void OSObject::retain() const
233 {
234     taggedRetain(0);
235 }
236 
237 void OSObject::release(int when) const
238 {
239     taggedRelease(0, when);
240 }
241 
242 bool 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 
255 thread_t gOSObjectTrackThread;
256 
257 queue_head_t gOSObjectTrackList =
258     { (queue_t) &gOSObjectTrackList, (queue_t) &gOSObjectTrackList };
259 
260 lck_spin_t gOSObjectTrackLock;
261 
262 OSArray * 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 
283 struct OSObjectTracking
284 {
285     queue_chain_t link;
286     void *	  bt[14];
287 };
288 
289 void *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 
318 void 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