Commit | Line | Data |
---|---|---|
c9b3f44b | 1 | /* |
108b91d0 | 2 | * test_trace_ir_ref.c |
c9b3f44b | 3 | * |
108b91d0 | 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" | |
9e550e5f | 23 | #include <babeltrace/babeltrace.h> |
c9b3f44b | 24 | #include <babeltrace/object-internal.h> |
3d9990ac | 25 | #include <babeltrace/compat/stdlib-internal.h> |
b8f13b8b | 26 | #include <babeltrace/assert-internal.h> |
851299b9 | 27 | #include "common.h" |
c9b3f44b | 28 | |
7b33a0e0 | 29 | #define NR_TESTS 37 |
8bbe269d | 30 | |
c9b3f44b | 31 | struct user { |
9e550e5f PP |
32 | struct bt_private_trace *tc; |
33 | struct bt_private_stream_class *sc; | |
34 | struct bt_private_event_class *ec; | |
35 | struct bt_private_stream *stream; | |
36 | struct bt_private_event *event; | |
c9b3f44b JG |
37 | }; |
38 | ||
8deee039 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 | ||
8deee039 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 | */ | |
9e550e5f | 66 | static struct bt_private_field_class *create_integer_struct(void) |
c9b3f44b JG |
67 | { |
68 | int ret; | |
9e550e5f PP |
69 | struct bt_private_field_class *structure = NULL; |
70 | struct bt_private_field_class *ui8 = NULL, *ui16 = NULL, *ui32 = NULL; | |
c9b3f44b | 71 | |
9e550e5f | 72 | structure = bt_private_field_class_structure_create(); |
7b33a0e0 | 73 | BT_ASSERT(structure); |
9e550e5f | 74 | ui8 = bt_private_field_class_unsigned_integer_create(); |
7b33a0e0 | 75 | BT_ASSERT(ui8); |
9e550e5f | 76 | ret = bt_private_field_class_integer_set_field_value_range(ui8, 8); |
7b33a0e0 | 77 | BT_ASSERT(ret == 0); |
96854e6a | 78 | ret = bt_private_field_class_structure_append_member(structure, |
7b33a0e0 PP |
79 | "payload_8", ui8); |
80 | BT_ASSERT(ret == 0); | |
9e550e5f | 81 | ui16 = bt_private_field_class_unsigned_integer_create(); |
7b33a0e0 | 82 | BT_ASSERT(ui16); |
9e550e5f | 83 | ret = bt_private_field_class_integer_set_field_value_range(ui16, 16); |
7b33a0e0 | 84 | BT_ASSERT(ret == 0); |
96854e6a | 85 | ret = bt_private_field_class_structure_append_member(structure, |
7b33a0e0 PP |
86 | "payload_16", ui16); |
87 | BT_ASSERT(ret == 0); | |
9e550e5f | 88 | ui32 = bt_private_field_class_unsigned_integer_create(); |
7b33a0e0 | 89 | BT_ASSERT(ui32); |
9e550e5f | 90 | ret = bt_private_field_class_integer_set_field_value_range(ui32, 32); |
7b33a0e0 | 91 | BT_ASSERT(ret == 0); |
96854e6a | 92 | ret = bt_private_field_class_structure_append_member(structure, |
7b33a0e0 PP |
93 | "payload_32", ui32); |
94 | BT_ASSERT(ret == 0); | |
8138bfe1 PP |
95 | BT_OBJECT_PUT_REF_AND_RESET(ui8); |
96 | BT_OBJECT_PUT_REF_AND_RESET(ui16); | |
97 | BT_OBJECT_PUT_REF_AND_RESET(ui32); | |
c9b3f44b | 98 | return structure; |
c9b3f44b JG |
99 | } |
100 | ||
8deee039 PP |
101 | static struct bt_ctf_field_type *create_writer_integer_struct(void) |
102 | { | |
103 | int ret; | |
104 | struct bt_ctf_field_type *structure = NULL; | |
105 | struct bt_ctf_field_type *ui8 = NULL, *ui16 = NULL, *ui32 = NULL; | |
106 | ||
107 | structure = bt_ctf_field_type_structure_create(); | |
7b33a0e0 | 108 | BT_ASSERT(structure); |
8deee039 | 109 | ui8 = bt_ctf_field_type_integer_create(8); |
7b33a0e0 | 110 | BT_ASSERT(ui8); |
8deee039 PP |
111 | ret = bt_ctf_field_type_structure_add_field(structure, ui8, |
112 | "payload_8"); | |
7b33a0e0 | 113 | BT_ASSERT(ret == 0); |
8deee039 | 114 | ui16 = bt_ctf_field_type_integer_create(16); |
7b33a0e0 | 115 | BT_ASSERT(ui16); |
8deee039 PP |
116 | ret = bt_ctf_field_type_structure_add_field(structure, ui16, |
117 | "payload_16"); | |
7b33a0e0 | 118 | BT_ASSERT(ret == 0); |
8deee039 | 119 | ui32 = bt_ctf_field_type_integer_create(32); |
7b33a0e0 | 120 | BT_ASSERT(ui32); |
8deee039 PP |
121 | ret = bt_ctf_field_type_structure_add_field(structure, ui32, |
122 | "payload_32"); | |
7b33a0e0 | 123 | BT_ASSERT(ret == 0); |
8138bfe1 PP |
124 | BT_OBJECT_PUT_REF_AND_RESET(ui8); |
125 | BT_OBJECT_PUT_REF_AND_RESET(ui16); | |
126 | BT_OBJECT_PUT_REF_AND_RESET(ui32); | |
8deee039 | 127 | return structure; |
8deee039 PP |
128 | } |
129 | ||
c9b3f44b JG |
130 | /** |
131 | * A simple event has the following payload: | |
132 | * - uint8_t payload_8; | |
133 | * - uint16_t payload_16; | |
134 | * - uint32_t payload_32; | |
135 | */ | |
9e550e5f PP |
136 | static struct bt_private_event_class *create_simple_event( |
137 | struct bt_private_stream_class *sc, const char *name) | |
c9b3f44b JG |
138 | { |
139 | int ret; | |
9e550e5f PP |
140 | struct bt_private_event_class *event = NULL; |
141 | struct bt_private_field_class *payload = NULL; | |
c9b3f44b | 142 | |
b8f13b8b | 143 | BT_ASSERT(name); |
9e550e5f | 144 | event = bt_private_event_class_create(sc); |
7b33a0e0 | 145 | BT_ASSERT(event); |
9e550e5f | 146 | ret = bt_private_event_class_set_name(event, name); |
7b33a0e0 | 147 | BT_ASSERT(ret == 0); |
c9b3f44b | 148 | payload = create_integer_struct(); |
7b33a0e0 | 149 | BT_ASSERT(payload); |
96854e6a | 150 | ret = bt_private_event_class_set_payload_field_class(event, payload); |
7b33a0e0 | 151 | BT_ASSERT(ret == 0); |
8138bfe1 | 152 | BT_OBJECT_PUT_REF_AND_RESET(payload); |
c9b3f44b | 153 | return event; |
c9b3f44b JG |
154 | } |
155 | ||
156 | /** | |
157 | * A complex event has the following payload: | |
158 | * - uint8_t payload_8; | |
159 | * - uint16_t payload_16; | |
160 | * - uint32_t payload_32; | |
161 | * - struct payload_struct: | |
162 | * - uint8_t payload_8; | |
163 | * - uint16_t payload_16; | |
164 | * - uint32_t payload_32; | |
165 | */ | |
9e550e5f PP |
166 | static struct bt_private_event_class *create_complex_event( |
167 | struct bt_private_stream_class *sc, | |
7b33a0e0 | 168 | const char *name) |
c9b3f44b JG |
169 | { |
170 | int ret; | |
9e550e5f PP |
171 | struct bt_private_event_class *event = NULL; |
172 | struct bt_private_field_class *inner = NULL, *outer = NULL; | |
c9b3f44b | 173 | |
b8f13b8b | 174 | BT_ASSERT(name); |
9e550e5f | 175 | event = bt_private_event_class_create(sc); |
7b33a0e0 | 176 | BT_ASSERT(event); |
9e550e5f | 177 | ret = bt_private_event_class_set_name(event, name); |
7b33a0e0 | 178 | BT_ASSERT(ret == 0); |
27f4d205 | 179 | outer = create_integer_struct(); |
7b33a0e0 | 180 | BT_ASSERT(outer); |
27f4d205 | 181 | inner = create_integer_struct(); |
7b33a0e0 | 182 | BT_ASSERT(inner); |
96854e6a | 183 | ret = bt_private_field_class_structure_append_member(outer, |
7b33a0e0 PP |
184 | "payload_struct", inner); |
185 | BT_ASSERT(ret == 0); | |
96854e6a | 186 | ret = bt_private_event_class_set_payload_field_class(event, outer); |
7b33a0e0 | 187 | BT_ASSERT(ret == 0); |
8138bfe1 PP |
188 | BT_OBJECT_PUT_REF_AND_RESET(inner); |
189 | BT_OBJECT_PUT_REF_AND_RESET(outer); | |
c9b3f44b | 190 | return event; |
c9b3f44b JG |
191 | } |
192 | ||
939190b3 | 193 | static void set_stream_class_field_classes( |
9e550e5f | 194 | struct bt_private_stream_class *stream_class) |
da1cc671 | 195 | { |
9e550e5f PP |
196 | struct bt_private_field_class *packet_context_type; |
197 | struct bt_private_field_class *event_header_type; | |
198 | struct bt_private_field_class *fc; | |
da1cc671 PP |
199 | int ret; |
200 | ||
9e550e5f | 201 | packet_context_type = bt_private_field_class_structure_create(); |
b8f13b8b | 202 | BT_ASSERT(packet_context_type); |
9e550e5f | 203 | fc = bt_private_field_class_unsigned_integer_create(); |
939190b3 | 204 | BT_ASSERT(fc); |
9e550e5f | 205 | ret = bt_private_field_class_integer_set_field_value_range(fc, 32); |
7b33a0e0 | 206 | BT_ASSERT(ret == 0); |
96854e6a | 207 | ret = bt_private_field_class_structure_append_member(packet_context_type, |
939190b3 | 208 | "packet_size", fc); |
b8f13b8b | 209 | BT_ASSERT(ret == 0); |
8138bfe1 | 210 | bt_object_put_ref(fc); |
9e550e5f | 211 | fc = bt_private_field_class_unsigned_integer_create(); |
939190b3 | 212 | BT_ASSERT(fc); |
9e550e5f | 213 | ret = bt_private_field_class_integer_set_field_value_range(fc, 32); |
7b33a0e0 | 214 | BT_ASSERT(ret == 0); |
96854e6a | 215 | ret = bt_private_field_class_structure_append_member(packet_context_type, |
939190b3 | 216 | "content_size", fc); |
b8f13b8b | 217 | BT_ASSERT(ret == 0); |
8138bfe1 | 218 | bt_object_put_ref(fc); |
9e550e5f | 219 | event_header_type = bt_private_field_class_structure_create(); |
b8f13b8b | 220 | BT_ASSERT(event_header_type); |
9e550e5f | 221 | fc = bt_private_field_class_unsigned_integer_create(); |
939190b3 | 222 | BT_ASSERT(fc); |
9e550e5f | 223 | ret = bt_private_field_class_integer_set_field_value_range(fc, 32); |
7b33a0e0 | 224 | BT_ASSERT(ret == 0); |
96854e6a | 225 | ret = bt_private_field_class_structure_append_member(event_header_type, |
939190b3 | 226 | "id", fc); |
b8f13b8b | 227 | BT_ASSERT(ret == 0); |
8138bfe1 | 228 | bt_object_put_ref(fc); |
96854e6a | 229 | ret = bt_private_stream_class_set_packet_context_field_class( |
9e550e5f | 230 | stream_class, packet_context_type); |
b8f13b8b | 231 | BT_ASSERT(ret == 0); |
96854e6a | 232 | ret = bt_private_stream_class_set_event_header_field_class( |
9e550e5f | 233 | stream_class, event_header_type); |
b8f13b8b | 234 | BT_ASSERT(ret == 0); |
8138bfe1 PP |
235 | bt_object_put_ref(packet_context_type); |
236 | bt_object_put_ref(event_header_type); | |
da1cc671 PP |
237 | } |
238 | ||
9e550e5f | 239 | static void create_sc1(struct bt_private_trace *trace) |
c9b3f44b JG |
240 | { |
241 | int ret; | |
9e550e5f PP |
242 | struct bt_private_event_class *ec1 = NULL, *ec2 = NULL; |
243 | struct bt_private_stream_class *sc1 = NULL, *ret_stream = NULL; | |
c9b3f44b | 244 | |
9e550e5f | 245 | sc1 = bt_private_stream_class_create(trace); |
7b33a0e0 | 246 | BT_ASSERT(sc1); |
9e550e5f | 247 | ret = bt_private_stream_class_set_name(sc1, "sc1"); |
7b33a0e0 | 248 | BT_ASSERT(ret == 0); |
939190b3 | 249 | set_stream_class_field_classes(sc1); |
7b33a0e0 PP |
250 | ec1 = create_complex_event(sc1, "ec1"); |
251 | BT_ASSERT(ec1); | |
252 | ec2 = create_simple_event(sc1, "ec2"); | |
253 | BT_ASSERT(ec2); | |
96854e6a | 254 | ret_stream = bt_private_event_class_borrow_stream_class(ec1); |
7b33a0e0 | 255 | ok(ret_stream == sc1, "Borrow parent stream SC1 from EC1"); |
96854e6a | 256 | ret_stream = bt_private_event_class_borrow_stream_class(ec2); |
7b33a0e0 | 257 | ok(ret_stream == sc1, "Borrow parent stream SC1 from EC2"); |
8138bfe1 PP |
258 | BT_OBJECT_PUT_REF_AND_RESET(ec1); |
259 | BT_OBJECT_PUT_REF_AND_RESET(ec2); | |
260 | BT_OBJECT_PUT_REF_AND_RESET(sc1); | |
c9b3f44b JG |
261 | } |
262 | ||
9e550e5f | 263 | static void create_sc2(struct bt_private_trace *trace) |
c9b3f44b JG |
264 | { |
265 | int ret; | |
9e550e5f PP |
266 | struct bt_private_event_class *ec3 = NULL; |
267 | struct bt_private_stream_class *sc2 = NULL, *ret_stream = NULL; | |
c9b3f44b | 268 | |
9e550e5f | 269 | sc2 = bt_private_stream_class_create(trace); |
7b33a0e0 | 270 | BT_ASSERT(sc2); |
9e550e5f | 271 | ret = bt_private_stream_class_set_name(sc2, "sc2"); |
7b33a0e0 | 272 | BT_ASSERT(ret == 0); |
939190b3 | 273 | set_stream_class_field_classes(sc2); |
7b33a0e0 | 274 | ec3 = create_simple_event(sc2, "ec3"); |
96854e6a | 275 | ret_stream = bt_private_event_class_borrow_stream_class(ec3); |
7b33a0e0 | 276 | ok(ret_stream == sc2, "Borrow parent stream SC2 from EC3"); |
8138bfe1 PP |
277 | BT_OBJECT_PUT_REF_AND_RESET(ec3); |
278 | BT_OBJECT_PUT_REF_AND_RESET(sc2); | |
c9b3f44b JG |
279 | } |
280 | ||
9e550e5f | 281 | static void set_trace_packet_header(struct bt_private_trace *trace) |
da1cc671 | 282 | { |
9e550e5f PP |
283 | struct bt_private_field_class *packet_header_type; |
284 | struct bt_private_field_class *fc; | |
da1cc671 PP |
285 | int ret; |
286 | ||
9e550e5f | 287 | packet_header_type = bt_private_field_class_structure_create(); |
b8f13b8b | 288 | BT_ASSERT(packet_header_type); |
9e550e5f | 289 | fc = bt_private_field_class_unsigned_integer_create(); |
939190b3 | 290 | BT_ASSERT(fc); |
9e550e5f | 291 | ret = bt_private_field_class_integer_set_field_value_range(fc, 32); |
7b33a0e0 | 292 | BT_ASSERT(ret == 0); |
96854e6a | 293 | ret = bt_private_field_class_structure_append_member(packet_header_type, |
939190b3 | 294 | "stream_id", fc); |
b8f13b8b | 295 | BT_ASSERT(ret == 0); |
8138bfe1 | 296 | bt_object_put_ref(fc); |
96854e6a | 297 | ret = bt_private_trace_set_packet_header_field_class(trace, |
da1cc671 | 298 | packet_header_type); |
b8f13b8b | 299 | BT_ASSERT(ret == 0); |
da1cc671 | 300 | |
8138bfe1 | 301 | bt_object_put_ref(packet_header_type); |
da1cc671 PP |
302 | } |
303 | ||
9e550e5f | 304 | static struct bt_private_trace *create_tc1(void) |
c9b3f44b | 305 | { |
9e550e5f | 306 | struct bt_private_trace *tc1 = NULL; |
c9b3f44b | 307 | |
9e550e5f | 308 | tc1 = bt_private_trace_create(); |
7b33a0e0 | 309 | BT_ASSERT(tc1); |
da1cc671 | 310 | set_trace_packet_header(tc1); |
7b33a0e0 PP |
311 | create_sc1(tc1); |
312 | create_sc2(tc1); | |
c9b3f44b | 313 | return tc1; |
c9b3f44b JG |
314 | } |
315 | ||
9e550e5f PP |
316 | static void init_weak_refs(struct bt_private_trace *tc, |
317 | struct bt_private_trace **tc1, | |
318 | struct bt_private_stream_class **sc1, | |
319 | struct bt_private_stream_class **sc2, | |
320 | struct bt_private_event_class **ec1, | |
321 | struct bt_private_event_class **ec2, | |
322 | struct bt_private_event_class **ec3) | |
c9b3f44b JG |
323 | { |
324 | *tc1 = tc; | |
96854e6a PP |
325 | *sc1 = bt_private_trace_borrow_stream_class_by_index(tc, 0); |
326 | *sc2 = bt_private_trace_borrow_stream_class_by_index(tc, 1); | |
327 | *ec1 = bt_private_stream_class_borrow_event_class_by_index(*sc1, 0); | |
328 | *ec2 = bt_private_stream_class_borrow_event_class_by_index(*sc1, 1); | |
329 | *ec3 = bt_private_stream_class_borrow_event_class_by_index(*sc2, 0); | |
c9b3f44b JG |
330 | } |
331 | ||
6271743c | 332 | static void test_example_scenario(void) |
c9b3f44b | 333 | { |
108b91d0 PP |
334 | /* |
335 | * Weak pointers to trace IR objects are to be used very | |
336 | * carefully. This is NOT a good practice and is strongly | |
337 | * discouraged; this is only done to facilitate the validation | |
338 | * of expected reference counts without affecting them by taking | |
339 | * "real" references to the objects. | |
c9b3f44b | 340 | */ |
9e550e5f PP |
341 | struct bt_private_trace *tc1 = NULL, *weak_tc1 = NULL; |
342 | struct bt_private_stream_class *weak_sc1 = NULL, *weak_sc2 = NULL; | |
343 | struct bt_private_event_class *weak_ec1 = NULL, *weak_ec2 = NULL, | |
c9b3f44b JG |
344 | *weak_ec3 = NULL; |
345 | struct user user_a = { 0 }, user_b = { 0 }, user_c = { 0 }; | |
346 | ||
347 | /* The only reference which exists at this point is on TC1. */ | |
348 | tc1 = create_tc1(); | |
27f4d205 | 349 | ok(tc1, "Initialize trace"); |
7b33a0e0 | 350 | BT_ASSERT(tc1); |
c9b3f44b JG |
351 | init_weak_refs(tc1, &weak_tc1, &weak_sc1, &weak_sc2, &weak_ec1, |
352 | &weak_ec2, &weak_ec3); | |
1d7bf349 | 353 | ok(bt_object_get_ref_count((void *) weak_sc1) == 0, |
c9b3f44b | 354 | "Initial SC1 reference count is 0"); |
1d7bf349 | 355 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 356 | "Initial SC2 reference count is 0"); |
1d7bf349 | 357 | ok(bt_object_get_ref_count((void *) weak_ec1) == 0, |
c9b3f44b | 358 | "Initial EC1 reference count is 0"); |
1d7bf349 | 359 | ok(bt_object_get_ref_count((void *) weak_ec2) == 0, |
c9b3f44b | 360 | "Initial EC2 reference count is 0"); |
1d7bf349 | 361 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b JG |
362 | "Initial EC3 reference count is 0"); |
363 | ||
364 | /* User A has ownership of the trace. */ | |
8138bfe1 | 365 | BT_OBJECT_MOVE_REF(user_a.tc, tc1); |
1d7bf349 | 366 | ok(bt_object_get_ref_count((void *) user_a.tc) == 1, |
c9b3f44b JG |
367 | "TC1 reference count is 1"); |
368 | ||
369 | /* User A acquires a reference to SC2 from TC1. */ | |
9e550e5f | 370 | user_a.sc = bt_object_get_ref( |
96854e6a | 371 | bt_private_trace_borrow_stream_class_by_index( |
9e550e5f | 372 | user_a.tc, 1)); |
c9b3f44b | 373 | ok(user_a.sc, "User A acquires SC2 from TC1"); |
1d7bf349 | 374 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 375 | "TC1 reference count is 2"); |
1d7bf349 | 376 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b JG |
377 | "SC2 reference count is 1"); |
378 | ||
379 | /* User A acquires a reference to EC3 from SC2. */ | |
8138bfe1 | 380 | user_a.ec = bt_object_get_ref( |
96854e6a | 381 | bt_private_stream_class_borrow_event_class_by_index( |
9e550e5f | 382 | user_a.sc, 0)); |
c9b3f44b | 383 | ok(user_a.ec, "User A acquires EC3 from SC2"); |
1d7bf349 | 384 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 385 | "TC1 reference count is 2"); |
1d7bf349 | 386 | ok(bt_object_get_ref_count((void *) weak_sc2) == 2, |
c9b3f44b | 387 | "SC2 reference count is 2"); |
1d7bf349 | 388 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
389 | "EC3 reference count is 1"); |
390 | ||
391 | /* User A releases its reference to SC2. */ | |
392 | diag("User A releases SC2"); | |
8138bfe1 | 393 | BT_OBJECT_PUT_REF_AND_RESET(user_a.sc); |
c9b3f44b JG |
394 | /* |
395 | * We keep the pointer to SC2 around to validate its reference | |
396 | * count. | |
397 | */ | |
1d7bf349 | 398 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 399 | "TC1 reference count is 2"); |
1d7bf349 | 400 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b | 401 | "SC2 reference count is 1"); |
1d7bf349 | 402 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
403 | "EC3 reference count is 1"); |
404 | ||
405 | /* User A releases its reference to TC1. */ | |
406 | diag("User A releases TC1"); | |
8138bfe1 | 407 | BT_OBJECT_PUT_REF_AND_RESET(user_a.tc); |
c9b3f44b JG |
408 | /* |
409 | * We keep the pointer to TC1 around to validate its reference | |
410 | * count. | |
411 | */ | |
1d7bf349 | 412 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b | 413 | "TC1 reference count is 1"); |
1d7bf349 | 414 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b | 415 | "SC2 reference count is 1"); |
1d7bf349 | 416 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
417 | "EC3 reference count is 1"); |
418 | ||
419 | /* User B acquires a reference to SC1. */ | |
420 | diag("User B acquires a reference to SC1"); | |
8138bfe1 | 421 | user_b.sc = bt_object_get_ref(weak_sc1); |
1d7bf349 | 422 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 423 | "TC1 reference count is 2"); |
1d7bf349 | 424 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b JG |
425 | "SC1 reference count is 1"); |
426 | ||
427 | /* User C acquires a reference to EC1. */ | |
428 | diag("User C acquires a reference to EC1"); | |
8138bfe1 | 429 | user_c.ec = bt_object_get_ref( |
96854e6a | 430 | bt_private_stream_class_borrow_event_class_by_index( |
9e550e5f | 431 | user_b.sc, 0)); |
1d7bf349 | 432 | ok(bt_object_get_ref_count((void *) weak_ec1) == 1, |
c9b3f44b | 433 | "EC1 reference count is 1"); |
1d7bf349 | 434 | ok(bt_object_get_ref_count((void *) weak_sc1) == 2, |
c9b3f44b JG |
435 | "SC1 reference count is 2"); |
436 | ||
437 | /* User A releases its reference on EC3. */ | |
438 | diag("User A releases its reference on EC3"); | |
8138bfe1 | 439 | BT_OBJECT_PUT_REF_AND_RESET(user_a.ec); |
1d7bf349 | 440 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b | 441 | "EC3 reference count is 1"); |
1d7bf349 | 442 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 443 | "SC2 reference count is 0"); |
1d7bf349 | 444 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b JG |
445 | "TC1 reference count is 1"); |
446 | ||
447 | /* User B releases its reference on SC1. */ | |
448 | diag("User B releases its reference on SC1"); | |
8138bfe1 | 449 | BT_OBJECT_PUT_REF_AND_RESET(user_b.sc); |
1d7bf349 | 450 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b JG |
451 | "SC1 reference count is 1"); |
452 | ||
453 | /* | |
454 | * User C is the sole owner of an object and is keeping the whole | |
455 | * trace hierarchy "alive" by holding a reference to EC1. | |
456 | */ | |
1d7bf349 | 457 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b | 458 | "TC1 reference count is 1"); |
1d7bf349 | 459 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b | 460 | "SC1 reference count is 1"); |
1d7bf349 | 461 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 462 | "SC2 reference count is 0"); |
1d7bf349 | 463 | ok(bt_object_get_ref_count((void *) weak_ec1) == 1, |
c9b3f44b | 464 | "EC1 reference count is 1"); |
1d7bf349 | 465 | ok(bt_object_get_ref_count((void *) weak_ec2) == 0, |
c9b3f44b | 466 | "EC2 reference count is 0"); |
1d7bf349 | 467 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b JG |
468 | "EC3 reference count is 0"); |
469 | ||
470 | /* Reclaim last reference held by User C. */ | |
8138bfe1 | 471 | BT_OBJECT_PUT_REF_AND_RESET(user_c.ec); |
6271743c PP |
472 | } |
473 | ||
8deee039 | 474 | static void create_writer_user_full(struct writer_user *user) |
6271743c | 475 | { |
9d6b510b | 476 | gchar *trace_path; |
8deee039 PP |
477 | struct bt_ctf_field_type *ft; |
478 | struct bt_ctf_field *field; | |
6271743c PP |
479 | struct bt_ctf_clock *clock; |
480 | int ret; | |
481 | ||
9d6b510b | 482 | trace_path = g_build_filename(g_get_tmp_dir(), "ctfwriter_XXXXXX", NULL); |
6271743c PP |
483 | if (!bt_mkdtemp(trace_path)) { |
484 | perror("# perror"); | |
485 | } | |
486 | ||
487 | user->writer = bt_ctf_writer_create(trace_path); | |
b8f13b8b | 488 | BT_ASSERT(user->writer); |
dc3fffef | 489 | ret = bt_ctf_writer_set_byte_order(user->writer, |
8deee039 | 490 | BT_CTF_BYTE_ORDER_LITTLE_ENDIAN); |
b8f13b8b | 491 | BT_ASSERT(ret == 0); |
6271743c | 492 | user->tc = bt_ctf_writer_get_trace(user->writer); |
b8f13b8b | 493 | BT_ASSERT(user->tc); |
8deee039 | 494 | user->sc = bt_ctf_stream_class_create("sc"); |
b8f13b8b | 495 | BT_ASSERT(user->sc); |
6271743c | 496 | clock = bt_ctf_clock_create("the_clock"); |
b8f13b8b | 497 | BT_ASSERT(clock); |
81582b6b | 498 | ret = bt_ctf_writer_add_clock(user->writer, clock); |
b8f13b8b | 499 | BT_ASSERT(!ret); |
8deee039 | 500 | ret = bt_ctf_stream_class_set_clock(user->sc, clock); |
b8f13b8b | 501 | BT_ASSERT(!ret); |
8138bfe1 | 502 | BT_OBJECT_PUT_REF_AND_RESET(clock); |
6271743c | 503 | user->stream = bt_ctf_writer_create_stream(user->writer, user->sc); |
b8f13b8b | 504 | BT_ASSERT(user->stream); |
8deee039 | 505 | user->ec = bt_ctf_event_class_create("ec"); |
b8f13b8b | 506 | BT_ASSERT(user->ec); |
8deee039 | 507 | ft = create_writer_integer_struct(); |
b8f13b8b | 508 | BT_ASSERT(ft); |
8deee039 | 509 | ret = bt_ctf_event_class_set_payload_field_type(user->ec, ft); |
8138bfe1 | 510 | BT_OBJECT_PUT_REF_AND_RESET(ft); |
b8f13b8b | 511 | BT_ASSERT(!ret); |
8deee039 | 512 | ret = bt_ctf_stream_class_add_event_class(user->sc, user->ec); |
b8f13b8b | 513 | BT_ASSERT(!ret); |
8deee039 | 514 | user->event = bt_ctf_event_create(user->ec); |
b8f13b8b | 515 | BT_ASSERT(user->event); |
8deee039 | 516 | field = bt_ctf_event_get_payload(user->event, "payload_8"); |
b8f13b8b | 517 | BT_ASSERT(field); |
8deee039 | 518 | ret = bt_ctf_field_integer_unsigned_set_value(field, 10); |
b8f13b8b | 519 | BT_ASSERT(!ret); |
8138bfe1 | 520 | BT_OBJECT_PUT_REF_AND_RESET(field); |
8deee039 | 521 | field = bt_ctf_event_get_payload(user->event, "payload_16"); |
b8f13b8b | 522 | BT_ASSERT(field); |
8deee039 | 523 | ret = bt_ctf_field_integer_unsigned_set_value(field, 20); |
b8f13b8b | 524 | BT_ASSERT(!ret); |
8138bfe1 | 525 | BT_OBJECT_PUT_REF_AND_RESET(field); |
8deee039 | 526 | field = bt_ctf_event_get_payload(user->event, "payload_32"); |
b8f13b8b | 527 | BT_ASSERT(field); |
8deee039 | 528 | ret = bt_ctf_field_integer_unsigned_set_value(field, 30); |
b8f13b8b | 529 | BT_ASSERT(!ret); |
8138bfe1 | 530 | BT_OBJECT_PUT_REF_AND_RESET(field); |
8deee039 | 531 | ret = bt_ctf_stream_append_event(user->stream, user->event); |
b8f13b8b | 532 | BT_ASSERT(!ret); |
851299b9 | 533 | recursive_rmdir(trace_path); |
9d6b510b | 534 | g_free(trace_path); |
6271743c PP |
535 | } |
536 | ||
537 | static void test_put_order_swap(size_t *array, size_t a, size_t b) | |
538 | { | |
539 | size_t temp = array[a]; | |
540 | ||
541 | array[a] = array[b]; | |
542 | array[b] = temp; | |
543 | } | |
544 | ||
545 | static void test_put_order_put_objects(size_t *array, size_t size) | |
546 | { | |
547 | size_t i; | |
8deee039 | 548 | struct writer_user user = { 0 }; |
6f2097e2 | 549 | void **objects = (void *) &user; |
6271743c | 550 | |
8deee039 | 551 | create_writer_user_full(&user); |
6271743c PP |
552 | printf("# "); |
553 | ||
554 | for (i = 0; i < size; ++i) { | |
6f2097e2 | 555 | void *obj = objects[array[i]]; |
6271743c | 556 | |
8deee039 | 557 | printf("%s", writer_user_names[array[i]]); |
8138bfe1 | 558 | BT_OBJECT_PUT_REF_AND_RESET(obj); |
6271743c PP |
559 | |
560 | if (i < size - 1) { | |
561 | printf(" -> "); | |
562 | } | |
563 | } | |
564 | ||
565 | puts(""); | |
566 | } | |
567 | ||
568 | static void test_put_order_permute(size_t *array, int k, size_t size) | |
569 | { | |
570 | if (k == 0) { | |
571 | test_put_order_put_objects(array, size); | |
572 | } else { | |
573 | int i; | |
574 | ||
575 | for (i = k - 1; i >= 0; i--) { | |
576 | size_t next_k = k - 1; | |
577 | ||
578 | test_put_order_swap(array, i, next_k); | |
579 | test_put_order_permute(array, next_k, size); | |
580 | test_put_order_swap(array, i, next_k); | |
581 | } | |
582 | } | |
583 | } | |
584 | ||
585 | static void test_put_order(void) | |
586 | { | |
587 | size_t i; | |
8deee039 | 588 | size_t array[WRITER_USER_NR_ELEMENTS]; |
6271743c PP |
589 | |
590 | /* Initialize array of indexes */ | |
8deee039 | 591 | for (i = 0; i < WRITER_USER_NR_ELEMENTS; ++i) { |
6271743c PP |
592 | array[i] = i; |
593 | } | |
594 | ||
8deee039 PP |
595 | test_put_order_permute(array, WRITER_USER_NR_ELEMENTS, |
596 | WRITER_USER_NR_ELEMENTS); | |
6271743c PP |
597 | } |
598 | ||
599 | /** | |
600 | * The objective of this test is to implement and expand upon the scenario | |
601 | * described in the reference counting documentation and ensure that any node of | |
602 | * the Trace, Stream Class, Event Class, Stream and Event hiearchy keeps all | |
603 | * other "alive" and reachable. | |
604 | * | |
605 | * External tools (e.g. valgrind) should be used to confirm that this | |
606 | * known-good test does not leak memory. | |
607 | */ | |
608 | int main(int argc, char **argv) | |
609 | { | |
27f4d205 | 610 | /* Initialize tap harness before any tests */ |
6271743c PP |
611 | plan_tests(NR_TESTS); |
612 | ||
613 | test_example_scenario(); | |
614 | test_put_order(); | |
615 | ||
c9b3f44b JG |
616 | return exit_status(); |
617 | } |