Commit | Line | Data |
---|---|---|
c9b3f44b | 1 | /* |
56e18c4c | 2 | * test_trace_ir_ref.c |
c9b3f44b | 3 | * |
56e18c4c | 4 | * Trace IR Reference Count test |
c9b3f44b JG |
5 | * |
6 | * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; under version 2 of the License. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along | |
18 | * with this program; if not, write to the Free Software Foundation, Inc., | |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
20 | */ | |
21 | ||
22 | #include "tap/tap.h" | |
e5be10ef | 23 | #include <babeltrace/babeltrace.h> |
c9b3f44b | 24 | #include <babeltrace/object-internal.h> |
3d9990ac | 25 | #include <babeltrace/compat/stdlib-internal.h> |
25583cd0 | 26 | #include <babeltrace/assert-internal.h> |
851299b9 | 27 | #include "common.h" |
c9b3f44b | 28 | |
44c440bc | 29 | #define NR_TESTS 37 |
8bbe269d | 30 | |
c9b3f44b | 31 | struct user { |
b19ff26f PP |
32 | bt_trace_class *tc; |
33 | bt_stream_class *sc; | |
34 | bt_event_class *ec; | |
35 | bt_stream *stream; | |
36 | bt_event *event; | |
c9b3f44b JG |
37 | }; |
38 | ||
3dca2276 PP |
39 | struct writer_user { |
40 | struct bt_ctf_writer *writer; | |
41 | struct bt_ctf_trace *tc; | |
42 | struct bt_ctf_stream_class *sc; | |
43 | struct bt_ctf_event_class *ec; | |
44 | struct bt_ctf_stream *stream; | |
45 | struct bt_ctf_event *event; | |
46 | }; | |
47 | ||
48 | const char *writer_user_names[] = { | |
6271743c PP |
49 | "writer", |
50 | "trace", | |
51 | "stream class", | |
52 | "event class", | |
53 | "stream", | |
54 | "event", | |
55 | }; | |
56 | ||
3dca2276 PP |
57 | static const size_t WRITER_USER_NR_ELEMENTS = |
58 | sizeof(struct writer_user) / sizeof(void *); | |
6271743c | 59 | |
c9b3f44b JG |
60 | /** |
61 | * Returns a structure containing the following fields: | |
62 | * - uint8_t payload_8; | |
63 | * - uint16_t payload_16; | |
64 | * - uint32_t payload_32; | |
65 | */ | |
1122a43a | 66 | static bt_field_class *create_integer_struct(bt_trace_class *trace_class) |
c9b3f44b JG |
67 | { |
68 | int ret; | |
b19ff26f PP |
69 | bt_field_class *structure = NULL; |
70 | bt_field_class *ui8 = NULL, *ui16 = NULL, *ui32 = NULL; | |
c9b3f44b | 71 | |
1122a43a | 72 | structure = bt_field_class_structure_create(trace_class); |
44c440bc | 73 | BT_ASSERT(structure); |
1122a43a | 74 | ui8 = bt_field_class_unsigned_integer_create(trace_class); |
44c440bc | 75 | BT_ASSERT(ui8); |
40f4ba76 PP |
76 | bt_field_class_integer_set_field_value_range(ui8, 8); |
77 | ret = bt_field_class_structure_append_member(structure, | |
44c440bc PP |
78 | "payload_8", ui8); |
79 | BT_ASSERT(ret == 0); | |
1122a43a | 80 | ui16 = bt_field_class_unsigned_integer_create(trace_class); |
44c440bc | 81 | BT_ASSERT(ui16); |
40f4ba76 PP |
82 | bt_field_class_integer_set_field_value_range(ui16, 16); |
83 | ret = bt_field_class_structure_append_member(structure, | |
44c440bc PP |
84 | "payload_16", ui16); |
85 | BT_ASSERT(ret == 0); | |
1122a43a | 86 | ui32 = bt_field_class_unsigned_integer_create(trace_class); |
44c440bc | 87 | BT_ASSERT(ui32); |
40f4ba76 PP |
88 | bt_field_class_integer_set_field_value_range(ui32, 32); |
89 | ret = bt_field_class_structure_append_member(structure, | |
44c440bc PP |
90 | "payload_32", ui32); |
91 | BT_ASSERT(ret == 0); | |
c5b9b441 PP |
92 | BT_FIELD_CLASS_PUT_REF_AND_RESET(ui8); |
93 | BT_FIELD_CLASS_PUT_REF_AND_RESET(ui16); | |
94 | BT_FIELD_CLASS_PUT_REF_AND_RESET(ui32); | |
c9b3f44b | 95 | return structure; |
c9b3f44b JG |
96 | } |
97 | ||
3dca2276 PP |
98 | static struct bt_ctf_field_type *create_writer_integer_struct(void) |
99 | { | |
100 | int ret; | |
101 | struct bt_ctf_field_type *structure = NULL; | |
102 | struct bt_ctf_field_type *ui8 = NULL, *ui16 = NULL, *ui32 = NULL; | |
103 | ||
104 | structure = bt_ctf_field_type_structure_create(); | |
44c440bc | 105 | BT_ASSERT(structure); |
3dca2276 | 106 | ui8 = bt_ctf_field_type_integer_create(8); |
44c440bc | 107 | BT_ASSERT(ui8); |
3dca2276 PP |
108 | ret = bt_ctf_field_type_structure_add_field(structure, ui8, |
109 | "payload_8"); | |
44c440bc | 110 | BT_ASSERT(ret == 0); |
3dca2276 | 111 | ui16 = bt_ctf_field_type_integer_create(16); |
44c440bc | 112 | BT_ASSERT(ui16); |
3dca2276 PP |
113 | ret = bt_ctf_field_type_structure_add_field(structure, ui16, |
114 | "payload_16"); | |
44c440bc | 115 | BT_ASSERT(ret == 0); |
3dca2276 | 116 | ui32 = bt_ctf_field_type_integer_create(32); |
44c440bc | 117 | BT_ASSERT(ui32); |
3dca2276 PP |
118 | ret = bt_ctf_field_type_structure_add_field(structure, ui32, |
119 | "payload_32"); | |
44c440bc | 120 | BT_ASSERT(ret == 0); |
65300d60 PP |
121 | BT_OBJECT_PUT_REF_AND_RESET(ui8); |
122 | BT_OBJECT_PUT_REF_AND_RESET(ui16); | |
123 | BT_OBJECT_PUT_REF_AND_RESET(ui32); | |
3dca2276 | 124 | return structure; |
3dca2276 PP |
125 | } |
126 | ||
c9b3f44b JG |
127 | /** |
128 | * A simple event has the following payload: | |
129 | * - uint8_t payload_8; | |
130 | * - uint16_t payload_16; | |
131 | * - uint32_t payload_32; | |
132 | */ | |
b19ff26f PP |
133 | static bt_event_class *create_simple_event( |
134 | bt_stream_class *sc, const char *name) | |
c9b3f44b JG |
135 | { |
136 | int ret; | |
b19ff26f PP |
137 | bt_event_class *event = NULL; |
138 | bt_field_class *payload = NULL; | |
c9b3f44b | 139 | |
25583cd0 | 140 | BT_ASSERT(name); |
40f4ba76 | 141 | event = bt_event_class_create(sc); |
44c440bc | 142 | BT_ASSERT(event); |
40f4ba76 | 143 | ret = bt_event_class_set_name(event, name); |
44c440bc | 144 | BT_ASSERT(ret == 0); |
1122a43a | 145 | payload = create_integer_struct(bt_stream_class_borrow_trace_class(sc)); |
44c440bc | 146 | BT_ASSERT(payload); |
40f4ba76 | 147 | ret = bt_event_class_set_payload_field_class(event, payload); |
44c440bc | 148 | BT_ASSERT(ret == 0); |
c5b9b441 | 149 | BT_FIELD_CLASS_PUT_REF_AND_RESET(payload); |
c9b3f44b | 150 | return event; |
c9b3f44b JG |
151 | } |
152 | ||
153 | /** | |
154 | * A complex event has the following payload: | |
155 | * - uint8_t payload_8; | |
156 | * - uint16_t payload_16; | |
157 | * - uint32_t payload_32; | |
158 | * - struct payload_struct: | |
159 | * - uint8_t payload_8; | |
160 | * - uint16_t payload_16; | |
161 | * - uint32_t payload_32; | |
162 | */ | |
1122a43a | 163 | static bt_event_class *create_complex_event(bt_stream_class *sc, |
44c440bc | 164 | const char *name) |
c9b3f44b JG |
165 | { |
166 | int ret; | |
b19ff26f PP |
167 | bt_event_class *event = NULL; |
168 | bt_field_class *inner = NULL, *outer = NULL; | |
1122a43a | 169 | bt_trace_class *trace_class = bt_stream_class_borrow_trace_class(sc); |
c9b3f44b | 170 | |
25583cd0 | 171 | BT_ASSERT(name); |
40f4ba76 | 172 | event = bt_event_class_create(sc); |
44c440bc | 173 | BT_ASSERT(event); |
40f4ba76 | 174 | ret = bt_event_class_set_name(event, name); |
44c440bc | 175 | BT_ASSERT(ret == 0); |
1122a43a | 176 | outer = create_integer_struct(trace_class); |
44c440bc | 177 | BT_ASSERT(outer); |
1122a43a | 178 | inner = create_integer_struct(trace_class); |
44c440bc | 179 | BT_ASSERT(inner); |
40f4ba76 | 180 | ret = bt_field_class_structure_append_member(outer, |
44c440bc PP |
181 | "payload_struct", inner); |
182 | BT_ASSERT(ret == 0); | |
40f4ba76 | 183 | ret = bt_event_class_set_payload_field_class(event, outer); |
44c440bc | 184 | BT_ASSERT(ret == 0); |
c5b9b441 PP |
185 | BT_FIELD_CLASS_PUT_REF_AND_RESET(inner); |
186 | BT_FIELD_CLASS_PUT_REF_AND_RESET(outer); | |
c9b3f44b | 187 | return event; |
c9b3f44b JG |
188 | } |
189 | ||
5cd6d0e5 | 190 | static void set_stream_class_field_classes( |
b19ff26f | 191 | bt_stream_class *stream_class) |
da1cc671 | 192 | { |
1122a43a PP |
193 | bt_trace_class *trace_class = |
194 | bt_stream_class_borrow_trace_class(stream_class); | |
b19ff26f PP |
195 | bt_field_class *packet_context_type; |
196 | bt_field_class *event_header_type; | |
197 | bt_field_class *fc; | |
da1cc671 PP |
198 | int ret; |
199 | ||
1122a43a | 200 | packet_context_type = bt_field_class_structure_create(trace_class); |
25583cd0 | 201 | BT_ASSERT(packet_context_type); |
1122a43a | 202 | fc = bt_field_class_unsigned_integer_create(trace_class); |
5cd6d0e5 | 203 | BT_ASSERT(fc); |
40f4ba76 PP |
204 | bt_field_class_integer_set_field_value_range(fc, 32); |
205 | ret = bt_field_class_structure_append_member(packet_context_type, | |
5cd6d0e5 | 206 | "packet_size", fc); |
25583cd0 | 207 | BT_ASSERT(ret == 0); |
c5b9b441 | 208 | bt_field_class_put_ref(fc); |
1122a43a | 209 | fc = bt_field_class_unsigned_integer_create(trace_class); |
5cd6d0e5 | 210 | BT_ASSERT(fc); |
40f4ba76 PP |
211 | bt_field_class_integer_set_field_value_range(fc, 32); |
212 | ret = bt_field_class_structure_append_member(packet_context_type, | |
5cd6d0e5 | 213 | "content_size", fc); |
25583cd0 | 214 | BT_ASSERT(ret == 0); |
c5b9b441 | 215 | bt_field_class_put_ref(fc); |
1122a43a | 216 | event_header_type = bt_field_class_structure_create(trace_class); |
25583cd0 | 217 | BT_ASSERT(event_header_type); |
1122a43a | 218 | fc = bt_field_class_unsigned_integer_create(trace_class); |
5cd6d0e5 | 219 | BT_ASSERT(fc); |
40f4ba76 PP |
220 | bt_field_class_integer_set_field_value_range(fc, 32); |
221 | ret = bt_field_class_structure_append_member(event_header_type, | |
5cd6d0e5 | 222 | "id", fc); |
25583cd0 | 223 | BT_ASSERT(ret == 0); |
c5b9b441 | 224 | bt_field_class_put_ref(fc); |
40f4ba76 | 225 | ret = bt_stream_class_set_packet_context_field_class( |
e5be10ef | 226 | stream_class, packet_context_type); |
25583cd0 | 227 | BT_ASSERT(ret == 0); |
40f4ba76 | 228 | ret = bt_stream_class_set_event_header_field_class( |
e5be10ef | 229 | stream_class, event_header_type); |
25583cd0 | 230 | BT_ASSERT(ret == 0); |
c5b9b441 PP |
231 | bt_field_class_put_ref(packet_context_type); |
232 | bt_field_class_put_ref(event_header_type); | |
da1cc671 PP |
233 | } |
234 | ||
b19ff26f | 235 | static void create_sc1(bt_trace_class *trace_class) |
c9b3f44b JG |
236 | { |
237 | int ret; | |
b19ff26f PP |
238 | bt_event_class *ec1 = NULL, *ec2 = NULL; |
239 | bt_stream_class *sc1 = NULL, *ret_stream = NULL; | |
c9b3f44b | 240 | |
862ca4ed | 241 | sc1 = bt_stream_class_create(trace_class); |
44c440bc | 242 | BT_ASSERT(sc1); |
40f4ba76 | 243 | ret = bt_stream_class_set_name(sc1, "sc1"); |
44c440bc | 244 | BT_ASSERT(ret == 0); |
5cd6d0e5 | 245 | set_stream_class_field_classes(sc1); |
44c440bc PP |
246 | ec1 = create_complex_event(sc1, "ec1"); |
247 | BT_ASSERT(ec1); | |
248 | ec2 = create_simple_event(sc1, "ec2"); | |
249 | BT_ASSERT(ec2); | |
40f4ba76 | 250 | ret_stream = bt_event_class_borrow_stream_class(ec1); |
44c440bc | 251 | ok(ret_stream == sc1, "Borrow parent stream SC1 from EC1"); |
40f4ba76 | 252 | ret_stream = bt_event_class_borrow_stream_class(ec2); |
44c440bc | 253 | ok(ret_stream == sc1, "Borrow parent stream SC1 from EC2"); |
c5b9b441 PP |
254 | BT_EVENT_CLASS_PUT_REF_AND_RESET(ec1); |
255 | BT_EVENT_CLASS_PUT_REF_AND_RESET(ec2); | |
256 | BT_STREAM_CLASS_PUT_REF_AND_RESET(sc1); | |
c9b3f44b JG |
257 | } |
258 | ||
b19ff26f | 259 | static void create_sc2(bt_trace_class *trace_class) |
c9b3f44b JG |
260 | { |
261 | int ret; | |
b19ff26f PP |
262 | bt_event_class *ec3 = NULL; |
263 | bt_stream_class *sc2 = NULL, *ret_stream = NULL; | |
c9b3f44b | 264 | |
862ca4ed | 265 | sc2 = bt_stream_class_create(trace_class); |
44c440bc | 266 | BT_ASSERT(sc2); |
40f4ba76 | 267 | ret = bt_stream_class_set_name(sc2, "sc2"); |
44c440bc | 268 | BT_ASSERT(ret == 0); |
5cd6d0e5 | 269 | set_stream_class_field_classes(sc2); |
44c440bc | 270 | ec3 = create_simple_event(sc2, "ec3"); |
40f4ba76 | 271 | ret_stream = bt_event_class_borrow_stream_class(ec3); |
44c440bc | 272 | ok(ret_stream == sc2, "Borrow parent stream SC2 from EC3"); |
c5b9b441 PP |
273 | BT_EVENT_CLASS_PUT_REF_AND_RESET(ec3); |
274 | BT_STREAM_CLASS_PUT_REF_AND_RESET(sc2); | |
c9b3f44b JG |
275 | } |
276 | ||
b19ff26f | 277 | static void set_trace_packet_header(bt_trace_class *trace_class) |
da1cc671 | 278 | { |
b19ff26f PP |
279 | bt_field_class *packet_header_type; |
280 | bt_field_class *fc; | |
da1cc671 PP |
281 | int ret; |
282 | ||
1122a43a | 283 | packet_header_type = bt_field_class_structure_create(trace_class); |
25583cd0 | 284 | BT_ASSERT(packet_header_type); |
1122a43a | 285 | fc = bt_field_class_unsigned_integer_create(trace_class); |
5cd6d0e5 | 286 | BT_ASSERT(fc); |
40f4ba76 PP |
287 | bt_field_class_integer_set_field_value_range(fc, 32); |
288 | ret = bt_field_class_structure_append_member(packet_header_type, | |
5cd6d0e5 | 289 | "stream_id", fc); |
25583cd0 | 290 | BT_ASSERT(ret == 0); |
c5b9b441 | 291 | bt_field_class_put_ref(fc); |
862ca4ed | 292 | ret = bt_trace_class_set_packet_header_field_class(trace_class, |
da1cc671 | 293 | packet_header_type); |
25583cd0 | 294 | BT_ASSERT(ret == 0); |
da1cc671 | 295 | |
c5b9b441 | 296 | bt_field_class_put_ref(packet_header_type); |
da1cc671 PP |
297 | } |
298 | ||
41693723 | 299 | static bt_trace_class *create_tc1(bt_self_component_source *self_comp) |
c9b3f44b | 300 | { |
b19ff26f | 301 | bt_trace_class *tc1 = NULL; |
c9b3f44b | 302 | |
41693723 PP |
303 | tc1 = bt_trace_class_create( |
304 | bt_self_component_source_as_self_component(self_comp)); | |
44c440bc | 305 | BT_ASSERT(tc1); |
da1cc671 | 306 | set_trace_packet_header(tc1); |
44c440bc PP |
307 | create_sc1(tc1); |
308 | create_sc2(tc1); | |
c9b3f44b | 309 | return tc1; |
c9b3f44b JG |
310 | } |
311 | ||
b19ff26f PP |
312 | static void init_weak_refs(bt_trace_class *tc, |
313 | bt_trace_class **tc1, | |
314 | bt_stream_class **sc1, | |
315 | bt_stream_class **sc2, | |
316 | bt_event_class **ec1, | |
317 | bt_event_class **ec2, | |
318 | bt_event_class **ec3) | |
c9b3f44b JG |
319 | { |
320 | *tc1 = tc; | |
862ca4ed PP |
321 | *sc1 = bt_trace_class_borrow_stream_class_by_index(tc, 0); |
322 | *sc2 = bt_trace_class_borrow_stream_class_by_index(tc, 1); | |
40f4ba76 PP |
323 | *ec1 = bt_stream_class_borrow_event_class_by_index(*sc1, 0); |
324 | *ec2 = bt_stream_class_borrow_event_class_by_index(*sc1, 1); | |
325 | *ec3 = bt_stream_class_borrow_event_class_by_index(*sc2, 0); | |
c9b3f44b JG |
326 | } |
327 | ||
41693723 | 328 | static void test_example_scenario(bt_self_component_source *self_comp) |
c9b3f44b | 329 | { |
56e18c4c PP |
330 | /* |
331 | * Weak pointers to trace IR objects are to be used very | |
332 | * carefully. This is NOT a good practice and is strongly | |
333 | * discouraged; this is only done to facilitate the validation | |
334 | * of expected reference counts without affecting them by taking | |
335 | * "real" references to the objects. | |
c9b3f44b | 336 | */ |
b19ff26f PP |
337 | bt_trace_class *tc1 = NULL, *weak_tc1 = NULL; |
338 | bt_stream_class *weak_sc1 = NULL, *weak_sc2 = NULL; | |
339 | bt_event_class *weak_ec1 = NULL, *weak_ec2 = NULL, | |
c9b3f44b JG |
340 | *weak_ec3 = NULL; |
341 | struct user user_a = { 0 }, user_b = { 0 }, user_c = { 0 }; | |
342 | ||
343 | /* The only reference which exists at this point is on TC1. */ | |
41693723 | 344 | tc1 = create_tc1(self_comp); |
27f4d205 | 345 | ok(tc1, "Initialize trace"); |
44c440bc | 346 | BT_ASSERT(tc1); |
c9b3f44b JG |
347 | init_weak_refs(tc1, &weak_tc1, &weak_sc1, &weak_sc2, &weak_ec1, |
348 | &weak_ec2, &weak_ec3); | |
3fea54f6 | 349 | ok(bt_object_get_ref_count((void *) weak_sc1) == 0, |
c9b3f44b | 350 | "Initial SC1 reference count is 0"); |
3fea54f6 | 351 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 352 | "Initial SC2 reference count is 0"); |
3fea54f6 | 353 | ok(bt_object_get_ref_count((void *) weak_ec1) == 0, |
c9b3f44b | 354 | "Initial EC1 reference count is 0"); |
3fea54f6 | 355 | ok(bt_object_get_ref_count((void *) weak_ec2) == 0, |
c9b3f44b | 356 | "Initial EC2 reference count is 0"); |
3fea54f6 | 357 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b JG |
358 | "Initial EC3 reference count is 0"); |
359 | ||
360 | /* User A has ownership of the trace. */ | |
65300d60 | 361 | BT_OBJECT_MOVE_REF(user_a.tc, tc1); |
3fea54f6 | 362 | ok(bt_object_get_ref_count((void *) user_a.tc) == 1, |
c9b3f44b JG |
363 | "TC1 reference count is 1"); |
364 | ||
365 | /* User A acquires a reference to SC2 from TC1. */ | |
862ca4ed | 366 | user_a.sc = bt_trace_class_borrow_stream_class_by_index( |
398454ed | 367 | user_a.tc, 1); |
c5b9b441 | 368 | bt_stream_class_get_ref(user_a.sc); |
c9b3f44b | 369 | ok(user_a.sc, "User A acquires SC2 from TC1"); |
3fea54f6 | 370 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 371 | "TC1 reference count is 2"); |
3fea54f6 | 372 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b JG |
373 | "SC2 reference count is 1"); |
374 | ||
375 | /* User A acquires a reference to EC3 from SC2. */ | |
40f4ba76 | 376 | user_a.ec = bt_stream_class_borrow_event_class_by_index( |
398454ed | 377 | user_a.sc, 0); |
c5b9b441 | 378 | bt_event_class_get_ref(user_a.ec); |
c9b3f44b | 379 | ok(user_a.ec, "User A acquires EC3 from SC2"); |
3fea54f6 | 380 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 381 | "TC1 reference count is 2"); |
3fea54f6 | 382 | ok(bt_object_get_ref_count((void *) weak_sc2) == 2, |
c9b3f44b | 383 | "SC2 reference count is 2"); |
3fea54f6 | 384 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
385 | "EC3 reference count is 1"); |
386 | ||
387 | /* User A releases its reference to SC2. */ | |
388 | diag("User A releases SC2"); | |
c5b9b441 | 389 | BT_STREAM_CLASS_PUT_REF_AND_RESET(user_a.sc); |
c9b3f44b JG |
390 | /* |
391 | * We keep the pointer to SC2 around to validate its reference | |
392 | * count. | |
393 | */ | |
3fea54f6 | 394 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 395 | "TC1 reference count is 2"); |
3fea54f6 | 396 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b | 397 | "SC2 reference count is 1"); |
3fea54f6 | 398 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
399 | "EC3 reference count is 1"); |
400 | ||
401 | /* User A releases its reference to TC1. */ | |
402 | diag("User A releases TC1"); | |
c5b9b441 | 403 | BT_TRACE_CLASS_PUT_REF_AND_RESET(user_a.tc); |
c9b3f44b JG |
404 | /* |
405 | * We keep the pointer to TC1 around to validate its reference | |
406 | * count. | |
407 | */ | |
3fea54f6 | 408 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b | 409 | "TC1 reference count is 1"); |
3fea54f6 | 410 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b | 411 | "SC2 reference count is 1"); |
3fea54f6 | 412 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
413 | "EC3 reference count is 1"); |
414 | ||
415 | /* User B acquires a reference to SC1. */ | |
416 | diag("User B acquires a reference to SC1"); | |
398454ed | 417 | user_b.sc = weak_sc1; |
c5b9b441 | 418 | bt_stream_class_get_ref(user_b.sc); |
3fea54f6 | 419 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 420 | "TC1 reference count is 2"); |
3fea54f6 | 421 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b JG |
422 | "SC1 reference count is 1"); |
423 | ||
424 | /* User C acquires a reference to EC1. */ | |
425 | diag("User C acquires a reference to EC1"); | |
40f4ba76 | 426 | user_c.ec = bt_stream_class_borrow_event_class_by_index( |
398454ed | 427 | user_b.sc, 0); |
c5b9b441 | 428 | bt_event_class_get_ref(user_c.ec); |
3fea54f6 | 429 | ok(bt_object_get_ref_count((void *) weak_ec1) == 1, |
c9b3f44b | 430 | "EC1 reference count is 1"); |
3fea54f6 | 431 | ok(bt_object_get_ref_count((void *) weak_sc1) == 2, |
c9b3f44b JG |
432 | "SC1 reference count is 2"); |
433 | ||
434 | /* User A releases its reference on EC3. */ | |
435 | diag("User A releases its reference on EC3"); | |
c5b9b441 | 436 | BT_EVENT_CLASS_PUT_REF_AND_RESET(user_a.ec); |
3fea54f6 | 437 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b | 438 | "EC3 reference count is 1"); |
3fea54f6 | 439 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 440 | "SC2 reference count is 0"); |
3fea54f6 | 441 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b JG |
442 | "TC1 reference count is 1"); |
443 | ||
444 | /* User B releases its reference on SC1. */ | |
445 | diag("User B releases its reference on SC1"); | |
c5b9b441 | 446 | BT_STREAM_CLASS_PUT_REF_AND_RESET(user_b.sc); |
3fea54f6 | 447 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b JG |
448 | "SC1 reference count is 1"); |
449 | ||
450 | /* | |
451 | * User C is the sole owner of an object and is keeping the whole | |
452 | * trace hierarchy "alive" by holding a reference to EC1. | |
453 | */ | |
3fea54f6 | 454 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b | 455 | "TC1 reference count is 1"); |
3fea54f6 | 456 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b | 457 | "SC1 reference count is 1"); |
3fea54f6 | 458 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 459 | "SC2 reference count is 0"); |
3fea54f6 | 460 | ok(bt_object_get_ref_count((void *) weak_ec1) == 1, |
c9b3f44b | 461 | "EC1 reference count is 1"); |
3fea54f6 | 462 | ok(bt_object_get_ref_count((void *) weak_ec2) == 0, |
c9b3f44b | 463 | "EC2 reference count is 0"); |
3fea54f6 | 464 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b JG |
465 | "EC3 reference count is 0"); |
466 | ||
467 | /* Reclaim last reference held by User C. */ | |
c5b9b441 | 468 | BT_EVENT_CLASS_PUT_REF_AND_RESET(user_c.ec); |
6271743c PP |
469 | } |
470 | ||
41693723 PP |
471 | static |
472 | bt_self_component_status src_init( | |
473 | bt_self_component_source *self_comp, | |
474 | const bt_value *params, void *init_method_data) | |
475 | { | |
476 | test_example_scenario(self_comp); | |
477 | return BT_SELF_COMPONENT_STATUS_OK; | |
478 | } | |
479 | ||
480 | static | |
481 | bt_self_message_iterator_status src_iter_next( | |
482 | bt_self_message_iterator *self_iterator, | |
483 | bt_message_array_const msgs, uint64_t capacity, | |
484 | uint64_t *count) | |
485 | { | |
486 | return BT_SELF_MESSAGE_ITERATOR_STATUS_ERROR; | |
487 | } | |
488 | ||
489 | static void test_example_scenario_in_graph(void) | |
490 | { | |
491 | bt_component_class_source *comp_cls; | |
492 | bt_graph *graph; | |
493 | int ret; | |
494 | ||
495 | comp_cls = bt_component_class_source_create("src", src_iter_next); | |
496 | BT_ASSERT(comp_cls); | |
497 | ret = bt_component_class_source_set_init_method(comp_cls, src_init); | |
498 | BT_ASSERT(ret == 0); | |
499 | graph = bt_graph_create(); | |
500 | ret = bt_graph_add_source_component(graph, comp_cls, "src-comp", | |
501 | NULL, NULL); | |
502 | BT_ASSERT(ret == 0); | |
503 | bt_graph_put_ref(graph); | |
504 | bt_component_class_source_put_ref(comp_cls); | |
505 | } | |
506 | ||
3dca2276 | 507 | static void create_writer_user_full(struct writer_user *user) |
6271743c | 508 | { |
32bd47d1 | 509 | gchar *trace_path; |
3dca2276 PP |
510 | struct bt_ctf_field_type *ft; |
511 | struct bt_ctf_field *field; | |
6271743c PP |
512 | struct bt_ctf_clock *clock; |
513 | int ret; | |
514 | ||
32bd47d1 | 515 | trace_path = g_build_filename(g_get_tmp_dir(), "ctfwriter_XXXXXX", NULL); |
6271743c PP |
516 | if (!bt_mkdtemp(trace_path)) { |
517 | perror("# perror"); | |
518 | } | |
519 | ||
520 | user->writer = bt_ctf_writer_create(trace_path); | |
25583cd0 | 521 | BT_ASSERT(user->writer); |
dc3fffef | 522 | ret = bt_ctf_writer_set_byte_order(user->writer, |
3dca2276 | 523 | BT_CTF_BYTE_ORDER_LITTLE_ENDIAN); |
25583cd0 | 524 | BT_ASSERT(ret == 0); |
6271743c | 525 | user->tc = bt_ctf_writer_get_trace(user->writer); |
25583cd0 | 526 | BT_ASSERT(user->tc); |
3dca2276 | 527 | user->sc = bt_ctf_stream_class_create("sc"); |
25583cd0 | 528 | BT_ASSERT(user->sc); |
6271743c | 529 | clock = bt_ctf_clock_create("the_clock"); |
25583cd0 | 530 | BT_ASSERT(clock); |
81582b6b | 531 | ret = bt_ctf_writer_add_clock(user->writer, clock); |
25583cd0 | 532 | BT_ASSERT(!ret); |
3dca2276 | 533 | ret = bt_ctf_stream_class_set_clock(user->sc, clock); |
25583cd0 | 534 | BT_ASSERT(!ret); |
65300d60 | 535 | BT_OBJECT_PUT_REF_AND_RESET(clock); |
6271743c | 536 | user->stream = bt_ctf_writer_create_stream(user->writer, user->sc); |
25583cd0 | 537 | BT_ASSERT(user->stream); |
3dca2276 | 538 | user->ec = bt_ctf_event_class_create("ec"); |
25583cd0 | 539 | BT_ASSERT(user->ec); |
3dca2276 | 540 | ft = create_writer_integer_struct(); |
25583cd0 | 541 | BT_ASSERT(ft); |
3dca2276 | 542 | ret = bt_ctf_event_class_set_payload_field_type(user->ec, ft); |
65300d60 | 543 | BT_OBJECT_PUT_REF_AND_RESET(ft); |
25583cd0 | 544 | BT_ASSERT(!ret); |
3dca2276 | 545 | ret = bt_ctf_stream_class_add_event_class(user->sc, user->ec); |
25583cd0 | 546 | BT_ASSERT(!ret); |
3dca2276 | 547 | user->event = bt_ctf_event_create(user->ec); |
25583cd0 | 548 | BT_ASSERT(user->event); |
3dca2276 | 549 | field = bt_ctf_event_get_payload(user->event, "payload_8"); |
25583cd0 | 550 | BT_ASSERT(field); |
3dca2276 | 551 | ret = bt_ctf_field_integer_unsigned_set_value(field, 10); |
25583cd0 | 552 | BT_ASSERT(!ret); |
65300d60 | 553 | BT_OBJECT_PUT_REF_AND_RESET(field); |
3dca2276 | 554 | field = bt_ctf_event_get_payload(user->event, "payload_16"); |
25583cd0 | 555 | BT_ASSERT(field); |
3dca2276 | 556 | ret = bt_ctf_field_integer_unsigned_set_value(field, 20); |
25583cd0 | 557 | BT_ASSERT(!ret); |
65300d60 | 558 | BT_OBJECT_PUT_REF_AND_RESET(field); |
3dca2276 | 559 | field = bt_ctf_event_get_payload(user->event, "payload_32"); |
25583cd0 | 560 | BT_ASSERT(field); |
3dca2276 | 561 | ret = bt_ctf_field_integer_unsigned_set_value(field, 30); |
25583cd0 | 562 | BT_ASSERT(!ret); |
65300d60 | 563 | BT_OBJECT_PUT_REF_AND_RESET(field); |
3dca2276 | 564 | ret = bt_ctf_stream_append_event(user->stream, user->event); |
25583cd0 | 565 | BT_ASSERT(!ret); |
851299b9 | 566 | recursive_rmdir(trace_path); |
32bd47d1 | 567 | g_free(trace_path); |
6271743c PP |
568 | } |
569 | ||
570 | static void test_put_order_swap(size_t *array, size_t a, size_t b) | |
571 | { | |
572 | size_t temp = array[a]; | |
573 | ||
574 | array[a] = array[b]; | |
575 | array[b] = temp; | |
576 | } | |
577 | ||
578 | static void test_put_order_put_objects(size_t *array, size_t size) | |
579 | { | |
580 | size_t i; | |
3dca2276 | 581 | struct writer_user user = { 0 }; |
6f2097e2 | 582 | void **objects = (void *) &user; |
6271743c | 583 | |
3dca2276 | 584 | create_writer_user_full(&user); |
6271743c PP |
585 | printf("# "); |
586 | ||
587 | for (i = 0; i < size; ++i) { | |
6f2097e2 | 588 | void *obj = objects[array[i]]; |
6271743c | 589 | |
3dca2276 | 590 | printf("%s", writer_user_names[array[i]]); |
65300d60 | 591 | BT_OBJECT_PUT_REF_AND_RESET(obj); |
6271743c PP |
592 | |
593 | if (i < size - 1) { | |
594 | printf(" -> "); | |
595 | } | |
596 | } | |
597 | ||
598 | puts(""); | |
599 | } | |
600 | ||
601 | static void test_put_order_permute(size_t *array, int k, size_t size) | |
602 | { | |
603 | if (k == 0) { | |
604 | test_put_order_put_objects(array, size); | |
605 | } else { | |
606 | int i; | |
607 | ||
608 | for (i = k - 1; i >= 0; i--) { | |
609 | size_t next_k = k - 1; | |
610 | ||
611 | test_put_order_swap(array, i, next_k); | |
612 | test_put_order_permute(array, next_k, size); | |
613 | test_put_order_swap(array, i, next_k); | |
614 | } | |
615 | } | |
616 | } | |
617 | ||
618 | static void test_put_order(void) | |
619 | { | |
620 | size_t i; | |
3dca2276 | 621 | size_t array[WRITER_USER_NR_ELEMENTS]; |
6271743c PP |
622 | |
623 | /* Initialize array of indexes */ | |
3dca2276 | 624 | for (i = 0; i < WRITER_USER_NR_ELEMENTS; ++i) { |
6271743c PP |
625 | array[i] = i; |
626 | } | |
627 | ||
3dca2276 PP |
628 | test_put_order_permute(array, WRITER_USER_NR_ELEMENTS, |
629 | WRITER_USER_NR_ELEMENTS); | |
6271743c PP |
630 | } |
631 | ||
632 | /** | |
633 | * The objective of this test is to implement and expand upon the scenario | |
634 | * described in the reference counting documentation and ensure that any node of | |
635 | * the Trace, Stream Class, Event Class, Stream and Event hiearchy keeps all | |
636 | * other "alive" and reachable. | |
637 | * | |
638 | * External tools (e.g. valgrind) should be used to confirm that this | |
639 | * known-good test does not leak memory. | |
640 | */ | |
641 | int main(int argc, char **argv) | |
642 | { | |
27f4d205 | 643 | /* Initialize tap harness before any tests */ |
6271743c PP |
644 | plan_tests(NR_TESTS); |
645 | ||
41693723 | 646 | test_example_scenario_in_graph(); |
6271743c PP |
647 | test_put_order(); |
648 | ||
c9b3f44b JG |
649 | return exit_status(); |
650 | } |