]> git.saurik.com Git - apple/xnu.git/blame - libkern/c++/OSObject.cpp
xnu-1699.22.73.tar.gz
[apple/xnu.git] / libkern / c++ / OSObject.cpp
CommitLineData
1c79356b 1/*
b0d623f7 2 * Copyright (c) 2000 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* OSObject.cpp created by gvdl on Fri 1998-11-17 */
29
30#include <libkern/c++/OSObject.h>
2d21ac55 31#include <libkern/c++/OSArray.h>
1c79356b 32#include <libkern/c++/OSSerialize.h>
1c79356b 33#include <libkern/c++/OSLib.h>
2d21ac55 34#include <libkern/OSDebug.h>
1c79356b 35#include <libkern/c++/OSCPPDebug.h>
2d21ac55 36#include <IOKit/IOKitDebug.h>
1c79356b
A
37#include <libkern/OSAtomic.h>
38
9bccf70c
A
39#include <libkern/c++/OSCollection.h>
40
2d21ac55
A
41#include <kern/queue.h>
42
1c79356b
A
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);
0c530ab8 89
9bccf70c
A
90static const char *getClassName(const OSObject *obj)
91{
92 const OSMetaClass *meta = obj->getMetaClass();
93 return (meta) ? meta->getClassName() : "unknown class?";
94}
95
96bool OSObject::init()
97 { return true; }
1c79356b 98
1c79356b
A
99void OSObject::free()
100{
101 const OSMetaClass *meta = getMetaClass();
102
103 if (meta)
104 meta->instanceDestructed();
105 delete this;
106}
107
108int OSObject::getRetainCount() const
109{
9bccf70c 110 return (int) ((UInt16) retainCount);
1c79356b
A
111}
112
9bccf70c 113void OSObject::taggedRetain(const void *tag) const
1c79356b 114{
9bccf70c
A
115 volatile UInt32 *countP = (volatile UInt32 *) &retainCount;
116 UInt32 inc = 1;
117 UInt32 origCount;
118 UInt32 newCount;
119
55e303ae 120 // Increment the collection bucket.
9bccf70c
A
121 if ((const void *) OSTypeID(OSCollection) == tag)
122 inc |= (1UL<<16);
123
124 do {
125 origCount = *countP;
55e303ae
A
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.
9bccf70c 139
55e303ae
A
140#if !DEBUG
141 break; // Break out of update loop which pegs the reference
b0d623f7 142#else /* DEBUG */
55e303ae
A
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 }
9bccf70c
A
150
151 newCount = origCount + inc;
b0d623f7 152 } while (!OSCompareAndSwap(origCount, newCount, const_cast<UInt32 *>(countP)));
1c79356b
A
153}
154
9bccf70c
A
155void OSObject::taggedRelease(const void *tag) const
156{
157 taggedRelease(tag, 1);
158}
159
160void OSObject::taggedRelease(const void *tag, const int when) const
1c79356b 161{
9bccf70c
A
162 volatile UInt32 *countP = (volatile UInt32 *) &retainCount;
163 UInt32 dec = 1;
164 UInt32 origCount;
165 UInt32 newCount;
166 UInt32 actualCount;
167
55e303ae 168 // Increment the collection bucket.
9bccf70c
A
169 if ((const void *) OSTypeID(OSCollection) == tag)
170 dec |= (1UL<<16);
171
172 do {
173 origCount = *countP;
55e303ae
A
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.
9bccf70c 186
55e303ae
A
187#if !DEBUG
188 return; // return out of function which pegs the reference
b0d623f7 189#else /* DEBUG */
55e303ae
A
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 }
9bccf70c 197 actualCount = origCount - dec;
55e303ae
A
198 if ((UInt16) actualCount < when)
199 newCount = 0xffff;
9bccf70c
A
200 else
201 newCount = actualCount;
202
b0d623f7 203 } while (!OSCompareAndSwap(origCount, newCount, const_cast<UInt32 *>(countP)));
9bccf70c
A
204
205 //
206 // This panic means that we have just attempted to release an object
b0d623f7 207 // whose retain count has gone to less than the number of collections
9bccf70c 208 // it is a member off. Take a panic immediately.
b0d623f7 209 // In fact the panic MAY not be a registry corruption but it is
9bccf70c
A
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 //
b0d623f7
A
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 }
9bccf70c
A
220
221 // Check for a 'free' condition and that if we are first through
b0d623f7
A
222 if (newCount == 0xffff) {
223 (const_cast<OSObject *>(this))->free();
224 }
1c79356b
A
225}
226
227void OSObject::release() const
228{
9bccf70c
A
229 taggedRelease(0);
230}
231
232void OSObject::retain() const
233{
234 taggedRetain(0);
235}
236
237void OSObject::release(int when) const
238{
239 taggedRelease(0, when);
1c79356b
A
240}
241
242bool OSObject::serialize(OSSerialize *s) const
243{
244 if (s->previouslySerialized(this)) return true;
245
246 if (!s->addXMLStartTag(this, "string")) return false;
247
9bccf70c 248 if (!s->addString(getClassName(this))) return false;
1c79356b
A
249 if (!s->addString(" is not serializable")) return false;
250
251 return s->addXMLEndTag("string");
252}
253
2d21ac55
A
254
255thread_t gOSObjectTrackThread;
256
257queue_head_t gOSObjectTrackList =
258 { (queue_t) &gOSObjectTrackList, (queue_t) &gOSObjectTrackList };
259
260lck_spin_t gOSObjectTrackLock;
261
262OSArray * 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
283struct OSObjectTracking
284{
285 queue_chain_t link;
286 void * bt[14];
287};
288
1c79356b
A
289void *OSObject::operator new(size_t size)
290{
2d21ac55
A
291 size_t tracking = (gIOKitDebug & kOSTraceObjectAlloc)
292 ? sizeof(OSObjectTracking) : 0;
293 OSObjectTracking * mem = (OSObjectTracking *) kalloc(size + tracking);
294
1c79356b 295 assert(mem);
2d21ac55
A
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
1c79356b
A
311 bzero(mem, size);
312
313 ACCUMSIZE(size);
314
2d21ac55 315 return (void *) mem;
1c79356b
A
316}
317
2d21ac55 318void OSObject::operator delete(void *_mem, size_t size)
1c79356b 319{
2d21ac55
A
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);
1c79356b
A
339
340 ACCUMSIZE(-size);
341}