Move to kernel style SPDX license identifiers
[babeltrace.git] / src / ctf-writer / object.h
CommitLineData
e1e02a22 1/*
0235b0db 2 * SPDX-License-Identifier: MIT
e1e02a22 3 *
0235b0db 4 * Copyright 2015 Jérémie Galarneau <jeremie.galarneau@efficios.com>
e1e02a22
PP
5 */
6
0235b0db
MJ
7#ifndef BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H
8#define BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H
9
91d81473 10#include "common/macros.h"
578e048b 11#include "common/assert.h"
e1e02a22
PP
12#include <stdbool.h>
13
14struct bt_ctf_object;
15
16typedef void (*bt_ctf_object_release_func)(struct bt_ctf_object *);
17typedef void (*bt_ctf_object_parent_is_owner_listener_func)(
18 struct bt_ctf_object *);
19
20static inline
21void *bt_ctf_object_get_no_null_check(struct bt_ctf_object *obj);
22
23static inline
24void 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 */
32struct 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
73static inline
74unsigned long long bt_ctf_object_get_ref_count(struct bt_ctf_object *obj)
75{
98b15851
PP
76 BT_ASSERT_DBG(obj);
77 BT_ASSERT_DBG(obj->is_shared);
e1e02a22
PP
78 return obj->ref_count;
79}
80
81static inline
82struct bt_ctf_object *bt_ctf_object_borrow_parent(struct bt_ctf_object *obj)
83{
98b15851
PP
84 BT_ASSERT_DBG(obj);
85 BT_ASSERT_DBG(obj->is_shared);
e1e02a22
PP
86 return obj->parent;
87}
88
89static inline
90struct 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
101static inline
102void bt_ctf_object_set_parent(struct bt_ctf_object *child, struct bt_ctf_object *parent)
103{
98b15851
PP
104 BT_ASSERT_DBG(child);
105 BT_ASSERT_DBG(child->is_shared);
e1e02a22 106
ef267d12
PP
107#ifdef BT_LOGT
108 BT_LOGT("Setting object's parent: addr=%p, parent-addr=%p",
e1e02a22
PP
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) {
98b15851 119 BT_ASSERT_DBG(!child->parent);
e1e02a22
PP
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
131static inline
132void bt_ctf_object_try_spec_release(struct bt_ctf_object *obj)
133{
98b15851
PP
134 BT_ASSERT_DBG(obj);
135 BT_ASSERT_DBG(obj->is_shared);
136 BT_ASSERT_DBG(obj->spec_release_func);
e1e02a22
PP
137
138 if (bt_ctf_object_get_ref_count(obj) == 0) {
139 obj->spec_release_func(obj);
140 }
141}
142
143static inline
144void 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
ef267d12
PP
154#ifdef BT_LOGT
155 BT_LOGT("Releasing parented object: addr=%p, ref-count=%llu, "
e1e02a22
PP
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
178static inline
179void bt_ctf_object_init(struct bt_ctf_object *obj, bool is_shared,
180 bt_ctf_object_release_func release_func)
181{
98b15851
PP
182 BT_ASSERT_DBG(obj);
183 BT_ASSERT_DBG(!is_shared || release_func);
e1e02a22
PP
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
192static inline
193void 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
199static inline
200void bt_ctf_object_init_unique(struct bt_ctf_object *obj)
201{
202 bt_ctf_object_init(obj, false, NULL);
203}
204
205static inline
206void bt_ctf_object_init_shared_with_parent(struct bt_ctf_object *obj,
207 bt_ctf_object_release_func spec_release_func)
208{
98b15851
PP
209 BT_ASSERT_DBG(obj);
210 BT_ASSERT_DBG(spec_release_func);
e1e02a22
PP
211 bt_ctf_object_init_shared(obj, bt_ctf_object_with_parent_release_func);
212 obj->spec_release_func = spec_release_func;
213}
214
215static inline
216void 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{
98b15851
PP
219 BT_ASSERT_DBG(obj);
220 BT_ASSERT_DBG(obj->is_shared);
221 BT_ASSERT_DBG(obj->spec_release_func);
e1e02a22
PP
222 ((struct bt_ctf_object *) obj)->parent_is_owner_listener_func = func;
223}
224
225static inline
226void bt_ctf_object_inc_ref_count(struct bt_ctf_object *obj)
227{
98b15851
PP
228 BT_ASSERT_DBG(obj);
229 BT_ASSERT_DBG(obj->is_shared);
e1e02a22 230 obj->ref_count++;
98b15851 231 BT_ASSERT_DBG(obj->ref_count != 0);
e1e02a22
PP
232}
233
234static inline
235void *bt_ctf_object_get_no_null_check_no_parent_check(struct bt_ctf_object *obj)
236{
98b15851
PP
237 BT_ASSERT_DBG(obj);
238 BT_ASSERT_DBG(obj->is_shared);
e1e02a22 239
ef267d12
PP
240#ifdef BT_LOGT
241 BT_LOGT("Incrementing object's reference count: %llu -> %llu: "
e1e02a22
PP
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
251static inline
252void *bt_ctf_object_get_no_null_check(struct bt_ctf_object *obj)
253{
98b15851
PP
254 BT_ASSERT_DBG(obj);
255 BT_ASSERT_DBG(obj->is_shared);
e1e02a22 256
91d81473 257 if (G_UNLIKELY(obj->parent && bt_ctf_object_get_ref_count(obj) == 0)) {
ef267d12
PP
258#ifdef BT_LOGT
259 BT_LOGT("Incrementing object's parent's reference count: "
e1e02a22
PP
260 "addr=%p, parent-addr=%p", obj, obj->parent);
261#endif
262
263 bt_ctf_object_get_no_null_check(obj->parent);
264 }
265
ef267d12
PP
266#ifdef BT_LOGT
267 BT_LOGT("Incrementing object's reference count: %llu -> %llu: "
e1e02a22
PP
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
277static inline
278void bt_ctf_object_put_no_null_check(struct bt_ctf_object *obj)
279{
98b15851
PP
280 BT_ASSERT_DBG(obj);
281 BT_ASSERT_DBG(obj->is_shared);
282 BT_ASSERT_DBG(obj->ref_count > 0);
e1e02a22 283
ef267d12
PP
284#ifdef BT_LOGT
285 BT_LOGT("Decrementing object's reference count: %llu -> %llu: "
e1e02a22
PP
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) {
98b15851 294 BT_ASSERT_DBG(obj->release_func);
e1e02a22
PP
295 obj->release_func(obj);
296 }
297}
298
299#endif /* BABELTRACE_CTF_WRITER_OBJECT_INTERNAL_H */
This page took 0.071931 seconds and 4 git commands to generate.