xref: /xnu-11215/libkern/c++/OSObject.cpp (revision a3bb9fcc)
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 #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 */
56 OSObject::MetaClass OSObject::gMetaClass;
57 const OSMetaClass * const OSObject::metaClass = &OSObject::gMetaClass;
58 const OSMetaClass * const OSObject::superClass = 0;
59 
60 /* Class member functions - Can't use defaults */
61 OSObject::OSObject()			{ retainCount = 1; }
62 OSObject::OSObject(const OSMetaClass *)	{ retainCount = 1; }
63 OSObject::~OSObject()			{ }
64 const OSMetaClass * OSObject::getMetaClass() const
65     { return &gMetaClass; }
66 OSObject *OSObject::MetaClass::alloc() const { return 0; }
67 
68 /* The OSObject::MetaClass constructor */
69 OSObject::MetaClass::MetaClass()
70     : OSMetaClass("OSObject", OSObject::superClass, sizeof(OSObject))
71     { }
72 
73 // Virtual Padding
74 OSMetaClassDefineReservedUnused(OSObject,  0);
75 OSMetaClassDefineReservedUnused(OSObject,  1);
76 OSMetaClassDefineReservedUnused(OSObject,  2);
77 OSMetaClassDefineReservedUnused(OSObject,  3);
78 OSMetaClassDefineReservedUnused(OSObject,  4);
79 OSMetaClassDefineReservedUnused(OSObject,  5);
80 OSMetaClassDefineReservedUnused(OSObject,  6);
81 OSMetaClassDefineReservedUnused(OSObject,  7);
82 OSMetaClassDefineReservedUnused(OSObject,  8);
83 OSMetaClassDefineReservedUnused(OSObject,  9);
84 OSMetaClassDefineReservedUnused(OSObject, 10);
85 OSMetaClassDefineReservedUnused(OSObject, 11);
86 OSMetaClassDefineReservedUnused(OSObject, 12);
87 OSMetaClassDefineReservedUnused(OSObject, 13);
88 OSMetaClassDefineReservedUnused(OSObject, 14);
89 OSMetaClassDefineReservedUnused(OSObject, 15);
90 
91 static const char *getClassName(const OSObject *obj)
92 {
93     const OSMetaClass *meta = obj->getMetaClass();
94     return (meta) ? meta->getClassName() : "unknown class?";
95 }
96 
97 bool OSObject::init()
98     { return true; }
99 
100 void OSObject::free()
101 {
102     const OSMetaClass *meta = getMetaClass();
103 
104     if (meta)
105 	meta->instanceDestructed();
106     delete this;
107 }
108 
109 int OSObject::getRetainCount() const
110 {
111     return (int) ((UInt16) retainCount);
112 }
113 
114 void 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 
156 void OSObject::taggedRelease(const void *tag) const
157 {
158     taggedRelease(tag, 1);
159 }
160 
161 void 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 
228 void OSObject::release() const
229 {
230     taggedRelease(0);
231 }
232 
233 void OSObject::retain() const
234 {
235     taggedRetain(0);
236 }
237 
238 void OSObject::release(int when) const
239 {
240     taggedRelease(0, when);
241 }
242 
243 bool 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 
261 thread_t gOSObjectTrackThread;
262 
263 queue_head_t gOSObjectTrackList =
264     { (queue_t) &gOSObjectTrackList, (queue_t) &gOSObjectTrackList };
265 
266 lck_spin_t gOSObjectTrackLock;
267 
268 OSArray * 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 
289 struct OSObjectTracking
290 {
291     queue_chain_t link;
292     void *	  bt[14];
293 };
294 
295 void *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 
324 void 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