1/*
2 * Copyright 2005-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <Referenceable.h>
8
9#ifdef DEBUG
10#include <stdio.h>
11#endif
12
13#include <OS.h>
14
15//#define TRACE_REFERENCEABLE
16#if defined(TRACE_REFERENCEABLE) && defined(_KERNEL_MODE)
17#	include <tracing.h>
18#	define TRACE(x, ...) ktrace_printf(x, __VA_ARGS__);
19#else
20#	define TRACE(x, ...)
21#endif
22
23
24BReferenceable::BReferenceable()
25	:
26	fReferenceCount(1)
27{
28}
29
30
31BReferenceable::~BReferenceable()
32{
33#if defined(DEBUG) && !defined(_BOOT_MODE)
34	bool enterDebugger = false;
35	char message[256];
36	if (fReferenceCount == 1) {
37		// Simple heuristic to test if this object was allocated
38		// on the stack: check if this is within 1KB in either
39		// direction of the current stack address, and the reference
40		// count is 1. If so, we don't flag a warning since that would
41		// imply the object was allocated/destroyed on the stack
42		// without any references being acquired or released.
43		char test;
44		ssize_t testOffset = (addr_t)this - (addr_t)&test;
45		if (testOffset > 1024 || -testOffset > 1024) {
46			// might still be a stack object, check the thread's
47			// stack range to be sure.
48			thread_info info;
49			status_t result = get_thread_info(find_thread(NULL), &info);
50			if (result == B_OK &&  (this < info.stack_base
51					|| this > info.stack_end)) {
52				snprintf(message, sizeof(message), "Deleted referenceable "
53					"object that's not on the stack (this: %p, stack_base: %p,"
54					" stack_end: %p)\n", this, info.stack_base,
55					info.stack_end);
56				enterDebugger = true;
57			}
58		}
59	} else if (fReferenceCount != 0) {
60		snprintf(message, sizeof(message), "Deleted referenceable object %p with "
61			"non-zero reference count (%" B_PRId32 ")\n", this, fReferenceCount);
62		enterDebugger = true;
63	}
64
65	if (enterDebugger)
66		debugger(message);
67#endif
68}
69
70
71int32
72BReferenceable::AcquireReference()
73{
74	int32 previousReferenceCount = atomic_add(&fReferenceCount, 1);
75	if (previousReferenceCount == 0)
76		FirstReferenceAcquired();
77
78	TRACE("%p: acquire %ld\n", this, fReferenceCount);
79
80	return previousReferenceCount;
81}
82
83
84int32
85BReferenceable::ReleaseReference()
86{
87	int32 previousReferenceCount = atomic_add(&fReferenceCount, -1);
88	TRACE("%p: release %ld\n", this, fReferenceCount);
89	if (previousReferenceCount == 1)
90		LastReferenceReleased();
91	return previousReferenceCount;
92}
93
94
95void
96BReferenceable::FirstReferenceAcquired()
97{
98}
99
100
101void
102BReferenceable::LastReferenceReleased()
103{
104	delete this;
105}
106