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