Commit | Line | Data |
---|---|---|
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 | ||
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 | { | |
98b15851 PP |
76 | BT_ASSERT_DBG(obj); |
77 | BT_ASSERT_DBG(obj->is_shared); | |
e1e02a22 PP |
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 | { | |
98b15851 PP |
84 | BT_ASSERT_DBG(obj); |
85 | BT_ASSERT_DBG(obj->is_shared); | |
e1e02a22 PP |
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 | { | |
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 | ||
131 | static inline | |
132 | void 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 | ||
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 | ||
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 | ||
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 | { | |
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 | ||
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 | { | |
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 | ||
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 | { | |
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 | ||
225 | static inline | |
226 | void 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 | ||
234 | static inline | |
235 | void *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 | ||
251 | static inline | |
252 | void *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 | ||
277 | static inline | |
278 | void 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 */ |