]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSObject.cpp
7da83e9a137f158ad23ff84322305e07bdf5ad59
[apple/xnu.git] / libkern / c++ / OSObject.cpp
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 }