4 * Trace IR Reference Count test
6 * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
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.
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.
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.
23 #include <babeltrace/ctf-writer/clock.h>
24 #include <babeltrace/ctf-writer/event.h>
25 #include <babeltrace/ctf-writer/fields.h>
26 #include <babeltrace/ctf-writer/stream-class.h>
27 #include <babeltrace/ctf-writer/stream.h>
28 #include <babeltrace/ctf-writer/trace.h>
29 #include <babeltrace/ctf-writer/writer.h>
30 #include <babeltrace/trace-ir/clock-class.h>
31 #include <babeltrace/trace-ir/event.h>
32 #include <babeltrace/trace-ir/event-class.h>
33 #include <babeltrace/trace-ir/fields.h>
34 #include <babeltrace/trace-ir/stream-class.h>
35 #include <babeltrace/trace-ir/stream.h>
36 #include <babeltrace/trace-ir/trace.h>
37 #include <babeltrace/object-internal.h>
38 #include <babeltrace/compat/stdlib-internal.h>
39 #include <babeltrace/assert-internal.h>
46 struct bt_stream_class
*sc
;
47 struct bt_event_class
*ec
;
48 struct bt_stream
*stream
;
49 struct bt_event
*event
;
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
;
61 const char *writer_user_names
[] = {
70 static const size_t WRITER_USER_NR_ELEMENTS
=
71 sizeof(struct writer_user
) / sizeof(void *);
74 * Returns a structure containing the following fields:
75 * - uint8_t payload_8;
76 * - uint16_t payload_16;
77 * - uint32_t payload_32;
79 static struct bt_field_type
*create_integer_struct(void)
82 struct bt_field_type
*structure
= NULL
;
83 struct bt_field_type
*ui8
= NULL
, *ui16
= NULL
, *ui32
= NULL
;
85 structure
= bt_field_type_structure_create();
87 ui8
= bt_field_type_unsigned_integer_create();
89 ret
= bt_field_type_integer_set_field_value_range(ui8
, 8);
91 ret
= bt_field_type_structure_append_member(structure
,
94 ui16
= bt_field_type_unsigned_integer_create();
96 ret
= bt_field_type_integer_set_field_value_range(ui16
, 16);
98 ret
= bt_field_type_structure_append_member(structure
,
101 ui32
= bt_field_type_unsigned_integer_create();
103 ret
= bt_field_type_integer_set_field_value_range(ui32
, 32);
105 ret
= bt_field_type_structure_append_member(structure
,
114 static struct bt_ctf_field_type
*create_writer_integer_struct(void)
117 struct bt_ctf_field_type
*structure
= NULL
;
118 struct bt_ctf_field_type
*ui8
= NULL
, *ui16
= NULL
, *ui32
= NULL
;
120 structure
= bt_ctf_field_type_structure_create();
121 BT_ASSERT(structure
);
122 ui8
= bt_ctf_field_type_integer_create(8);
124 ret
= bt_ctf_field_type_structure_add_field(structure
, ui8
,
127 ui16
= bt_ctf_field_type_integer_create(16);
129 ret
= bt_ctf_field_type_structure_add_field(structure
, ui16
,
132 ui32
= bt_ctf_field_type_integer_create(32);
134 ret
= bt_ctf_field_type_structure_add_field(structure
, ui32
,
144 * A simple event has the following payload:
145 * - uint8_t payload_8;
146 * - uint16_t payload_16;
147 * - uint32_t payload_32;
149 static struct bt_event_class
*create_simple_event(struct bt_stream_class
*sc
,
153 struct bt_event_class
*event
= NULL
;
154 struct bt_field_type
*payload
= NULL
;
157 event
= bt_event_class_create(sc
);
159 ret
= bt_event_class_set_name(event
, name
);
161 payload
= create_integer_struct();
163 ret
= bt_event_class_set_payload_field_type(event
, payload
);
170 * A complex event has the following payload:
171 * - uint8_t payload_8;
172 * - uint16_t payload_16;
173 * - uint32_t payload_32;
174 * - struct payload_struct:
175 * - uint8_t payload_8;
176 * - uint16_t payload_16;
177 * - uint32_t payload_32;
179 static struct bt_event_class
*create_complex_event(struct bt_stream_class
*sc
,
183 struct bt_event_class
*event
= NULL
;
184 struct bt_field_type
*inner
= NULL
, *outer
= NULL
;
187 event
= bt_event_class_create(sc
);
189 ret
= bt_event_class_set_name(event
, name
);
191 outer
= create_integer_struct();
193 inner
= create_integer_struct();
195 ret
= bt_field_type_structure_append_member(outer
,
196 "payload_struct", inner
);
198 ret
= bt_event_class_set_payload_field_type(event
, outer
);
205 static void set_stream_class_field_types(
206 struct bt_stream_class
*stream_class
)
208 struct bt_field_type
*packet_context_type
;
209 struct bt_field_type
*event_header_type
;
210 struct bt_field_type
*ft
;
213 packet_context_type
= bt_field_type_structure_create();
214 BT_ASSERT(packet_context_type
);
215 ft
= bt_field_type_unsigned_integer_create();
217 ret
= bt_field_type_integer_set_field_value_range(ft
, 32);
219 ret
= bt_field_type_structure_append_member(packet_context_type
,
223 ft
= bt_field_type_unsigned_integer_create();
225 ret
= bt_field_type_integer_set_field_value_range(ft
, 32);
227 ret
= bt_field_type_structure_append_member(packet_context_type
,
231 event_header_type
= bt_field_type_structure_create();
232 BT_ASSERT(event_header_type
);
233 ft
= bt_field_type_unsigned_integer_create();
235 ret
= bt_field_type_integer_set_field_value_range(ft
, 32);
237 ret
= bt_field_type_structure_append_member(event_header_type
,
241 ret
= bt_stream_class_set_packet_context_field_type(stream_class
,
242 packet_context_type
);
244 ret
= bt_stream_class_set_event_header_field_type(stream_class
,
247 bt_put(packet_context_type
);
248 bt_put(event_header_type
);
251 static void create_sc1(struct bt_trace
*trace
)
254 struct bt_event_class
*ec1
= NULL
, *ec2
= NULL
;
255 struct bt_stream_class
*sc1
= NULL
, *ret_stream
= NULL
;
257 sc1
= bt_stream_class_create(trace
);
259 ret
= bt_stream_class_set_name(sc1
, "sc1");
261 set_stream_class_field_types(sc1
);
262 ec1
= create_complex_event(sc1
, "ec1");
264 ec2
= create_simple_event(sc1
, "ec2");
266 ret_stream
= bt_event_class_borrow_stream_class(ec1
);
267 ok(ret_stream
== sc1
, "Borrow parent stream SC1 from EC1");
268 ret_stream
= bt_event_class_borrow_stream_class(ec2
);
269 ok(ret_stream
== sc1
, "Borrow parent stream SC1 from EC2");
275 static void create_sc2(struct bt_trace
*trace
)
278 struct bt_event_class
*ec3
= NULL
;
279 struct bt_stream_class
*sc2
= NULL
, *ret_stream
= NULL
;
281 sc2
= bt_stream_class_create(trace
);
283 ret
= bt_stream_class_set_name(sc2
, "sc2");
285 set_stream_class_field_types(sc2
);
286 ec3
= create_simple_event(sc2
, "ec3");
287 ret_stream
= bt_event_class_borrow_stream_class(ec3
);
288 ok(ret_stream
== sc2
, "Borrow parent stream SC2 from EC3");
293 static void set_trace_packet_header(struct bt_trace
*trace
)
295 struct bt_field_type
*packet_header_type
;
296 struct bt_field_type
*ft
;
299 packet_header_type
= bt_field_type_structure_create();
300 BT_ASSERT(packet_header_type
);
301 ft
= bt_field_type_unsigned_integer_create();
303 ret
= bt_field_type_integer_set_field_value_range(ft
, 32);
305 ret
= bt_field_type_structure_append_member(packet_header_type
,
309 ret
= bt_trace_set_packet_header_field_type(trace
,
313 bt_put(packet_header_type
);
316 static struct bt_trace
*create_tc1(void)
318 struct bt_trace
*tc1
= NULL
;
320 tc1
= bt_trace_create();
322 set_trace_packet_header(tc1
);
328 static void init_weak_refs(struct bt_trace
*tc
,
329 struct bt_trace
**tc1
,
330 struct bt_stream_class
**sc1
,
331 struct bt_stream_class
**sc2
,
332 struct bt_event_class
**ec1
,
333 struct bt_event_class
**ec2
,
334 struct bt_event_class
**ec3
)
337 *sc1
= bt_trace_borrow_stream_class_by_index(tc
, 0);
338 *sc2
= bt_trace_borrow_stream_class_by_index(tc
, 1);
339 *ec1
= bt_stream_class_borrow_event_class_by_index(*sc1
, 0);
340 *ec2
= bt_stream_class_borrow_event_class_by_index(*sc1
, 1);
341 *ec3
= bt_stream_class_borrow_event_class_by_index(*sc2
, 0);
344 static void test_example_scenario(void)
347 * Weak pointers to trace IR objects are to be used very
348 * carefully. This is NOT a good practice and is strongly
349 * discouraged; this is only done to facilitate the validation
350 * of expected reference counts without affecting them by taking
351 * "real" references to the objects.
353 struct bt_trace
*tc1
= NULL
, *weak_tc1
= NULL
;
354 struct bt_stream_class
*weak_sc1
= NULL
, *weak_sc2
= NULL
;
355 struct bt_event_class
*weak_ec1
= NULL
, *weak_ec2
= NULL
,
357 struct user user_a
= { 0 }, user_b
= { 0 }, user_c
= { 0 };
359 /* The only reference which exists at this point is on TC1. */
361 ok(tc1
, "Initialize trace");
363 init_weak_refs(tc1
, &weak_tc1
, &weak_sc1
, &weak_sc2
, &weak_ec1
,
364 &weak_ec2
, &weak_ec3
);
365 ok(bt_object_get_ref_count((void *) weak_sc1
) == 0,
366 "Initial SC1 reference count is 0");
367 ok(bt_object_get_ref_count((void *) weak_sc2
) == 0,
368 "Initial SC2 reference count is 0");
369 ok(bt_object_get_ref_count((void *) weak_ec1
) == 0,
370 "Initial EC1 reference count is 0");
371 ok(bt_object_get_ref_count((void *) weak_ec2
) == 0,
372 "Initial EC2 reference count is 0");
373 ok(bt_object_get_ref_count((void *) weak_ec3
) == 0,
374 "Initial EC3 reference count is 0");
376 /* User A has ownership of the trace. */
377 BT_MOVE(user_a
.tc
, tc1
);
378 ok(bt_object_get_ref_count((void *) user_a
.tc
) == 1,
379 "TC1 reference count is 1");
381 /* User A acquires a reference to SC2 from TC1. */
382 user_a
.sc
= bt_get(bt_trace_borrow_stream_class_by_index(user_a
.tc
, 1));
383 ok(user_a
.sc
, "User A acquires SC2 from TC1");
384 ok(bt_object_get_ref_count((void *) weak_tc1
) == 2,
385 "TC1 reference count is 2");
386 ok(bt_object_get_ref_count((void *) weak_sc2
) == 1,
387 "SC2 reference count is 1");
389 /* User A acquires a reference to EC3 from SC2. */
391 bt_stream_class_borrow_event_class_by_index(user_a
.sc
, 0));
392 ok(user_a
.ec
, "User A acquires EC3 from SC2");
393 ok(bt_object_get_ref_count((void *) weak_tc1
) == 2,
394 "TC1 reference count is 2");
395 ok(bt_object_get_ref_count((void *) weak_sc2
) == 2,
396 "SC2 reference count is 2");
397 ok(bt_object_get_ref_count((void *) weak_ec3
) == 1,
398 "EC3 reference count is 1");
400 /* User A releases its reference to SC2. */
401 diag("User A releases SC2");
404 * We keep the pointer to SC2 around to validate its reference
407 ok(bt_object_get_ref_count((void *) weak_tc1
) == 2,
408 "TC1 reference count is 2");
409 ok(bt_object_get_ref_count((void *) weak_sc2
) == 1,
410 "SC2 reference count is 1");
411 ok(bt_object_get_ref_count((void *) weak_ec3
) == 1,
412 "EC3 reference count is 1");
414 /* User A releases its reference to TC1. */
415 diag("User A releases TC1");
418 * We keep the pointer to TC1 around to validate its reference
421 ok(bt_object_get_ref_count((void *) weak_tc1
) == 1,
422 "TC1 reference count is 1");
423 ok(bt_object_get_ref_count((void *) weak_sc2
) == 1,
424 "SC2 reference count is 1");
425 ok(bt_object_get_ref_count((void *) weak_ec3
) == 1,
426 "EC3 reference count is 1");
428 /* User B acquires a reference to SC1. */
429 diag("User B acquires a reference to SC1");
430 user_b
.sc
= bt_get(weak_sc1
);
431 ok(bt_object_get_ref_count((void *) weak_tc1
) == 2,
432 "TC1 reference count is 2");
433 ok(bt_object_get_ref_count((void *) weak_sc1
) == 1,
434 "SC1 reference count is 1");
436 /* User C acquires a reference to EC1. */
437 diag("User C acquires a reference to EC1");
439 bt_stream_class_borrow_event_class_by_index(user_b
.sc
, 0));
440 ok(bt_object_get_ref_count((void *) weak_ec1
) == 1,
441 "EC1 reference count is 1");
442 ok(bt_object_get_ref_count((void *) weak_sc1
) == 2,
443 "SC1 reference count is 2");
445 /* User A releases its reference on EC3. */
446 diag("User A releases its reference on EC3");
448 ok(bt_object_get_ref_count((void *) weak_ec3
) == 0,
449 "EC3 reference count is 1");
450 ok(bt_object_get_ref_count((void *) weak_sc2
) == 0,
451 "SC2 reference count is 0");
452 ok(bt_object_get_ref_count((void *) weak_tc1
) == 1,
453 "TC1 reference count is 1");
455 /* User B releases its reference on SC1. */
456 diag("User B releases its reference on SC1");
458 ok(bt_object_get_ref_count((void *) weak_sc1
) == 1,
459 "SC1 reference count is 1");
462 * User C is the sole owner of an object and is keeping the whole
463 * trace hierarchy "alive" by holding a reference to EC1.
465 ok(bt_object_get_ref_count((void *) weak_tc1
) == 1,
466 "TC1 reference count is 1");
467 ok(bt_object_get_ref_count((void *) weak_sc1
) == 1,
468 "SC1 reference count is 1");
469 ok(bt_object_get_ref_count((void *) weak_sc2
) == 0,
470 "SC2 reference count is 0");
471 ok(bt_object_get_ref_count((void *) weak_ec1
) == 1,
472 "EC1 reference count is 1");
473 ok(bt_object_get_ref_count((void *) weak_ec2
) == 0,
474 "EC2 reference count is 0");
475 ok(bt_object_get_ref_count((void *) weak_ec3
) == 0,
476 "EC3 reference count is 0");
478 /* Reclaim last reference held by User C. */
482 static void create_writer_user_full(struct writer_user
*user
)
485 struct bt_ctf_field_type
*ft
;
486 struct bt_ctf_field
*field
;
487 struct bt_ctf_clock
*clock
;
490 trace_path
= g_build_filename(g_get_tmp_dir(), "ctfwriter_XXXXXX", NULL
);
491 if (!bt_mkdtemp(trace_path
)) {
495 user
->writer
= bt_ctf_writer_create(trace_path
);
496 BT_ASSERT(user
->writer
);
497 ret
= bt_ctf_writer_set_byte_order(user
->writer
,
498 BT_CTF_BYTE_ORDER_LITTLE_ENDIAN
);
500 user
->tc
= bt_ctf_writer_get_trace(user
->writer
);
502 user
->sc
= bt_ctf_stream_class_create("sc");
504 clock
= bt_ctf_clock_create("the_clock");
506 ret
= bt_ctf_writer_add_clock(user
->writer
, clock
);
508 ret
= bt_ctf_stream_class_set_clock(user
->sc
, clock
);
511 user
->stream
= bt_ctf_writer_create_stream(user
->writer
, user
->sc
);
512 BT_ASSERT(user
->stream
);
513 user
->ec
= bt_ctf_event_class_create("ec");
515 ft
= create_writer_integer_struct();
517 ret
= bt_ctf_event_class_set_payload_field_type(user
->ec
, ft
);
520 ret
= bt_ctf_stream_class_add_event_class(user
->sc
, user
->ec
);
522 user
->event
= bt_ctf_event_create(user
->ec
);
523 BT_ASSERT(user
->event
);
524 field
= bt_ctf_event_get_payload(user
->event
, "payload_8");
526 ret
= bt_ctf_field_integer_unsigned_set_value(field
, 10);
529 field
= bt_ctf_event_get_payload(user
->event
, "payload_16");
531 ret
= bt_ctf_field_integer_unsigned_set_value(field
, 20);
534 field
= bt_ctf_event_get_payload(user
->event
, "payload_32");
536 ret
= bt_ctf_field_integer_unsigned_set_value(field
, 30);
539 ret
= bt_ctf_stream_append_event(user
->stream
, user
->event
);
541 recursive_rmdir(trace_path
);
545 static void test_put_order_swap(size_t *array
, size_t a
, size_t b
)
547 size_t temp
= array
[a
];
553 static void test_put_order_put_objects(size_t *array
, size_t size
)
556 struct writer_user user
= { 0 };
557 void **objects
= (void *) &user
;
559 create_writer_user_full(&user
);
562 for (i
= 0; i
< size
; ++i
) {
563 void *obj
= objects
[array
[i
]];
565 printf("%s", writer_user_names
[array
[i
]]);
576 static void test_put_order_permute(size_t *array
, int k
, size_t size
)
579 test_put_order_put_objects(array
, size
);
583 for (i
= k
- 1; i
>= 0; i
--) {
584 size_t next_k
= k
- 1;
586 test_put_order_swap(array
, i
, next_k
);
587 test_put_order_permute(array
, next_k
, size
);
588 test_put_order_swap(array
, i
, next_k
);
593 static void test_put_order(void)
596 size_t array
[WRITER_USER_NR_ELEMENTS
];
598 /* Initialize array of indexes */
599 for (i
= 0; i
< WRITER_USER_NR_ELEMENTS
; ++i
) {
603 test_put_order_permute(array
, WRITER_USER_NR_ELEMENTS
,
604 WRITER_USER_NR_ELEMENTS
);
608 * The objective of this test is to implement and expand upon the scenario
609 * described in the reference counting documentation and ensure that any node of
610 * the Trace, Stream Class, Event Class, Stream and Event hiearchy keeps all
611 * other "alive" and reachable.
613 * External tools (e.g. valgrind) should be used to confirm that this
614 * known-good test does not leak memory.
616 int main(int argc
, char **argv
)
618 /* Initialize tap harness before any tests */
619 plan_tests(NR_TESTS
);
621 test_example_scenario();
624 return exit_status();