1/*
2 * Copyright (c) 2000 Apple Computer, 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
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);
89
90#ifdef __ppc__
91OSMetaClassDefineReservedUnused(OSObject, 16);
92OSMetaClassDefineReservedUnused(OSObject, 17);
93OSMetaClassDefineReservedUnused(OSObject, 18);
94OSMetaClassDefineReservedUnused(OSObject, 19);
95OSMetaClassDefineReservedUnused(OSObject, 20);
96OSMetaClassDefineReservedUnused(OSObject, 21);
97OSMetaClassDefineReservedUnused(OSObject, 22);
98OSMetaClassDefineReservedUnused(OSObject, 23);
99OSMetaClassDefineReservedUnused(OSObject, 24);
100OSMetaClassDefineReservedUnused(OSObject, 25);
101OSMetaClassDefineReservedUnused(OSObject, 26);
102OSMetaClassDefineReservedUnused(OSObject, 27);
103OSMetaClassDefineReservedUnused(OSObject, 28);
104OSMetaClassDefineReservedUnused(OSObject, 29);
105OSMetaClassDefineReservedUnused(OSObject, 30);
106OSMetaClassDefineReservedUnused(OSObject, 31);
107#endif
108
109static const char *getClassName(const OSObject *obj)
110{
111    const OSMetaClass *meta = obj->getMetaClass();
112    return (meta) ? meta->getClassName() : "unknown class?";
113}
114
115bool OSObject::init()
116    { return true; }
117
118#if (!__ppc__) || (__GNUC__ < 3)
119
120// Implemented in assembler in post gcc 3.x systems as we have a problem
121// where the destructor in gcc2.95 gets 2 arguments.  The second argument
122// appears to be a flag argument.  I have copied the assembler from Puma xnu
123// to OSRuntimeSupport.c  So for 2.95 builds use the C
124void OSObject::free()
125{
126    const OSMetaClass *meta = getMetaClass();
127
128    if (meta)
129	meta->instanceDestructed();
130    delete this;
131}
132#endif /* (!__ppc__) || (__GNUC__ < 3) */
133
134int OSObject::getRetainCount() const
135{
136    return (int) ((UInt16) retainCount);
137}
138
139void OSObject::taggedRetain(const void *tag) const
140{
141    volatile UInt32 *countP = (volatile UInt32 *) &retainCount;
142    UInt32 inc = 1;
143    UInt32 origCount;
144    UInt32 newCount;
145
146    // Increment the collection bucket.
147    if ((const void *) OSTypeID(OSCollection) == tag)
148	inc |= (1UL<<16);
149
150    do {
151	origCount = *countP;
152        if ( ((UInt16) origCount | 0x1) == 0xffff ) {
153            const char *msg;
154            if (origCount & 0x1) {
155                // If count == 0xffff that means we are freeing now so we can
156                // just return obviously somebody is cleaning up dangling
157                // references.
158                msg = "Attempting to retain a freed object";
159            }
160            else {
161                // If count == 0xfffe then we have wrapped our reference count.
162                // We should stop counting now as this reference must be
163                // leaked rather than accidently wrapping around the clock and
164                // freeing a very active object later.
165
166#if !DEBUG
167		break;	// Break out of update loop which pegs the reference
168#else DEBUG
169                // @@@ gvdl: eventually need to make this panic optional
170                // based on a boot argument i.e. debug= boot flag
171                msg = "About to wrap the reference count, reference leak?";
172#endif /* !DEBUG */
173            }
174            panic("OSObject::refcount: %s", msg);
175        }
176
177	newCount = origCount + inc;
178    } while (!OSCompareAndSwap(origCount, newCount, (UInt32 *) countP));
179}
180
181void OSObject::taggedRelease(const void *tag) const
182{
183    taggedRelease(tag, 1);
184}
185
186void OSObject::taggedRelease(const void *tag, const int when) const
187{
188    volatile UInt32 *countP = (volatile UInt32 *) &retainCount;
189    UInt32 dec = 1;
190    UInt32 origCount;
191    UInt32 newCount;
192    UInt32 actualCount;
193
194    // Increment the collection bucket.
195    if ((const void *) OSTypeID(OSCollection) == tag)
196	dec |= (1UL<<16);
197
198    do {
199	origCount = *countP;
200
201        if ( ((UInt16) origCount | 0x1) == 0xffff ) {
202            if (origCount & 0x1) {
203                // If count == 0xffff that means we are freeing now so we can
204                // just return obviously somebody is cleaning up some dangling
205                // references.  So we blow out immediately.
206                return;
207            }
208            else {
209                // If count == 0xfffe then we have wrapped our reference
210                // count.  We should stop counting now as this reference must be
211                // leaked rather than accidently freeing an active object later.
212
213#if !DEBUG
214		return;	// return out of function which pegs the reference
215#else DEBUG
216                // @@@ gvdl: eventually need to make this panic optional
217                // based on a boot argument i.e. debug= boot flag
218                panic("OSObject::refcount: %s",
219                      "About to unreference a pegged object, reference leak?");
220#endif /* !DEBUG */
221            }
222        }
223	actualCount = origCount - dec;
224        if ((UInt16) actualCount < when)
225            newCount = 0xffff;
226        else
227            newCount = actualCount;
228
229    } while (!OSCompareAndSwap(origCount, newCount, (UInt32 *) countP));
230
231    //
232    // This panic means that we have just attempted to release an object
233    // who's retain count has gone to less than the number of collections
234    // it is a member off.  Take a panic immediately.
235    // In Fact the panic MAY not be a registry corruption but it is
236    // ALWAYS the wrong thing to do.  I call it a registry corruption 'cause
237    // the registry is the biggest single use of a network of collections.
238    //
239    if ((UInt16) actualCount < (actualCount >> 16))
240	panic("A driver releasing a(n) %s has corrupted the registry\n",
241	    getClassName(this));
242
243    // Check for a 'free' condition and that if we are first through
244    if (newCount == 0xffff)
245	((OSObject *) this)->free();
246}
247
248void OSObject::release() const
249{
250    taggedRelease(0);
251}
252
253void OSObject::retain() const
254{
255    taggedRetain(0);
256}
257
258void OSObject::release(int when) const
259{
260    taggedRelease(0, when);
261}
262
263bool OSObject::serialize(OSSerialize *s) const
264{
265    if (s->previouslySerialized(this)) return true;
266
267    if (!s->addXMLStartTag(this, "string")) return false;
268
269    if (!s->addString(getClassName(this))) return false;
270    if (!s->addString(" is not serializable")) return false;
271
272    return s->addXMLEndTag("string");
273}
274
275
276thread_t gOSObjectTrackThread;
277
278queue_head_t gOSObjectTrackList =
279    { (queue_t) &gOSObjectTrackList, (queue_t) &gOSObjectTrackList };
280
281lck_spin_t gOSObjectTrackLock;
282
283OSArray * OSFlushObjectTrackList(void)
284{
285    OSArray *     array;
286    queue_entry_t next;
287
288    array = OSArray::withCapacity(16);
289
290    lck_spin_lock(&gOSObjectTrackLock);
291    while (!queue_empty(&gOSObjectTrackList))
292    {
293	next = queue_first(&gOSObjectTrackList);
294	remque(next);
295	lck_spin_unlock(&gOSObjectTrackLock);
296	array->setObject((OSObject *) (next + 1));
297	lck_spin_lock(&gOSObjectTrackLock);
298    }
299    lck_spin_unlock(&gOSObjectTrackLock);
300
301    return (array);
302}
303
304struct OSObjectTracking
305{
306    queue_chain_t link;
307    void *	  bt[14];
308};
309
310void *OSObject::operator new(size_t size)
311{
312    size_t tracking        = (gIOKitDebug & kOSTraceObjectAlloc)
313			   ? sizeof(OSObjectTracking) : 0;
314    OSObjectTracking * mem = (OSObjectTracking *) kalloc(size + tracking);
315
316    assert(mem);
317
318    if (tracking)
319    {
320	if ((((thread_t) 1) == gOSObjectTrackThread) || (current_thread() == gOSObjectTrackThread))
321	{
322	    (void) OSBacktrace(&mem->bt[0], sizeof(mem->bt) / sizeof(mem->bt[0]));
323	    lck_spin_lock(&gOSObjectTrackLock);
324	    enqueue_tail(&gOSObjectTrackList, &mem->link);
325	    lck_spin_unlock(&gOSObjectTrackLock);
326	}
327	else
328	    mem->link.next = 0;
329	mem++;
330    }
331
332    bzero(mem, size);
333
334    ACCUMSIZE(size);
335
336    return (void *) mem;
337}
338
339void OSObject::operator delete(void *_mem, size_t size)
340{
341    size_t             tracking = (gIOKitDebug & kOSTraceObjectAlloc)
342				? sizeof(OSObjectTracking) : 0;
343    OSObjectTracking * mem      = (OSObjectTracking *) _mem;
344
345    if (!mem)
346	return;
347
348    if (tracking)
349    {
350	mem--;
351	if (mem->link.next)
352	{
353	    lck_spin_lock(&gOSObjectTrackLock);
354	    remque(&mem->link);
355	    lck_spin_unlock(&gOSObjectTrackLock);
356	}
357    }
358
359    kfree(mem, size + tracking);
360
361    ACCUMSIZE(-size);
362}
363