Commit | Line | Data |
---|---|---|
c9b3f44b | 1 | /* |
56e18c4c | 2 | * test_trace_ir_ref.c |
c9b3f44b | 3 | * |
56e18c4c | 4 | * Trace IR Reference Count test |
c9b3f44b JG |
5 | * |
6 | * Copyright 2016 - Jérémie Galarneau <jeremie.galarneau@efficios.com> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License as published by | |
10 | * the Free Software Foundation; under version 2 of the License. | |
11 | * | |
12 | * This program is distributed in the hope that it will be useful, | |
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | * GNU General Public License for more details. | |
16 | * | |
17 | * You should have received a copy of the GNU General Public License along | |
18 | * with this program; if not, write to the Free Software Foundation, Inc., | |
19 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
20 | */ | |
21 | ||
22 | #include "tap/tap.h" | |
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> | |
56e18c4c PP |
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> | |
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 | |
44c440bc | 42 | #define NR_TESTS 37 |
8bbe269d | 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(); |
44c440bc PP |
86 | BT_ASSERT(structure); |
87 | ui8 = bt_field_type_unsigned_integer_create(); | |
88 | BT_ASSERT(ui8); | |
89 | ret = bt_field_type_integer_set_field_value_range(ui8, 8); | |
90 | BT_ASSERT(ret == 0); | |
91 | ret = bt_field_type_structure_append_member(structure, | |
92 | "payload_8", ui8); | |
93 | BT_ASSERT(ret == 0); | |
94 | ui16 = bt_field_type_unsigned_integer_create(); | |
95 | BT_ASSERT(ui16); | |
96 | ret = bt_field_type_integer_set_field_value_range(ui16, 16); | |
97 | BT_ASSERT(ret == 0); | |
98 | ret = bt_field_type_structure_append_member(structure, | |
99 | "payload_16", ui16); | |
100 | BT_ASSERT(ret == 0); | |
101 | ui32 = bt_field_type_unsigned_integer_create(); | |
102 | BT_ASSERT(ui32); | |
103 | ret = bt_field_type_integer_set_field_value_range(ui32, 32); | |
104 | BT_ASSERT(ret == 0); | |
105 | ret = bt_field_type_structure_append_member(structure, | |
106 | "payload_32", ui32); | |
107 | BT_ASSERT(ret == 0); | |
c9b3f44b JG |
108 | BT_PUT(ui8); |
109 | BT_PUT(ui16); | |
110 | BT_PUT(ui32); | |
111 | return structure; | |
c9b3f44b JG |
112 | } |
113 | ||
3dca2276 PP |
114 | static struct bt_ctf_field_type *create_writer_integer_struct(void) |
115 | { | |
116 | int ret; | |
117 | struct bt_ctf_field_type *structure = NULL; | |
118 | struct bt_ctf_field_type *ui8 = NULL, *ui16 = NULL, *ui32 = NULL; | |
119 | ||
120 | structure = bt_ctf_field_type_structure_create(); | |
44c440bc | 121 | BT_ASSERT(structure); |
3dca2276 | 122 | ui8 = bt_ctf_field_type_integer_create(8); |
44c440bc | 123 | BT_ASSERT(ui8); |
3dca2276 PP |
124 | ret = bt_ctf_field_type_structure_add_field(structure, ui8, |
125 | "payload_8"); | |
44c440bc | 126 | BT_ASSERT(ret == 0); |
3dca2276 | 127 | ui16 = bt_ctf_field_type_integer_create(16); |
44c440bc | 128 | BT_ASSERT(ui16); |
3dca2276 PP |
129 | ret = bt_ctf_field_type_structure_add_field(structure, ui16, |
130 | "payload_16"); | |
44c440bc | 131 | BT_ASSERT(ret == 0); |
3dca2276 | 132 | ui32 = bt_ctf_field_type_integer_create(32); |
44c440bc | 133 | BT_ASSERT(ui32); |
3dca2276 PP |
134 | ret = bt_ctf_field_type_structure_add_field(structure, ui32, |
135 | "payload_32"); | |
44c440bc | 136 | BT_ASSERT(ret == 0); |
3dca2276 PP |
137 | BT_PUT(ui8); |
138 | BT_PUT(ui16); | |
139 | BT_PUT(ui32); | |
140 | return structure; | |
3dca2276 PP |
141 | } |
142 | ||
c9b3f44b JG |
143 | /** |
144 | * A simple event has the following payload: | |
145 | * - uint8_t payload_8; | |
146 | * - uint16_t payload_16; | |
147 | * - uint32_t payload_32; | |
148 | */ | |
44c440bc PP |
149 | static struct bt_event_class *create_simple_event(struct bt_stream_class *sc, |
150 | const char *name) | |
c9b3f44b JG |
151 | { |
152 | int ret; | |
50842bdc PP |
153 | struct bt_event_class *event = NULL; |
154 | struct bt_field_type *payload = NULL; | |
c9b3f44b | 155 | |
25583cd0 | 156 | BT_ASSERT(name); |
44c440bc PP |
157 | event = bt_event_class_create(sc); |
158 | BT_ASSERT(event); | |
159 | ret = bt_event_class_set_name(event, name); | |
160 | BT_ASSERT(ret == 0); | |
c9b3f44b | 161 | payload = create_integer_struct(); |
44c440bc | 162 | BT_ASSERT(payload); |
3dca2276 | 163 | ret = bt_event_class_set_payload_field_type(event, payload); |
44c440bc | 164 | BT_ASSERT(ret == 0); |
c9b3f44b JG |
165 | BT_PUT(payload); |
166 | return event; | |
c9b3f44b JG |
167 | } |
168 | ||
169 | /** | |
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; | |
178 | */ | |
44c440bc PP |
179 | static struct bt_event_class *create_complex_event(struct bt_stream_class *sc, |
180 | const char *name) | |
c9b3f44b JG |
181 | { |
182 | int ret; | |
50842bdc PP |
183 | struct bt_event_class *event = NULL; |
184 | struct bt_field_type *inner = NULL, *outer = NULL; | |
c9b3f44b | 185 | |
25583cd0 | 186 | BT_ASSERT(name); |
44c440bc PP |
187 | event = bt_event_class_create(sc); |
188 | BT_ASSERT(event); | |
189 | ret = bt_event_class_set_name(event, name); | |
190 | BT_ASSERT(ret == 0); | |
27f4d205 | 191 | outer = create_integer_struct(); |
44c440bc | 192 | BT_ASSERT(outer); |
27f4d205 | 193 | inner = create_integer_struct(); |
44c440bc PP |
194 | BT_ASSERT(inner); |
195 | ret = bt_field_type_structure_append_member(outer, | |
196 | "payload_struct", inner); | |
197 | BT_ASSERT(ret == 0); | |
3dca2276 | 198 | ret = bt_event_class_set_payload_field_type(event, outer); |
44c440bc | 199 | BT_ASSERT(ret == 0); |
c9b3f44b JG |
200 | BT_PUT(inner); |
201 | BT_PUT(outer); | |
202 | return event; | |
c9b3f44b JG |
203 | } |
204 | ||
da1cc671 | 205 | static void set_stream_class_field_types( |
50842bdc | 206 | struct bt_stream_class *stream_class) |
da1cc671 | 207 | { |
50842bdc PP |
208 | struct bt_field_type *packet_context_type; |
209 | struct bt_field_type *event_header_type; | |
210 | struct bt_field_type *ft; | |
da1cc671 PP |
211 | int ret; |
212 | ||
50842bdc | 213 | packet_context_type = bt_field_type_structure_create(); |
25583cd0 | 214 | BT_ASSERT(packet_context_type); |
44c440bc | 215 | ft = bt_field_type_unsigned_integer_create(); |
25583cd0 | 216 | BT_ASSERT(ft); |
44c440bc PP |
217 | ret = bt_field_type_integer_set_field_value_range(ft, 32); |
218 | BT_ASSERT(ret == 0); | |
219 | ret = bt_field_type_structure_append_member(packet_context_type, | |
220 | "packet_size", ft); | |
25583cd0 | 221 | BT_ASSERT(ret == 0); |
da1cc671 | 222 | bt_put(ft); |
44c440bc | 223 | ft = bt_field_type_unsigned_integer_create(); |
25583cd0 | 224 | BT_ASSERT(ft); |
44c440bc PP |
225 | ret = bt_field_type_integer_set_field_value_range(ft, 32); |
226 | BT_ASSERT(ret == 0); | |
227 | ret = bt_field_type_structure_append_member(packet_context_type, | |
228 | "content_size", ft); | |
25583cd0 | 229 | BT_ASSERT(ret == 0); |
da1cc671 | 230 | bt_put(ft); |
50842bdc | 231 | event_header_type = bt_field_type_structure_create(); |
25583cd0 | 232 | BT_ASSERT(event_header_type); |
44c440bc | 233 | ft = bt_field_type_unsigned_integer_create(); |
25583cd0 | 234 | BT_ASSERT(ft); |
44c440bc PP |
235 | ret = bt_field_type_integer_set_field_value_range(ft, 32); |
236 | BT_ASSERT(ret == 0); | |
237 | ret = bt_field_type_structure_append_member(event_header_type, | |
238 | "id", ft); | |
25583cd0 | 239 | BT_ASSERT(ret == 0); |
da1cc671 | 240 | bt_put(ft); |
3dca2276 | 241 | ret = bt_stream_class_set_packet_context_field_type(stream_class, |
da1cc671 | 242 | packet_context_type); |
25583cd0 | 243 | BT_ASSERT(ret == 0); |
3dca2276 | 244 | ret = bt_stream_class_set_event_header_field_type(stream_class, |
da1cc671 | 245 | event_header_type); |
25583cd0 | 246 | BT_ASSERT(ret == 0); |
da1cc671 PP |
247 | bt_put(packet_context_type); |
248 | bt_put(event_header_type); | |
249 | } | |
250 | ||
44c440bc | 251 | static void create_sc1(struct bt_trace *trace) |
c9b3f44b JG |
252 | { |
253 | int ret; | |
50842bdc PP |
254 | struct bt_event_class *ec1 = NULL, *ec2 = NULL; |
255 | struct bt_stream_class *sc1 = NULL, *ret_stream = NULL; | |
c9b3f44b | 256 | |
44c440bc PP |
257 | sc1 = bt_stream_class_create(trace); |
258 | BT_ASSERT(sc1); | |
259 | ret = bt_stream_class_set_name(sc1, "sc1"); | |
260 | BT_ASSERT(ret == 0); | |
da1cc671 | 261 | set_stream_class_field_types(sc1); |
44c440bc PP |
262 | ec1 = create_complex_event(sc1, "ec1"); |
263 | BT_ASSERT(ec1); | |
264 | ec2 = create_simple_event(sc1, "ec2"); | |
265 | BT_ASSERT(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"); | |
c9b3f44b JG |
270 | BT_PUT(ec1); |
271 | BT_PUT(ec2); | |
c9b3f44b | 272 | BT_PUT(sc1); |
c9b3f44b JG |
273 | } |
274 | ||
44c440bc | 275 | static void create_sc2(struct bt_trace *trace) |
c9b3f44b JG |
276 | { |
277 | int ret; | |
50842bdc PP |
278 | struct bt_event_class *ec3 = NULL; |
279 | struct bt_stream_class *sc2 = NULL, *ret_stream = NULL; | |
c9b3f44b | 280 | |
44c440bc PP |
281 | sc2 = bt_stream_class_create(trace); |
282 | BT_ASSERT(sc2); | |
283 | ret = bt_stream_class_set_name(sc2, "sc2"); | |
284 | BT_ASSERT(ret == 0); | |
da1cc671 | 285 | set_stream_class_field_types(sc2); |
44c440bc PP |
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"); | |
c9b3f44b | 289 | BT_PUT(ec3); |
c9b3f44b | 290 | BT_PUT(sc2); |
c9b3f44b JG |
291 | } |
292 | ||
50842bdc | 293 | static void set_trace_packet_header(struct bt_trace *trace) |
da1cc671 | 294 | { |
50842bdc PP |
295 | struct bt_field_type *packet_header_type; |
296 | struct bt_field_type *ft; | |
da1cc671 PP |
297 | int ret; |
298 | ||
50842bdc | 299 | packet_header_type = bt_field_type_structure_create(); |
25583cd0 | 300 | BT_ASSERT(packet_header_type); |
44c440bc | 301 | ft = bt_field_type_unsigned_integer_create(); |
25583cd0 | 302 | BT_ASSERT(ft); |
44c440bc PP |
303 | ret = bt_field_type_integer_set_field_value_range(ft, 32); |
304 | BT_ASSERT(ret == 0); | |
305 | ret = bt_field_type_structure_append_member(packet_header_type, | |
306 | "stream_id", ft); | |
25583cd0 | 307 | BT_ASSERT(ret == 0); |
da1cc671 | 308 | bt_put(ft); |
3dca2276 | 309 | ret = bt_trace_set_packet_header_field_type(trace, |
da1cc671 | 310 | packet_header_type); |
25583cd0 | 311 | BT_ASSERT(ret == 0); |
da1cc671 PP |
312 | |
313 | bt_put(packet_header_type); | |
314 | } | |
315 | ||
50842bdc | 316 | static struct bt_trace *create_tc1(void) |
c9b3f44b | 317 | { |
50842bdc | 318 | struct bt_trace *tc1 = NULL; |
c9b3f44b | 319 | |
50842bdc | 320 | tc1 = bt_trace_create(); |
44c440bc | 321 | BT_ASSERT(tc1); |
da1cc671 | 322 | set_trace_packet_header(tc1); |
44c440bc PP |
323 | create_sc1(tc1); |
324 | create_sc2(tc1); | |
c9b3f44b | 325 | return tc1; |
c9b3f44b JG |
326 | } |
327 | ||
50842bdc PP |
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) | |
c9b3f44b JG |
335 | { |
336 | *tc1 = tc; | |
44c440bc PP |
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); | |
c9b3f44b JG |
342 | } |
343 | ||
6271743c | 344 | static void test_example_scenario(void) |
c9b3f44b | 345 | { |
56e18c4c PP |
346 | /* |
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. | |
c9b3f44b | 352 | */ |
50842bdc PP |
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, | |
c9b3f44b JG |
356 | *weak_ec3 = NULL; |
357 | struct user user_a = { 0 }, user_b = { 0 }, user_c = { 0 }; | |
358 | ||
359 | /* The only reference which exists at this point is on TC1. */ | |
360 | tc1 = create_tc1(); | |
27f4d205 | 361 | ok(tc1, "Initialize trace"); |
44c440bc | 362 | BT_ASSERT(tc1); |
c9b3f44b JG |
363 | init_weak_refs(tc1, &weak_tc1, &weak_sc1, &weak_sc2, &weak_ec1, |
364 | &weak_ec2, &weak_ec3); | |
3fea54f6 | 365 | ok(bt_object_get_ref_count((void *) weak_sc1) == 0, |
c9b3f44b | 366 | "Initial SC1 reference count is 0"); |
3fea54f6 | 367 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 368 | "Initial SC2 reference count is 0"); |
3fea54f6 | 369 | ok(bt_object_get_ref_count((void *) weak_ec1) == 0, |
c9b3f44b | 370 | "Initial EC1 reference count is 0"); |
3fea54f6 | 371 | ok(bt_object_get_ref_count((void *) weak_ec2) == 0, |
c9b3f44b | 372 | "Initial EC2 reference count is 0"); |
3fea54f6 | 373 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b JG |
374 | "Initial EC3 reference count is 0"); |
375 | ||
376 | /* User A has ownership of the trace. */ | |
377 | BT_MOVE(user_a.tc, tc1); | |
3fea54f6 | 378 | ok(bt_object_get_ref_count((void *) user_a.tc) == 1, |
c9b3f44b JG |
379 | "TC1 reference count is 1"); |
380 | ||
381 | /* User A acquires a reference to SC2 from TC1. */ | |
44c440bc | 382 | user_a.sc = bt_get(bt_trace_borrow_stream_class_by_index(user_a.tc, 1)); |
c9b3f44b | 383 | ok(user_a.sc, "User A acquires SC2 from TC1"); |
3fea54f6 | 384 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 385 | "TC1 reference count is 2"); |
3fea54f6 | 386 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b JG |
387 | "SC2 reference count is 1"); |
388 | ||
389 | /* User A acquires a reference to EC3 from SC2. */ | |
44c440bc PP |
390 | user_a.ec = bt_get( |
391 | bt_stream_class_borrow_event_class_by_index(user_a.sc, 0)); | |
c9b3f44b | 392 | ok(user_a.ec, "User A acquires EC3 from SC2"); |
3fea54f6 | 393 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 394 | "TC1 reference count is 2"); |
3fea54f6 | 395 | ok(bt_object_get_ref_count((void *) weak_sc2) == 2, |
c9b3f44b | 396 | "SC2 reference count is 2"); |
3fea54f6 | 397 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
398 | "EC3 reference count is 1"); |
399 | ||
400 | /* User A releases its reference to SC2. */ | |
401 | diag("User A releases SC2"); | |
402 | BT_PUT(user_a.sc); | |
403 | /* | |
404 | * We keep the pointer to SC2 around to validate its reference | |
405 | * count. | |
406 | */ | |
3fea54f6 | 407 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 408 | "TC1 reference count is 2"); |
3fea54f6 | 409 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b | 410 | "SC2 reference count is 1"); |
3fea54f6 | 411 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
412 | "EC3 reference count is 1"); |
413 | ||
414 | /* User A releases its reference to TC1. */ | |
415 | diag("User A releases TC1"); | |
27f4d205 | 416 | BT_PUT(user_a.tc); |
c9b3f44b JG |
417 | /* |
418 | * We keep the pointer to TC1 around to validate its reference | |
419 | * count. | |
420 | */ | |
3fea54f6 | 421 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b | 422 | "TC1 reference count is 1"); |
3fea54f6 | 423 | ok(bt_object_get_ref_count((void *) weak_sc2) == 1, |
c9b3f44b | 424 | "SC2 reference count is 1"); |
3fea54f6 | 425 | ok(bt_object_get_ref_count((void *) weak_ec3) == 1, |
c9b3f44b JG |
426 | "EC3 reference count is 1"); |
427 | ||
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); | |
3fea54f6 | 431 | ok(bt_object_get_ref_count((void *) weak_tc1) == 2, |
c9b3f44b | 432 | "TC1 reference count is 2"); |
3fea54f6 | 433 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b JG |
434 | "SC1 reference count is 1"); |
435 | ||
436 | /* User C acquires a reference to EC1. */ | |
437 | diag("User C acquires a reference to EC1"); | |
44c440bc PP |
438 | user_c.ec = bt_get( |
439 | bt_stream_class_borrow_event_class_by_index(user_b.sc, 0)); | |
3fea54f6 | 440 | ok(bt_object_get_ref_count((void *) weak_ec1) == 1, |
c9b3f44b | 441 | "EC1 reference count is 1"); |
3fea54f6 | 442 | ok(bt_object_get_ref_count((void *) weak_sc1) == 2, |
c9b3f44b JG |
443 | "SC1 reference count is 2"); |
444 | ||
445 | /* User A releases its reference on EC3. */ | |
446 | diag("User A releases its reference on EC3"); | |
447 | BT_PUT(user_a.ec); | |
3fea54f6 | 448 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b | 449 | "EC3 reference count is 1"); |
3fea54f6 | 450 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 451 | "SC2 reference count is 0"); |
3fea54f6 | 452 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b JG |
453 | "TC1 reference count is 1"); |
454 | ||
455 | /* User B releases its reference on SC1. */ | |
456 | diag("User B releases its reference on SC1"); | |
457 | BT_PUT(user_b.sc); | |
3fea54f6 | 458 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b JG |
459 | "SC1 reference count is 1"); |
460 | ||
461 | /* | |
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. | |
464 | */ | |
3fea54f6 | 465 | ok(bt_object_get_ref_count((void *) weak_tc1) == 1, |
c9b3f44b | 466 | "TC1 reference count is 1"); |
3fea54f6 | 467 | ok(bt_object_get_ref_count((void *) weak_sc1) == 1, |
c9b3f44b | 468 | "SC1 reference count is 1"); |
3fea54f6 | 469 | ok(bt_object_get_ref_count((void *) weak_sc2) == 0, |
c9b3f44b | 470 | "SC2 reference count is 0"); |
3fea54f6 | 471 | ok(bt_object_get_ref_count((void *) weak_ec1) == 1, |
c9b3f44b | 472 | "EC1 reference count is 1"); |
3fea54f6 | 473 | ok(bt_object_get_ref_count((void *) weak_ec2) == 0, |
c9b3f44b | 474 | "EC2 reference count is 0"); |
3fea54f6 | 475 | ok(bt_object_get_ref_count((void *) weak_ec3) == 0, |
c9b3f44b JG |
476 | "EC3 reference count is 0"); |
477 | ||
478 | /* Reclaim last reference held by User C. */ | |
479 | BT_PUT(user_c.ec); | |
6271743c PP |
480 | } |
481 | ||
3dca2276 | 482 | static void create_writer_user_full(struct writer_user *user) |
6271743c | 483 | { |
32bd47d1 | 484 | gchar *trace_path; |
3dca2276 PP |
485 | struct bt_ctf_field_type *ft; |
486 | struct bt_ctf_field *field; | |
6271743c PP |
487 | struct bt_ctf_clock *clock; |
488 | int ret; | |
489 | ||
32bd47d1 | 490 | trace_path = g_build_filename(g_get_tmp_dir(), "ctfwriter_XXXXXX", NULL); |
6271743c PP |
491 | if (!bt_mkdtemp(trace_path)) { |
492 | perror("# perror"); | |
493 | } | |
494 | ||
495 | user->writer = bt_ctf_writer_create(trace_path); | |
25583cd0 | 496 | BT_ASSERT(user->writer); |
dc3fffef | 497 | ret = bt_ctf_writer_set_byte_order(user->writer, |
3dca2276 | 498 | BT_CTF_BYTE_ORDER_LITTLE_ENDIAN); |
25583cd0 | 499 | BT_ASSERT(ret == 0); |
6271743c | 500 | user->tc = bt_ctf_writer_get_trace(user->writer); |
25583cd0 | 501 | BT_ASSERT(user->tc); |
3dca2276 | 502 | user->sc = bt_ctf_stream_class_create("sc"); |
25583cd0 | 503 | BT_ASSERT(user->sc); |
6271743c | 504 | clock = bt_ctf_clock_create("the_clock"); |
25583cd0 | 505 | BT_ASSERT(clock); |
81582b6b | 506 | ret = bt_ctf_writer_add_clock(user->writer, clock); |
25583cd0 | 507 | BT_ASSERT(!ret); |
3dca2276 | 508 | ret = bt_ctf_stream_class_set_clock(user->sc, clock); |
25583cd0 | 509 | BT_ASSERT(!ret); |
dc3fffef | 510 | BT_PUT(clock); |
6271743c | 511 | user->stream = bt_ctf_writer_create_stream(user->writer, user->sc); |
25583cd0 | 512 | BT_ASSERT(user->stream); |
3dca2276 | 513 | user->ec = bt_ctf_event_class_create("ec"); |
25583cd0 | 514 | BT_ASSERT(user->ec); |
3dca2276 | 515 | ft = create_writer_integer_struct(); |
25583cd0 | 516 | BT_ASSERT(ft); |
3dca2276 | 517 | ret = bt_ctf_event_class_set_payload_field_type(user->ec, ft); |
6271743c | 518 | BT_PUT(ft); |
25583cd0 | 519 | BT_ASSERT(!ret); |
3dca2276 | 520 | ret = bt_ctf_stream_class_add_event_class(user->sc, user->ec); |
25583cd0 | 521 | BT_ASSERT(!ret); |
3dca2276 | 522 | user->event = bt_ctf_event_create(user->ec); |
25583cd0 | 523 | BT_ASSERT(user->event); |
3dca2276 | 524 | field = bt_ctf_event_get_payload(user->event, "payload_8"); |
25583cd0 | 525 | BT_ASSERT(field); |
3dca2276 | 526 | ret = bt_ctf_field_integer_unsigned_set_value(field, 10); |
25583cd0 | 527 | BT_ASSERT(!ret); |
6271743c | 528 | BT_PUT(field); |
3dca2276 | 529 | field = bt_ctf_event_get_payload(user->event, "payload_16"); |
25583cd0 | 530 | BT_ASSERT(field); |
3dca2276 | 531 | ret = bt_ctf_field_integer_unsigned_set_value(field, 20); |
25583cd0 | 532 | BT_ASSERT(!ret); |
6271743c | 533 | BT_PUT(field); |
3dca2276 | 534 | field = bt_ctf_event_get_payload(user->event, "payload_32"); |
25583cd0 | 535 | BT_ASSERT(field); |
3dca2276 | 536 | ret = bt_ctf_field_integer_unsigned_set_value(field, 30); |
25583cd0 | 537 | BT_ASSERT(!ret); |
6271743c | 538 | BT_PUT(field); |
3dca2276 | 539 | ret = bt_ctf_stream_append_event(user->stream, user->event); |
25583cd0 | 540 | BT_ASSERT(!ret); |
851299b9 | 541 | recursive_rmdir(trace_path); |
32bd47d1 | 542 | g_free(trace_path); |
6271743c PP |
543 | } |
544 | ||
545 | static void test_put_order_swap(size_t *array, size_t a, size_t b) | |
546 | { | |
547 | size_t temp = array[a]; | |
548 | ||
549 | array[a] = array[b]; | |
550 | array[b] = temp; | |
551 | } | |
552 | ||
553 | static void test_put_order_put_objects(size_t *array, size_t size) | |
554 | { | |
555 | size_t i; | |
3dca2276 | 556 | struct writer_user user = { 0 }; |
6f2097e2 | 557 | void **objects = (void *) &user; |
6271743c | 558 | |
3dca2276 | 559 | create_writer_user_full(&user); |
6271743c PP |
560 | printf("# "); |
561 | ||
562 | for (i = 0; i < size; ++i) { | |
6f2097e2 | 563 | void *obj = objects[array[i]]; |
6271743c | 564 | |
3dca2276 | 565 | printf("%s", writer_user_names[array[i]]); |
6271743c PP |
566 | BT_PUT(obj); |
567 | ||
568 | if (i < size - 1) { | |
569 | printf(" -> "); | |
570 | } | |
571 | } | |
572 | ||
573 | puts(""); | |
574 | } | |
575 | ||
576 | static void test_put_order_permute(size_t *array, int k, size_t size) | |
577 | { | |
578 | if (k == 0) { | |
579 | test_put_order_put_objects(array, size); | |
580 | } else { | |
581 | int i; | |
582 | ||
583 | for (i = k - 1; i >= 0; i--) { | |
584 | size_t next_k = k - 1; | |
585 | ||
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); | |
589 | } | |
590 | } | |
591 | } | |
592 | ||
593 | static void test_put_order(void) | |
594 | { | |
595 | size_t i; | |
3dca2276 | 596 | size_t array[WRITER_USER_NR_ELEMENTS]; |
6271743c PP |
597 | |
598 | /* Initialize array of indexes */ | |
3dca2276 | 599 | for (i = 0; i < WRITER_USER_NR_ELEMENTS; ++i) { |
6271743c PP |
600 | array[i] = i; |
601 | } | |
602 | ||
3dca2276 PP |
603 | test_put_order_permute(array, WRITER_USER_NR_ELEMENTS, |
604 | WRITER_USER_NR_ELEMENTS); | |
6271743c PP |
605 | } |
606 | ||
607 | /** | |
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. | |
612 | * | |
613 | * External tools (e.g. valgrind) should be used to confirm that this | |
614 | * known-good test does not leak memory. | |
615 | */ | |
616 | int main(int argc, char **argv) | |
617 | { | |
27f4d205 | 618 | /* Initialize tap harness before any tests */ |
6271743c PP |
619 | plan_tests(NR_TESTS); |
620 | ||
621 | test_example_scenario(); | |
622 | test_put_order(); | |
623 | ||
c9b3f44b JG |
624 | return exit_status(); |
625 | } |