cpp-common/bt2c/fmt.hpp: use `wise_enum::string_type` in `EnableIfIsWiseEnum` definition
[babeltrace.git] / src / lib / object.h
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
14 struct bt_object;
15
16 typedef void (*bt_object_release_func)(struct bt_object *);
17 typedef void (*bt_object_parent_is_owner_listener_func)(
18 struct bt_object *);
19
20 static inline
21 void bt_object_get_ref_no_null_check(const void *obj);
22
23 static inline
24 void 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 */
32 struct 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
73 static inline
74 unsigned 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
83 static inline
84 struct 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
93 static inline
94 struct 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
106 static inline
107 void 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
136 static inline
137 void 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
148 static inline
149 void 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
183 static inline
184 void 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
197 static inline
198 void 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
204 static inline
205 void bt_object_init_unique(struct bt_object *obj)
206 {
207 bt_object_init(obj, false, NULL);
208 }
209
210 static inline
211 void 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
220 static inline
221 void 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
230 static inline
231 void 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
241 static inline
242 void 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
259 static inline
260 void 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
286 static inline
287 void 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
310 static inline
311 void 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
323 static inline
324 void 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.036654 seconds and 4 git commands to generate.