0f8eec4c8bea9236f299d4344af89119064b2ff8
[babeltrace.git] / src / ctf-writer / object.h
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 */
6
7 #ifndef BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H
8 #define BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H
9
10 #include "common/macros.h"
11 #include "common/assert.h"
12 #include <stdbool.h>
13
14 struct bt_ctf_object;
15
16 typedef void (*bt_ctf_object_release_func)(struct bt_ctf_object *);
17 typedef void (*bt_ctf_object_parent_is_owner_listener_func)(
18 struct bt_ctf_object *);
19
20 static inline
21 void *bt_ctf_object_get_no_null_check(struct bt_ctf_object *obj);
22
23 static inline
24 void bt_ctf_object_put_no_null_check(struct bt_ctf_object *obj);
25
26 /*
27 * Babeltrace object base.
28 *
29 * All objects publicly exposed by Babeltrace APIs must contain this
30 * object as their first member.
31 */
32 struct bt_ctf_object {
33 /*
34 * True if this object is shared, that is, it has a reference
35 * count.
36 */
37 bool is_shared;
38
39 /*
40 * Current reference count.
41 */
42 unsigned long long ref_count;
43
44 /*
45 * Release function called when the object's reference count
46 * falls to zero. For an object with a parent, this function is
47 * bt_ctf_object_with_parent_release_func(), which calls
48 * `spec_release_func` below if there's no current parent.
49 */
50 bt_ctf_object_release_func release_func;
51
52 /*
53 * Specific release function called by
54 * bt_ctf_object_with_parent_release_func() or directly by a
55 * parent object.
56 */
57 bt_ctf_object_release_func spec_release_func;
58
59 /*
60 * Optional callback for an object with a parent, called by
61 * bt_ctf_object_with_parent_release_func() to indicate to the
62 * object that its parent is its owner.
63 */
64 bt_ctf_object_parent_is_owner_listener_func
65 parent_is_owner_listener_func;
66
67 /*
68 * Optional parent object.
69 */
70 struct bt_ctf_object *parent;
71 };
72
73 static inline
74 unsigned long long bt_ctf_object_get_ref_count(struct bt_ctf_object *obj)
75 {
76 BT_ASSERT_DBG(obj);
77 BT_ASSERT_DBG(obj->is_shared);
78 return obj->ref_count;
79 }
80
81 static inline
82 struct bt_ctf_object *bt_ctf_object_borrow_parent(struct bt_ctf_object *obj)
83 {
84 BT_ASSERT_DBG(obj);
85 BT_ASSERT_DBG(obj->is_shared);
86 return obj->parent;
87 }
88
89 static inline
90 struct bt_ctf_object *bt_ctf_object_get_parent(struct bt_ctf_object *obj)
91 {
92 struct bt_ctf_object *parent = bt_ctf_object_borrow_parent(obj);
93
94 if (parent) {
95 bt_ctf_object_get_no_null_check(parent);
96 }
97
98 return parent;
99 }
100
101 static inline
102 void bt_ctf_object_set_parent(struct bt_ctf_object *child, struct bt_ctf_object *parent)
103 {
104 BT_ASSERT_DBG(child);
105 BT_ASSERT_DBG(child->is_shared);
106
107 #ifdef BT_LOGT
108 BT_LOGT("Setting object's parent: addr=%p, parent-addr=%p",
109 child, parent);
110 #endif
111
112 /*
113 * It is assumed that a "child" having a parent is publicly
114 * reachable. Therefore, a reference to its parent must be
115 * taken. The reference to the parent will be released once the
116 * object's reference count falls to zero.
117 */
118 if (parent) {
119 BT_ASSERT_DBG(!child->parent);
120 child->parent = parent;
121 bt_ctf_object_get_no_null_check(parent);
122 } else {
123 if (child->parent) {
124 bt_ctf_object_put_no_null_check(child->parent);
125 }
126
127 child->parent = NULL;
128 }
129 }
130
131 static inline
132 void bt_ctf_object_try_spec_release(struct bt_ctf_object *obj)
133 {
134 BT_ASSERT_DBG(obj);
135 BT_ASSERT_DBG(obj->is_shared);
136 BT_ASSERT_DBG(obj->spec_release_func);
137
138 if (bt_ctf_object_get_ref_count(obj) == 0) {
139 obj->spec_release_func(obj);
140 }
141 }
142
143 static inline
144 void bt_ctf_object_with_parent_release_func(struct bt_ctf_object *obj)
145 {
146 if (obj->parent) {
147 /*
148 * Keep our own copy of the parent address because `obj`
149 * could be destroyed in
150 * obj->parent_is_owner_listener_func().
151 */
152 struct bt_ctf_object *parent = obj->parent;
153
154 #ifdef BT_LOGT
155 BT_LOGT("Releasing parented object: addr=%p, ref-count=%llu, "
156 "parent-addr=%p, parent-ref-count=%llu",
157 obj, obj->ref_count,
158 parent, parent->ref_count);
159 #endif
160
161 if (obj->parent_is_owner_listener_func) {
162 /*
163 * Object has a chance to destroy itself here
164 * under certain conditions and notify its
165 * parent. At this point the parent is
166 * guaranteed to exist because it's not put yet.
167 */
168 obj->parent_is_owner_listener_func(obj);
169 }
170
171 /* The release function will be invoked by the parent. */
172 bt_ctf_object_put_no_null_check(parent);
173 } else {
174 bt_ctf_object_try_spec_release(obj);
175 }
176 }
177
178 static inline
179 void bt_ctf_object_init(struct bt_ctf_object *obj, bool is_shared,
180 bt_ctf_object_release_func release_func)
181 {
182 BT_ASSERT_DBG(obj);
183 BT_ASSERT_DBG(!is_shared || release_func);
184 obj->is_shared = is_shared;
185 obj->release_func = release_func;
186 obj->parent_is_owner_listener_func = NULL;
187 obj->spec_release_func = NULL;
188 obj->parent = NULL;
189 obj->ref_count = 1;
190 }
191
192 static inline
193 void bt_ctf_object_init_shared(struct bt_ctf_object *obj,
194 bt_ctf_object_release_func release_func)
195 {
196 bt_ctf_object_init(obj, true, release_func);
197 }
198
199 static inline
200 void bt_ctf_object_init_unique(struct bt_ctf_object *obj)
201 {
202 bt_ctf_object_init(obj, false, NULL);
203 }
204
205 static inline
206 void bt_ctf_object_init_shared_with_parent(struct bt_ctf_object *obj,
207 bt_ctf_object_release_func spec_release_func)
208 {
209 BT_ASSERT_DBG(obj);
210 BT_ASSERT_DBG(spec_release_func);
211 bt_ctf_object_init_shared(obj, bt_ctf_object_with_parent_release_func);
212 obj->spec_release_func = spec_release_func;
213 }
214
215 static inline
216 void bt_ctf_object_set_parent_is_owner_listener_func(struct bt_ctf_object *obj,
217 bt_ctf_object_parent_is_owner_listener_func func)
218 {
219 BT_ASSERT_DBG(obj);
220 BT_ASSERT_DBG(obj->is_shared);
221 BT_ASSERT_DBG(obj->spec_release_func);
222 ((struct bt_ctf_object *) obj)->parent_is_owner_listener_func = func;
223 }
224
225 static inline
226 void bt_ctf_object_inc_ref_count(struct bt_ctf_object *obj)
227 {
228 BT_ASSERT_DBG(obj);
229 BT_ASSERT_DBG(obj->is_shared);
230 obj->ref_count++;
231 BT_ASSERT_DBG(obj->ref_count != 0);
232 }
233
234 static inline
235 void *bt_ctf_object_get_no_null_check_no_parent_check(struct bt_ctf_object *obj)
236 {
237 BT_ASSERT_DBG(obj);
238 BT_ASSERT_DBG(obj->is_shared);
239
240 #ifdef BT_LOGT
241 BT_LOGT("Incrementing object's reference count: %llu -> %llu: "
242 "addr=%p, cur-count=%llu, new-count=%llu",
243 obj->ref_count, obj->ref_count + 1,
244 obj, obj->ref_count, obj->ref_count + 1);
245 #endif
246
247 bt_ctf_object_inc_ref_count(obj);
248 return obj;
249 }
250
251 static inline
252 void *bt_ctf_object_get_no_null_check(struct bt_ctf_object *obj)
253 {
254 BT_ASSERT_DBG(obj);
255 BT_ASSERT_DBG(obj->is_shared);
256
257 if (G_UNLIKELY(obj->parent && bt_ctf_object_get_ref_count(obj) == 0)) {
258 #ifdef BT_LOGT
259 BT_LOGT("Incrementing object's parent's reference count: "
260 "addr=%p, parent-addr=%p", obj, obj->parent);
261 #endif
262
263 bt_ctf_object_get_no_null_check(obj->parent);
264 }
265
266 #ifdef BT_LOGT
267 BT_LOGT("Incrementing object's reference count: %llu -> %llu: "
268 "addr=%p, cur-count=%llu, new-count=%llu",
269 obj->ref_count, obj->ref_count + 1,
270 obj, obj->ref_count, obj->ref_count + 1);
271 #endif
272
273 bt_ctf_object_inc_ref_count(obj);
274 return obj;
275 }
276
277 static inline
278 void bt_ctf_object_put_no_null_check(struct bt_ctf_object *obj)
279 {
280 BT_ASSERT_DBG(obj);
281 BT_ASSERT_DBG(obj->is_shared);
282 BT_ASSERT_DBG(obj->ref_count > 0);
283
284 #ifdef BT_LOGT
285 BT_LOGT("Decrementing object's reference count: %llu -> %llu: "
286 "addr=%p, cur-count=%llu, new-count=%llu",
287 obj->ref_count, obj->ref_count - 1,
288 obj, obj->ref_count, obj->ref_count - 1);
289 #endif
290
291 obj->ref_count--;
292
293 if (obj->ref_count == 0) {
294 BT_ASSERT_DBG(obj->release_func);
295 obj->release_func(obj);
296 }
297 }
298
299 #endif /* BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H */
This page took 0.035554 seconds and 4 git commands to generate.