xref: /haiku/src/kits/support/Referenceable.cpp (revision b617a7b410c05275effb95f4b2f5608359d9b7b9)
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 
24 BReferenceable::BReferenceable()
25 	:
26 	fReferenceCount(1)
27 {
28 }
29 
30 
31 BReferenceable::~BReferenceable()
32 {
33 #ifdef DEBUG
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 
71 int32
72 BReferenceable::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 
84 int32
85 BReferenceable::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 
95 void
96 BReferenceable::FirstReferenceAcquired()
97 {
98 }
99 
100 
101 void
102 BReferenceable::LastReferenceReleased()
103 {
104 	delete this;
105 }
106