Commit | Line | Data |
---|---|---|
c9b3f44b JG |
1 | /* |
2 | * test_ctf_ir_ref.c | |
3 | * | |
4 | * CTF IR Reference Count test | |
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" | |
6271743c | 23 | #include <babeltrace/ctf-writer/clock.h> |
3dca2276 PP |
24 | #include <babeltrace/ctf-writer/event.h> |
25 | #include <babeltrace/ctf-writer/fields.h> | |
6271743c | 26 | #include <babeltrace/ctf-writer/stream-class.h> |
3dca2276 PP |
27 | #include <babeltrace/ctf-writer/stream.h> |
28 | #include <babeltrace/ctf-writer/trace.h> | |
29 | #include <babeltrace/ctf-writer/writer.h> | |
30 | #include <babeltrace/ctf-ir/clock-class.h> | |
c9b3f44b | 31 | #include <babeltrace/ctf-ir/event.h> |
272df73e | 32 | #include <babeltrace/ctf-ir/event-class.h> |
3dca2276 PP |
33 | #include <babeltrace/ctf-ir/fields.h> |
34 | #include <babeltrace/ctf-ir/stream-class.h> | |
35 | #include <babeltrace/ctf-ir/stream.h> | |
36 | #include <babeltrace/ctf-ir/trace.h> | |
c9b3f44b | 37 | #include <babeltrace/object-internal.h> |
3d9990ac | 38 | #include <babeltrace/compat/stdlib-internal.h> |
25583cd0 | 39 | #include <babeltrace/assert-internal.h> |
851299b9 | 40 | #include "common.h" |
c9b3f44b | 41 | |
8bbe269d MJ |
42 | #define NR_TESTS 41 |
43 | ||
c9b3f44b | 44 | struct user { |
50842bdc PP |
45 | struct bt_trace *tc; |
46 | struct bt_stream_class *sc; | |
47 | struct bt_event_class *ec; | |
48 | struct bt_stream *stream; | |
49 | struct bt_event *event; | |
c9b3f44b JG |
50 | }; |
51 | ||
3dca2276 PP |
52 | struct writer_user { |
53 | struct bt_ctf_writer *writer; | |
54 | struct bt_ctf_trace *tc; | |
55 | struct bt_ctf_stream_class *sc; | |
56 | struct bt_ctf_event_class *ec; | |
57 | struct bt_ctf_stream *stream; | |
58 | struct bt_ctf_event *event; | |
59 | }; | |
60 | ||
61 | const char *writer_user_names[] = { | |
6271743c PP |
62 | "writer", |
63 | "trace", | |
64 | "stream class", | |
65 | "event class", | |
66 | "stream", | |
67 | "event", | |
68 | }; | |
69 | ||
3dca2276 PP |
70 | static const size_t WRITER_USER_NR_ELEMENTS = |
71 | sizeof(struct writer_user) / sizeof(void *); | |
6271743c | 72 | |
c9b3f44b JG |
73 | /** |
74 | * Returns a structure containing the following fields: | |
75 | * - uint8_t payload_8; | |
76 | * - uint16_t payload_16; | |
77 | * - uint32_t payload_32; | |
78 | */ | |
50842bdc | 79 | static struct bt_field_type *create_integer_struct(void) |
c9b3f44b JG |
80 | { |
81 | int ret; | |
50842bdc PP |
82 | struct bt_field_type *structure = NULL; |
83 | struct bt_field_type *ui8 = NULL, *ui16 = NULL, *ui32 = NULL; | |
c9b3f44b | 84 | |
50842bdc | 85 | structure = bt_field_type_structure_create(); |
c9b3f44b JG |
86 | if (!structure) { |
87 | goto error; | |
88 | } | |
89 | ||
50842bdc | 90 | ui8 = bt_field_type_integer_create(8); |
c9b3f44b JG |
91 | if (!ui8) { |
92 | diag("Failed to create uint8_t type"); | |
93 | goto error; | |
94 | } | |
50842bdc | 95 | ret = bt_field_type_structure_add_field(structure, ui8, |
c9b3f44b JG |
96 | "payload_8"); |
97 | if (ret) { | |
98 | diag("Failed to add uint8_t to structure"); | |
99 | goto error; | |
100 | } | |
50842bdc | 101 | ui16 = bt_field_type_integer_create(16); |
c9b3f44b JG |
102 | if (!ui16) { |
103 | diag("Failed to create uint16_t type"); | |
104 | goto error; | |
105 | } | |
50842bdc | 106 | ret = bt_field_type_structure_add_field(structure, ui16, |
c9b3f44b JG |
107 | "payload_16"); |
108 | if (ret) { | |
109 | diag("Failed to add uint16_t to structure"); | |
110 | goto error; | |
111 | } | |
50842bdc | 112 | ui32 = bt_field_type_integer_create(32); |
c9b3f44b JG |
113 | if (!ui32) { |
114 | diag("Failed to create uint32_t type"); | |
115 | goto error; | |
116 | } | |
50842bdc | 117 | ret = bt_field_type_structure_add_field(structure, ui32, |
c9b3f44b JG |
118 | "payload_32"); |
119 | if (ret) { | |
120 | diag("Failed to add uint32_t to structure"); | |
121 | goto error; | |
122 | } | |
123 | end: | |
124 | BT_PUT(ui8); | |
125 | BT_PUT(ui16); | |
126 | BT_PUT(ui32); | |
127 | return structure; | |
128 | error: | |
129 | BT_PUT(structure); | |
130 | goto end; | |
131 | } | |
132 | ||
3dca2276 PP |
133 | static struct bt_ctf_field_type *create_writer_integer_struct(void) |
134 | { | |
135 | int ret; | |
136 | struct bt_ctf_field_type *structure = NULL; | |
137 | struct bt_ctf_field_type *ui8 = NULL, *ui16 = NULL, *ui32 = NULL; | |
138 | ||
139 | structure = bt_ctf_field_type_structure_create(); | |
140 | if (!structure) { | |
141 | goto error; | |
142 | } | |
143 | ||
144 | ui8 = bt_ctf_field_type_integer_create(8); | |
145 | if (!ui8) { | |
146 | diag("Failed to create uint8_t type"); | |
147 | goto error; | |
148 | } | |
149 | ret = bt_ctf_field_type_structure_add_field(structure, ui8, | |
150 | "payload_8"); | |
151 | if (ret) { | |
152 | diag("Failed to add uint8_t to structure"); | |
153 | goto error; | |
154 | } | |
155 | ui16 = bt_ctf_field_type_integer_create(16); | |
156 | if (!ui16) { | |
157 | diag("Failed to create uint16_t type"); | |
158 | goto error; | |
159 | } | |
160 | ret = bt_ctf_field_type_structure_add_field(structure, ui16, | |
161 | "payload_16"); | |
162 | if (ret) { | |
163 | diag("Failed to add uint16_t to structure"); | |
164 | goto error; | |
165 | } | |
166 | ui32 = bt_ctf_field_type_integer_create(32); | |
167 | if (!ui32) { | |
168 | diag("Failed to create uint32_t type"); | |
169 | goto error; | |
170 | } | |
171 | ret = bt_ctf_field_type_structure_add_field(structure, ui32, | |
172 | "payload_32"); | |
173 | if (ret) { | |
174 | diag("Failed to add uint32_t to structure"); | |
175 | goto error; | |
176 | } | |
177 | end: | |
178 | BT_PUT(ui8); | |
179 | BT_PUT(ui16); | |
180 | BT_PUT(ui32); | |
181 | return structure; | |
182 | error: | |
183 | BT_PUT(structure); | |
184 | goto end; | |
185 | } | |
186 | ||
c9b3f44b JG |
187 | /** |
188 | * A simple event has the following payload: | |
189 | * - uint8_t payload_8; | |
190 | * - uint16_t payload_16; | |
191 | * - uint32_t payload_32; | |
192 | */ | |
50842bdc | 193 | static struct bt_event_class *create_simple_event(const char *name) |
c9b3f44b JG |
194 | { |
195 | int ret; | |
50842bdc PP |
196 | struct bt_event_class *event = NULL; |
197 | struct bt_field_type *payload = NULL; | |
c9b3f44b | 198 | |
25583cd0 | 199 | BT_ASSERT(name); |
50842bdc | 200 | event = bt_event_class_create(name); |
c9b3f44b JG |
201 | if (!event) { |
202 | diag("Failed to create simple event"); | |
203 | goto error; | |
204 | } | |
205 | ||
206 | payload = create_integer_struct(); | |
207 | if (!payload) { | |
208 | diag("Failed to initialize integer structure"); | |
209 | goto error; | |
210 | } | |
211 | ||
3dca2276 | 212 | ret = bt_event_class_set_payload_field_type(event, payload); |
c9b3f44b JG |
213 | if (ret) { |
214 | diag("Failed to set simple event payload"); | |
215 | goto error; | |
216 | } | |
217 | end: | |
218 | BT_PUT(payload); | |
219 | return event; | |
220 | error: | |
221 | BT_PUT(event); | |
222 | goto end;; | |
223 | } | |
224 | ||
225 | /** | |
226 | * A complex event has the following payload: | |
227 | * - uint8_t payload_8; | |
228 | * - uint16_t payload_16; | |
229 | * - uint32_t payload_32; | |
230 | * - struct payload_struct: | |
231 | * - uint8_t payload_8; | |
232 | * - uint16_t payload_16; | |
233 | * - uint32_t payload_32; | |
234 | */ | |
50842bdc | 235 | static struct bt_event_class *create_complex_event(const char *name) |
c9b3f44b JG |
236 | { |
237 | int ret; | |
50842bdc PP |
238 | struct bt_event_class *event = NULL; |
239 | struct bt_field_type *inner = NULL, *outer = NULL; | |
c9b3f44b | 240 | |
25583cd0 | 241 | BT_ASSERT(name); |
50842bdc | 242 | event = bt_event_class_create(name); |
c9b3f44b JG |
243 | if (!event) { |
244 | diag("Failed to create complex event"); | |
245 | goto error; | |
246 | } | |
247 | ||
27f4d205 | 248 | outer = create_integer_struct(); |
c9b3f44b JG |
249 | if (!outer) { |
250 | diag("Failed to initialize integer structure"); | |
251 | goto error; | |
252 | } | |
253 | ||
27f4d205 | 254 | inner = create_integer_struct(); |
c9b3f44b JG |
255 | if (!inner) { |
256 | diag("Failed to initialize integer structure"); | |
257 | goto error; | |
258 | } | |
259 | ||
50842bdc | 260 | ret = bt_field_type_structure_add_field(outer, inner, |
27f4d205 | 261 | "payload_struct"); |
c9b3f44b JG |
262 | if (ret) { |
263 | diag("Failed to add inner structure to outer structure"); | |
264 | goto error; | |
265 | } | |
266 | ||
3dca2276 | 267 | ret = bt_event_class_set_payload_field_type(event, outer); |
c9b3f44b JG |
268 | if (ret) { |
269 | diag("Failed to set complex event payload"); | |
270 | goto error; | |
271 | } | |
272 | end: | |
273 | BT_PUT(inner); | |
274 | BT_PUT(outer); | |
275 | return event; | |
276 | error: | |
277 | BT_PUT(event); | |
278 | goto end;; | |
279 | } | |
280 | ||
da1cc671 | 281 | static void set_stream_class_field_types( |
50842bdc | 282 | struct bt_stream_class *stream_class) |
da1cc671 | 283 | { |
50842bdc PP |
284 | struct bt_field_type *packet_context_type; |
285 | struct bt_field_type *event_header_type; | |
286 | struct bt_field_type *ft; | |
da1cc671 PP |
287 | int ret; |
288 | ||
50842bdc | 289 | packet_context_type = bt_field_type_structure_create(); |
25583cd0 | 290 | BT_ASSERT(packet_context_type); |
50842bdc | 291 | ft = bt_field_type_integer_create(32); |
25583cd0 | 292 | BT_ASSERT(ft); |
50842bdc | 293 | ret = bt_field_type_structure_add_field(packet_context_type, |
da1cc671 | 294 | ft, "packet_size"); |
25583cd0 | 295 | BT_ASSERT(ret == 0); |
da1cc671 | 296 | bt_put(ft); |
50842bdc | 297 | ft = bt_field_type_integer_create(32); |
25583cd0 | 298 | BT_ASSERT(ft); |
50842bdc | 299 | ret = bt_field_type_structure_add_field(packet_context_type, |
da1cc671 | 300 | ft, "content_size"); |
25583cd0 | 301 | BT_ASSERT(ret == 0); |
da1cc671 PP |
302 | bt_put(ft); |
303 | ||
50842bdc | 304 | event_header_type = bt_field_type_structure_create(); |
25583cd0 | 305 | BT_ASSERT(event_header_type); |
50842bdc | 306 | ft = bt_field_type_integer_create(32); |
25583cd0 | 307 | BT_ASSERT(ft); |
50842bdc | 308 | ret = bt_field_type_structure_add_field(event_header_type, |
da1cc671 | 309 | ft, "id"); |
25583cd0 | 310 | BT_ASSERT(ret == 0); |
da1cc671 PP |
311 | bt_put(ft); |
312 | ||
3dca2276 | 313 | ret = bt_stream_class_set_packet_context_field_type(stream_class, |
da1cc671 | 314 | packet_context_type); |
25583cd0 | 315 | BT_ASSERT(ret == 0); |
3dca2276 | 316 | ret = bt_stream_class_set_event_header_field_type(stream_class, |
da1cc671 | 317 | event_header_type); |
25583cd0 | 318 | BT_ASSERT(ret == 0); |
da1cc671 PP |
319 | |
320 | bt_put(packet_context_type); | |
321 | bt_put(event_header_type); | |
322 | } | |
323 | ||
50842bdc | 324 | static struct bt_stream_class *create_sc1(void) |
c9b3f44b JG |
325 | { |
326 | int ret; | |
50842bdc PP |
327 | struct bt_event_class *ec1 = NULL, *ec2 = NULL; |
328 | struct bt_stream_class *sc1 = NULL, *ret_stream = NULL; | |
c9b3f44b | 329 | |
3dca2276 | 330 | sc1 = bt_stream_class_create("sc1"); |
c9b3f44b JG |
331 | if (!sc1) { |
332 | diag("Failed to create Stream Class"); | |
333 | goto error; | |
334 | } | |
335 | ||
da1cc671 | 336 | set_stream_class_field_types(sc1); |
c9b3f44b JG |
337 | ec1 = create_complex_event("ec1"); |
338 | if (!ec1) { | |
339 | diag("Failed to create complex event EC1"); | |
340 | goto error; | |
341 | } | |
50842bdc | 342 | ret = bt_stream_class_add_event_class(sc1, ec1); |
c9b3f44b JG |
343 | if (ret) { |
344 | diag("Failed to add EC1 to SC1"); | |
345 | goto error; | |
346 | } | |
347 | ||
348 | ec2 = create_simple_event("ec2"); | |
349 | if (!ec2) { | |
350 | diag("Failed to create simple event EC2"); | |
351 | goto error; | |
352 | } | |
50842bdc | 353 | ret = bt_stream_class_add_event_class(sc1, ec2); |
c9b3f44b JG |
354 | if (ret) { |
355 | diag("Failed to add EC1 to SC1"); | |
356 | goto error; | |
357 | } | |
358 | ||
50842bdc | 359 | ret_stream = bt_event_class_get_stream_class(ec1); |
c9b3f44b JG |
360 | ok(ret_stream == sc1, "Get parent stream SC1 from EC1"); |
361 | BT_PUT(ret_stream); | |
362 | ||
50842bdc | 363 | ret_stream = bt_event_class_get_stream_class(ec2); |
c9b3f44b JG |
364 | ok(ret_stream == sc1, "Get parent stream SC1 from EC2"); |
365 | end: | |
366 | BT_PUT(ret_stream); | |
367 | BT_PUT(ec1); | |
368 | BT_PUT(ec2); | |
369 | return sc1; | |
370 | error: | |
371 | BT_PUT(sc1); | |
27f4d205 | 372 | goto end; |
c9b3f44b JG |
373 | } |
374 | ||
50842bdc | 375 | static struct bt_stream_class *create_sc2(void) |
c9b3f44b JG |
376 | { |
377 | int ret; | |
50842bdc PP |
378 | struct bt_event_class *ec3 = NULL; |
379 | struct bt_stream_class *sc2 = NULL, *ret_stream = NULL; | |
c9b3f44b | 380 | |
3dca2276 | 381 | sc2 = bt_stream_class_create("sc2"); |
c9b3f44b JG |
382 | if (!sc2) { |
383 | diag("Failed to create Stream Class"); | |
384 | goto error; | |
385 | } | |
386 | ||
da1cc671 | 387 | set_stream_class_field_types(sc2); |
c9b3f44b JG |
388 | ec3 = create_simple_event("ec3"); |
389 | if (!ec3) { | |
390 | diag("Failed to create simple event EC3"); | |
391 | goto error; | |
392 | } | |
50842bdc | 393 | ret = bt_stream_class_add_event_class(sc2, ec3); |
c9b3f44b JG |
394 | if (ret) { |
395 | diag("Failed to add EC3 to SC2"); | |
396 | goto error; | |
397 | } | |
398 | ||
50842bdc | 399 | ret_stream = bt_event_class_get_stream_class(ec3); |
c9b3f44b JG |
400 | ok(ret_stream == sc2, "Get parent stream SC2 from EC3"); |
401 | end: | |
402 | BT_PUT(ret_stream); | |
403 | BT_PUT(ec3); | |
404 | return sc2; | |
405 | error: | |
406 | BT_PUT(sc2); | |
27f4d205 | 407 | goto end; |
c9b3f44b JG |
408 | } |
409 | ||
50842bdc | 410 | static void set_trace_packet_header(struct bt_trace *trace) |
da1cc671 | 411 | { |
50842bdc PP |
412 | struct bt_field_type *packet_header_type; |
413 | struct bt_field_type *ft; | |
da1cc671 PP |
414 | int ret; |
415 | ||
50842bdc | 416 | packet_header_type = bt_field_type_structure_create(); |
25583cd0 | 417 | BT_ASSERT(packet_header_type); |
50842bdc | 418 | ft = bt_field_type_integer_create(32); |
25583cd0 | 419 | BT_ASSERT(ft); |
50842bdc | 420 | ret = bt_field_type_structure_add_field(packet_header_type, |
da1cc671 | 421 | ft, "stream_id"); |
25583cd0 | 422 | BT_ASSERT(ret == 0); |
da1cc671 PP |
423 | bt_put(ft); |
424 | ||
3dca2276 | 425 | ret = bt_trace_set_packet_header_field_type(trace, |
da1cc671 | 426 | packet_header_type); |
25583cd0 | 427 | BT_ASSERT(ret == 0); |
da1cc671 PP |
428 | |
429 | bt_put(packet_header_type); | |
430 | } | |
431 | ||
50842bdc | 432 | static struct bt_trace *create_tc1(void) |
c9b3f44b JG |
433 | { |
434 | int ret; | |
50842bdc PP |
435 | struct bt_trace *tc1 = NULL; |
436 | struct bt_stream_class *sc1 = NULL, *sc2 = NULL; | |
c9b3f44b | 437 | |
50842bdc | 438 | tc1 = bt_trace_create(); |
c9b3f44b | 439 | if (!tc1) { |
50842bdc | 440 | diag("bt_trace_create returned NULL"); |
c9b3f44b JG |
441 | goto error; |
442 | } | |
443 | ||
da1cc671 | 444 | set_trace_packet_header(tc1); |
c9b3f44b JG |
445 | sc1 = create_sc1(); |
446 | ok(sc1, "Create SC1"); | |
447 | if (!sc1) { | |
448 | goto error; | |
449 | } | |
50842bdc | 450 | ret = bt_trace_add_stream_class(tc1, sc1); |
c9b3f44b JG |
451 | ok(!ret, "Add SC1 to TC1"); |
452 | if (ret) { | |
453 | goto error; | |
454 | } | |
455 | ||
456 | sc2 = create_sc2(); | |
457 | ok(sc2, "Create SC2"); | |
458 | if (!sc2) { | |
459 | goto error; | |
460 | } | |
50842bdc | 461 | ret = bt_trace_add_stream_class(tc1, sc2); |
c9b3f44b JG |
462 | ok(!ret, "Add SC2 to TC1"); |
463 | if (ret) { | |
464 | goto error; | |
465 | } | |
466 | end: | |
467 | BT_PUT(sc1); | |
468 | BT_PUT(sc2); | |
469 | return tc1; | |
470 | error: | |
471 | BT_PUT(tc1); | |
27f4d205 | 472 | goto end; |
c9b3f44b JG |
473 | } |
474 | ||
50842bdc PP |
475 | static void init_weak_refs(struct bt_trace *tc, |
476 | struct bt_trace **tc1, | |
477 | struct bt_stream_class **sc1, | |
478 | struct bt_stream_class **sc2, | |
479 | struct bt_event_class **ec1, | |
480 | struct bt_event_class **ec2, | |
481 | struct bt_event_class **ec3) | |
c9b3f44b JG |
482 | { |
483 | *tc1 = tc; | |
50842bdc PP |
484 | *sc1 = bt_trace_get_stream_class_by_index(tc, 0); |
485 | *sc2 = bt_trace_get_stream_class_by_index(tc, 1); | |
486 | *ec1 = bt_stream_class_get_event_class_by_index(*sc1, 0); | |
487 | *ec2 = bt_stream_class_get_event_class_by_index(*sc1, 1); | |
488 | *ec3 = bt_stream_class_get_event_class_by_index(*sc2, 0); | |
c9b3f44b JG |
489 | bt_put(*sc1); |
490 | bt_put(*sc2); | |
491 | bt_put(*ec1); | |
492 | bt_put(*ec2); | |
493 | bt_put(*ec3); | |
494 | } | |
495 | ||
6271743c | 496 | static void test_example_scenario(void) |
c9b3f44b JG |
497 | { |
498 | /** | |
499 | * Weak pointers to CTF-IR objects are to be used very carefully. | |
500 | * This is NOT a good practice and is strongly discouraged; this | |
501 | * is only done to facilitate the validation of expected reference | |
502 | * counts without affecting them by taking "real" references to the | |
503 | * objects. | |
504 | */ | |
50842bdc PP |
505 | struct bt_trace *tc1 = NULL, *weak_tc1 = NULL; |
506 | struct bt_stream_class *weak_sc1 = NULL, *weak_sc2 = NULL; | |
507 | struct bt_event_class *weak_ec1 = NULL, *weak_ec2 = NULL, | |
c9b3f44b JG |
508 | *weak_ec3 = NULL; |
509 | struct user user_a = { 0 }, user_b = { 0 }, user_c = { 0 }; | |
510 | ||
511 | /* The only reference which exists at this point is on TC1. */ | |
512 | tc1 = create_tc1(); | |
27f4d205 | 513 | ok(tc1, "Initialize trace"); |
c9b3f44b | 514 | if (!tc1) { |
6271743c | 515 | return; |
c9b3f44b JG |
516 | } |
517 | ||
518 | init_weak_refs(tc1, &weak_tc1, &weak_sc1, &weak_sc2, &weak_ec1, | |
519 | &weak_ec2, &weak_ec3); | |
c9b3f44b | 520 | |
3fea54f6 | 521 | ok(bt_object_get_ref_count((void *) weak_sc1) == 0, |
c9b3f44b | 522 | "Initial SC1 reference count is 0"); |
3fea54f6 | 523 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 524 | "Initial SC2 reference count is 0"); |
3fea54f6 | 525 | ok(bt_object_get_ref_count((void *) weak_ec1) == 0, |
c9b3f44b | 526 | "Initial EC1 reference count is 0"); |
3fea54f6 | 527 | ok(bt_object_get_ref_count((void *) weak_ec2) == 0, |
c9b3f44b | 528 | "Initial EC2 reference count is 0"); |
3fea54f6 | 529 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b JG |
530 | "Initial EC3 reference count is 0"); |
531 | ||
532 | /* User A has ownership of the trace. */ | |
533 | BT_MOVE(user_a.tc, tc1); | |
3fea54f6 | 534 | ok(bt_object_get_ref_count((void *) user_a.tc) == 1, |
c9b3f44b JG |
535 | "TC1 reference count is 1"); |
536 | ||
537 | /* User A acquires a reference to SC2 from TC1. */ | |
50842bdc | 538 | user_a.sc = bt_trace_get_stream_class_by_index(user_a.tc, 1); |
c9b3f44b | 539 | ok(user_a.sc, "User A acquires SC2 from TC1"); |
3fea54f6 | 540 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 541 | "TC1 reference count is 2"); |
3fea54f6 | 542 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b JG |
543 | "SC2 reference count is 1"); |
544 | ||
545 | /* User A acquires a reference to EC3 from SC2. */ | |
50842bdc | 546 | user_a.ec = bt_stream_class_get_event_class_by_index(user_a.sc, 0); |
c9b3f44b | 547 | ok(user_a.ec, "User A acquires EC3 from SC2"); |
3fea54f6 | 548 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 549 | "TC1 reference count is 2"); |
3fea54f6 | 550 | ok(bt_object_get_ref_count((void *) weak_sc2) == 2, |
c9b3f44b | 551 | "SC2 reference count is 2"); |
3fea54f6 | 552 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
553 | "EC3 reference count is 1"); |
554 | ||
555 | /* User A releases its reference to SC2. */ | |
556 | diag("User A releases SC2"); | |
557 | BT_PUT(user_a.sc); | |
558 | /* | |
559 | * We keep the pointer to SC2 around to validate its reference | |
560 | * count. | |
561 | */ | |
3fea54f6 | 562 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 563 | "TC1 reference count is 2"); |
3fea54f6 | 564 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b | 565 | "SC2 reference count is 1"); |
3fea54f6 | 566 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
567 | "EC3 reference count is 1"); |
568 | ||
569 | /* User A releases its reference to TC1. */ | |
570 | diag("User A releases TC1"); | |
27f4d205 | 571 | BT_PUT(user_a.tc); |
c9b3f44b JG |
572 | /* |
573 | * We keep the pointer to TC1 around to validate its reference | |
574 | * count. | |
575 | */ | |
3fea54f6 | 576 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b | 577 | "TC1 reference count is 1"); |
3fea54f6 | 578 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b | 579 | "SC2 reference count is 1"); |
3fea54f6 | 580 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
581 | "EC3 reference count is 1"); |
582 | ||
583 | /* User B acquires a reference to SC1. */ | |
584 | diag("User B acquires a reference to SC1"); | |
585 | user_b.sc = bt_get(weak_sc1); | |
3fea54f6 | 586 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 587 | "TC1 reference count is 2"); |
3fea54f6 | 588 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b JG |
589 | "SC1 reference count is 1"); |
590 | ||
591 | /* User C acquires a reference to EC1. */ | |
592 | diag("User C acquires a reference to EC1"); | |
50842bdc | 593 | user_c.ec = bt_stream_class_get_event_class_by_index(user_b.sc, 0); |
3fea54f6 | 594 | ok(bt_object_get_ref_count((void *) weak_ec1) == 1, |
c9b3f44b | 595 | "EC1 reference count is 1"); |
3fea54f6 | 596 | ok(bt_object_get_ref_count((void *) weak_sc1) == 2, |
c9b3f44b JG |
597 | "SC1 reference count is 2"); |
598 | ||
599 | /* User A releases its reference on EC3. */ | |
600 | diag("User A releases its reference on EC3"); | |
601 | BT_PUT(user_a.ec); | |
3fea54f6 | 602 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b | 603 | "EC3 reference count is 1"); |
3fea54f6 | 604 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 605 | "SC2 reference count is 0"); |
3fea54f6 | 606 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b JG |
607 | "TC1 reference count is 1"); |
608 | ||
609 | /* User B releases its reference on SC1. */ | |
610 | diag("User B releases its reference on SC1"); | |
611 | BT_PUT(user_b.sc); | |
3fea54f6 | 612 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b JG |
613 | "SC1 reference count is 1"); |
614 | ||
615 | /* | |
616 | * User C is the sole owner of an object and is keeping the whole | |
617 | * trace hierarchy "alive" by holding a reference to EC1. | |
618 | */ | |
3fea54f6 | 619 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b | 620 | "TC1 reference count is 1"); |
3fea54f6 | 621 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b | 622 | "SC1 reference count is 1"); |
3fea54f6 | 623 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 624 | "SC2 reference count is 0"); |
3fea54f6 | 625 | ok(bt_object_get_ref_count((void *) weak_ec1) == 1, |
c9b3f44b | 626 | "EC1 reference count is 1"); |
3fea54f6 | 627 | ok(bt_object_get_ref_count((void *) weak_ec2) == 0, |
c9b3f44b | 628 | "EC2 reference count is 0"); |
3fea54f6 | 629 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b JG |
630 | "EC3 reference count is 0"); |
631 | ||
632 | /* Reclaim last reference held by User C. */ | |
633 | BT_PUT(user_c.ec); | |
6271743c PP |
634 | } |
635 | ||
3dca2276 | 636 | static void create_writer_user_full(struct writer_user *user) |
6271743c | 637 | { |
32bd47d1 | 638 | gchar *trace_path; |
3dca2276 PP |
639 | struct bt_ctf_field_type *ft; |
640 | struct bt_ctf_field *field; | |
6271743c PP |
641 | struct bt_ctf_clock *clock; |
642 | int ret; | |
643 | ||
32bd47d1 | 644 | trace_path = g_build_filename(g_get_tmp_dir(), "ctfwriter_XXXXXX", NULL); |
6271743c PP |
645 | if (!bt_mkdtemp(trace_path)) { |
646 | perror("# perror"); | |
647 | } | |
648 | ||
649 | user->writer = bt_ctf_writer_create(trace_path); | |
25583cd0 | 650 | BT_ASSERT(user->writer); |
dc3fffef | 651 | ret = bt_ctf_writer_set_byte_order(user->writer, |
3dca2276 | 652 | BT_CTF_BYTE_ORDER_LITTLE_ENDIAN); |
25583cd0 | 653 | BT_ASSERT(ret == 0); |
6271743c | 654 | user->tc = bt_ctf_writer_get_trace(user->writer); |
25583cd0 | 655 | BT_ASSERT(user->tc); |
3dca2276 | 656 | user->sc = bt_ctf_stream_class_create("sc"); |
25583cd0 | 657 | BT_ASSERT(user->sc); |
6271743c | 658 | clock = bt_ctf_clock_create("the_clock"); |
25583cd0 | 659 | BT_ASSERT(clock); |
81582b6b | 660 | ret = bt_ctf_writer_add_clock(user->writer, clock); |
25583cd0 | 661 | BT_ASSERT(!ret); |
3dca2276 | 662 | ret = bt_ctf_stream_class_set_clock(user->sc, clock); |
25583cd0 | 663 | BT_ASSERT(!ret); |
dc3fffef | 664 | BT_PUT(clock); |
6271743c | 665 | user->stream = bt_ctf_writer_create_stream(user->writer, user->sc); |
25583cd0 | 666 | BT_ASSERT(user->stream); |
3dca2276 | 667 | user->ec = bt_ctf_event_class_create("ec"); |
25583cd0 | 668 | BT_ASSERT(user->ec); |
3dca2276 | 669 | ft = create_writer_integer_struct(); |
25583cd0 | 670 | BT_ASSERT(ft); |
3dca2276 | 671 | ret = bt_ctf_event_class_set_payload_field_type(user->ec, ft); |
6271743c | 672 | BT_PUT(ft); |
25583cd0 | 673 | BT_ASSERT(!ret); |
3dca2276 | 674 | ret = bt_ctf_stream_class_add_event_class(user->sc, user->ec); |
25583cd0 | 675 | BT_ASSERT(!ret); |
3dca2276 | 676 | user->event = bt_ctf_event_create(user->ec); |
25583cd0 | 677 | BT_ASSERT(user->event); |
3dca2276 | 678 | field = bt_ctf_event_get_payload(user->event, "payload_8"); |
25583cd0 | 679 | BT_ASSERT(field); |
3dca2276 | 680 | ret = bt_ctf_field_integer_unsigned_set_value(field, 10); |
25583cd0 | 681 | BT_ASSERT(!ret); |
6271743c | 682 | BT_PUT(field); |
3dca2276 | 683 | field = bt_ctf_event_get_payload(user->event, "payload_16"); |
25583cd0 | 684 | BT_ASSERT(field); |
3dca2276 | 685 | ret = bt_ctf_field_integer_unsigned_set_value(field, 20); |
25583cd0 | 686 | BT_ASSERT(!ret); |
6271743c | 687 | BT_PUT(field); |
3dca2276 | 688 | field = bt_ctf_event_get_payload(user->event, "payload_32"); |
25583cd0 | 689 | BT_ASSERT(field); |
3dca2276 | 690 | ret = bt_ctf_field_integer_unsigned_set_value(field, 30); |
25583cd0 | 691 | BT_ASSERT(!ret); |
6271743c | 692 | BT_PUT(field); |
3dca2276 | 693 | ret = bt_ctf_stream_append_event(user->stream, user->event); |
25583cd0 | 694 | BT_ASSERT(!ret); |
851299b9 | 695 | recursive_rmdir(trace_path); |
32bd47d1 | 696 | g_free(trace_path); |
6271743c PP |
697 | } |
698 | ||
699 | static void test_put_order_swap(size_t *array, size_t a, size_t b) | |
700 | { | |
701 | size_t temp = array[a]; | |
702 | ||
703 | array[a] = array[b]; | |
704 | array[b] = temp; | |
705 | } | |
706 | ||
707 | static void test_put_order_put_objects(size_t *array, size_t size) | |
708 | { | |
709 | size_t i; | |
3dca2276 | 710 | struct writer_user user = { 0 }; |
6f2097e2 | 711 | void **objects = (void *) &user; |
6271743c | 712 | |
3dca2276 | 713 | create_writer_user_full(&user); |
6271743c PP |
714 | printf("# "); |
715 | ||
716 | for (i = 0; i < size; ++i) { | |
6f2097e2 | 717 | void *obj = objects[array[i]]; |
6271743c | 718 | |
3dca2276 | 719 | printf("%s", writer_user_names[array[i]]); |
6271743c PP |
720 | BT_PUT(obj); |
721 | ||
722 | if (i < size - 1) { | |
723 | printf(" -> "); | |
724 | } | |
725 | } | |
726 | ||
727 | puts(""); | |
728 | } | |
729 | ||
730 | static void test_put_order_permute(size_t *array, int k, size_t size) | |
731 | { | |
732 | if (k == 0) { | |
733 | test_put_order_put_objects(array, size); | |
734 | } else { | |
735 | int i; | |
736 | ||
737 | for (i = k - 1; i >= 0; i--) { | |
738 | size_t next_k = k - 1; | |
739 | ||
740 | test_put_order_swap(array, i, next_k); | |
741 | test_put_order_permute(array, next_k, size); | |
742 | test_put_order_swap(array, i, next_k); | |
743 | } | |
744 | } | |
745 | } | |
746 | ||
747 | static void test_put_order(void) | |
748 | { | |
749 | size_t i; | |
3dca2276 | 750 | size_t array[WRITER_USER_NR_ELEMENTS]; |
6271743c PP |
751 | |
752 | /* Initialize array of indexes */ | |
3dca2276 | 753 | for (i = 0; i < WRITER_USER_NR_ELEMENTS; ++i) { |
6271743c PP |
754 | array[i] = i; |
755 | } | |
756 | ||
3dca2276 PP |
757 | test_put_order_permute(array, WRITER_USER_NR_ELEMENTS, |
758 | WRITER_USER_NR_ELEMENTS); | |
6271743c PP |
759 | } |
760 | ||
761 | /** | |
762 | * The objective of this test is to implement and expand upon the scenario | |
763 | * described in the reference counting documentation and ensure that any node of | |
764 | * the Trace, Stream Class, Event Class, Stream and Event hiearchy keeps all | |
765 | * other "alive" and reachable. | |
766 | * | |
767 | * External tools (e.g. valgrind) should be used to confirm that this | |
768 | * known-good test does not leak memory. | |
769 | */ | |
770 | int main(int argc, char **argv) | |
771 | { | |
27f4d205 | 772 | /* Initialize tap harness before any tests */ |
6271743c PP |
773 | plan_tests(NR_TESTS); |
774 | ||
775 | test_example_scenario(); | |
776 | test_put_order(); | |
777 | ||
c9b3f44b JG |
778 | return exit_status(); |
779 | } |