lib: remove some unnecessary uses of `GString`
[babeltrace.git] / src / lib / object.h
... / ...
CommitLineData
1/*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
5 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 */
7
8#ifndef BABELTRACE_OBJECT_INTERNAL_H
9#define BABELTRACE_OBJECT_INTERNAL_H
10
11#include "common/assert.h"
12#include <stdbool.h>
13
14struct bt_object;
15
16typedef void (*bt_object_release_func)(struct bt_object *);
17typedef void (*bt_object_parent_is_owner_listener_func)(
18 struct bt_object *);
19
20static inline
21void bt_object_get_ref_no_null_check(const void *obj);
22
23static inline
24void bt_object_put_ref_no_null_check(const void *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 */
32struct bt_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_object_with_parent_release_func(), which calls
48 * `spec_release_func` below if there's no current parent.
49 */
50 bt_object_release_func release_func;
51
52 /*
53 * Specific release function called by
54 * bt_object_with_parent_release_func() or directly by a
55 * parent object.
56 */
57 bt_object_release_func spec_release_func;
58
59 /*
60 * Optional callback for an object with a parent, called by
61 * bt_object_with_parent_release_func() to indicate to the
62 * object that its parent is its owner.
63 */
64 bt_object_parent_is_owner_listener_func
65 parent_is_owner_listener_func;
66
67 /*
68 * Optional parent object.
69 */
70 struct bt_object *parent;
71};
72
73static inline
74unsigned long long bt_object_get_ref_count(const struct bt_object *c_obj)
75{
76 struct bt_object *obj = (void *) c_obj;
77
78 BT_ASSERT_DBG(obj);
79 BT_ASSERT_DBG(obj->is_shared);
80 return obj->ref_count;
81}
82
83static inline
84struct bt_object *bt_object_borrow_parent(const struct bt_object *c_obj)
85{
86 struct bt_object *obj = (void *) c_obj;
87
88 BT_ASSERT_DBG(obj);
89 BT_ASSERT_DBG(obj->is_shared);
90 return obj->parent;
91}
92
93static inline
94struct bt_object *bt_object_get_parent(const struct bt_object *c_obj)
95{
96 struct bt_object *obj = (void *) c_obj;
97 struct bt_object *parent = bt_object_borrow_parent(obj);
98
99 if (parent) {
100 bt_object_get_ref_no_null_check(parent);
101 }
102
103 return parent;
104}
105
106static inline
107void bt_object_set_parent(struct bt_object *child, struct bt_object *parent)
108{
109 BT_ASSERT_DBG(child);
110 BT_ASSERT_DBG(child->is_shared);
111
112#ifdef BT_LOGT
113 BT_LOGT("Setting object's parent: addr=%p, parent-addr=%p",
114 child, parent);
115#endif
116
117 /*
118 * It is assumed that a "child" having a parent is publicly
119 * reachable. Therefore, a reference to its parent must be
120 * taken. The reference to the parent will be released once the
121 * object's reference count falls to zero.
122 */
123 if (parent) {
124 BT_ASSERT_DBG(!child->parent);
125 child->parent = parent;
126 bt_object_get_ref_no_null_check(parent);
127 } else {
128 if (child->parent) {
129 bt_object_put_ref_no_null_check(child->parent);
130 }
131
132 child->parent = NULL;
133 }
134}
135
136static inline
137void bt_object_try_spec_release(struct bt_object *obj)
138{
139 BT_ASSERT_DBG(obj);
140 BT_ASSERT_DBG(obj->is_shared);
141 BT_ASSERT_DBG(obj->spec_release_func);
142
143 if (bt_object_get_ref_count(obj) == 0) {
144 obj->spec_release_func(obj);
145 }
146}
147
148static inline
149void bt_object_with_parent_release_func(struct bt_object *obj)
150{
151 if (obj->parent) {
152 /*
153 * Keep our own copy of the parent address because `obj`
154 * could be destroyed in
155 * obj->parent_is_owner_listener_func().
156 */
157 struct bt_object *parent = obj->parent;
158
159#ifdef BT_LOGT
160 BT_LOGT("Releasing parented object: addr=%p, ref-count=%llu, "
161 "parent-addr=%p, parent-ref-count=%llu",
162 obj, obj->ref_count,
163 parent, parent->ref_count);
164#endif
165
166 if (obj->parent_is_owner_listener_func) {
167 /*
168 * Object has a chance to destroy itself here
169 * under certain conditions and notify its
170 * parent. At this point the parent is
171 * guaranteed to exist because it's not put yet.
172 */
173 obj->parent_is_owner_listener_func(obj);
174 }
175
176 /* The release function will be invoked by the parent. */
177 bt_object_put_ref_no_null_check(parent);
178 } else {
179 bt_object_try_spec_release(obj);
180 }
181}
182
183static inline
184void bt_object_init(struct bt_object *obj, bool is_shared,
185 bt_object_release_func release_func)
186{
187 BT_ASSERT_DBG(obj);
188 BT_ASSERT_DBG(!is_shared || release_func);
189 obj->is_shared = is_shared;
190 obj->release_func = release_func;
191 obj->parent_is_owner_listener_func = NULL;
192 obj->spec_release_func = NULL;
193 obj->parent = NULL;
194 obj->ref_count = 1;
195}
196
197static inline
198void bt_object_init_shared(struct bt_object *obj,
199 bt_object_release_func release_func)
200{
201 bt_object_init(obj, true, release_func);
202}
203
204static inline
205void bt_object_init_unique(struct bt_object *obj)
206{
207 bt_object_init(obj, false, NULL);
208}
209
210static inline
211void bt_object_init_shared_with_parent(struct bt_object *obj,
212 bt_object_release_func spec_release_func)
213{
214 BT_ASSERT_DBG(obj);
215 BT_ASSERT_DBG(spec_release_func);
216 bt_object_init_shared(obj, bt_object_with_parent_release_func);
217 obj->spec_release_func = spec_release_func;
218}
219
220static inline
221void bt_object_set_parent_is_owner_listener_func(struct bt_object *obj,
222 bt_object_parent_is_owner_listener_func func)
223{
224 BT_ASSERT_DBG(obj);
225 BT_ASSERT_DBG(obj->is_shared);
226 BT_ASSERT_DBG(obj->spec_release_func);
227 ((struct bt_object *) obj)->parent_is_owner_listener_func = func;
228}
229
230static inline
231void bt_object_inc_ref_count(const struct bt_object *c_obj)
232{
233 struct bt_object *obj = (void *) c_obj;
234
235 BT_ASSERT_DBG(obj);
236 BT_ASSERT_DBG(obj->is_shared);
237 obj->ref_count++;
238 BT_ASSERT_DBG(obj->ref_count != 0);
239}
240
241static inline
242void bt_object_get_ref_no_null_check_no_parent_check(const struct bt_object *c_obj)
243{
244 struct bt_object *obj = (void *) c_obj;
245
246 BT_ASSERT_DBG(obj);
247 BT_ASSERT_DBG(obj->is_shared);
248
249#ifdef BT_LOGT
250 BT_LOGT("Incrementing object's reference count: %llu -> %llu: "
251 "addr=%p, cur-count=%llu, new-count=%llu",
252 obj->ref_count, obj->ref_count + 1,
253 obj, obj->ref_count, obj->ref_count + 1);
254#endif
255
256 bt_object_inc_ref_count(obj);
257}
258
259static inline
260void bt_object_get_ref_no_null_check(const void *c_obj)
261{
262 struct bt_object *obj = (void *) c_obj;
263
264 BT_ASSERT_DBG(obj);
265 BT_ASSERT_DBG(obj->is_shared);
266
267 if (G_UNLIKELY(obj->parent && bt_object_get_ref_count(obj) == 0)) {
268#ifdef BT_LOGT
269 BT_LOGT("Incrementing object's parent's reference count: "
270 "addr=%p, parent-addr=%p", obj, obj->parent);
271#endif
272
273 bt_object_get_ref_no_null_check(obj->parent);
274 }
275
276#ifdef BT_LOGT
277 BT_LOGT("Incrementing object's reference count: %llu -> %llu: "
278 "addr=%p, cur-count=%llu, new-count=%llu",
279 obj->ref_count, obj->ref_count + 1,
280 obj, obj->ref_count, obj->ref_count + 1);
281#endif
282
283 bt_object_inc_ref_count(obj);
284}
285
286static inline
287void bt_object_put_ref_no_null_check(const void *c_obj)
288{
289 struct bt_object *obj = (void *) c_obj;
290
291 BT_ASSERT_DBG(obj);
292 BT_ASSERT_DBG(obj->is_shared);
293 BT_ASSERT_DBG(obj->ref_count > 0);
294
295#ifdef BT_LOGT
296 BT_LOGT("Decrementing object's reference count: %llu -> %llu: "
297 "addr=%p, cur-count=%llu, new-count=%llu",
298 obj->ref_count, obj->ref_count - 1,
299 obj, obj->ref_count, obj->ref_count - 1);
300#endif
301
302 obj->ref_count--;
303
304 if (obj->ref_count == 0) {
305 BT_ASSERT_DBG(obj->release_func);
306 obj->release_func(obj);
307 }
308}
309
310static inline
311void bt_object_get_ref(const void *ptr)
312{
313 struct bt_object *obj = (void *) ptr;
314
315 if (G_UNLIKELY(!obj)) {
316 return;
317 }
318
319 BT_ASSERT_DBG(obj->is_shared);
320 bt_object_get_ref_no_null_check(obj);
321}
322
323static inline
324void bt_object_put_ref(const void *ptr)
325{
326 struct bt_object *obj = (void *) ptr;
327
328 if (G_UNLIKELY(!obj)) {
329 return;
330 }
331
332 BT_ASSERT_DBG(obj->is_shared);
333 BT_ASSERT_DBG(bt_object_get_ref_count(obj) > 0);
334 bt_object_put_ref_no_null_check(obj);
335}
336
337#define BT_OBJECT_PUT_REF_AND_RESET(_var) \
338 do { \
339 bt_object_put_ref(_var); \
340 (_var) = NULL; \
341 } while (0)
342
343#define BT_OBJECT_MOVE_REF(_var_dst, _var_src) \
344 do { \
345 bt_object_put_ref(_var_dst); \
346 (_var_dst) = (_var_src); \
347 (_var_src) = NULL; \
348 } while (0)
349
350#endif /* BABELTRACE_OBJECT_INTERNAL_H */
This page took 0.024101 seconds and 5 git commands to generate.