Solaris build fix: missing inclusion of endian.h
[babeltrace.git] / tests / lib / test_ctf_ir_ref.c
CommitLineData
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"
23#include <babeltrace/ctf-ir/trace.h>
24#include <babeltrace/ctf-ir/stream-class.h>
25#include <babeltrace/ctf-ir/stream.h>
26#include <babeltrace/ctf-ir/event.h>
272df73e 27#include <babeltrace/ctf-ir/event-class.h>
c9b3f44b
JG
28#include <babeltrace/object-internal.h>
29#include <assert.h>
30
8bbe269d
MJ
31#define NR_TESTS 41
32
c9b3f44b
JG
33struct user {
34 struct bt_ctf_trace *tc;
35 struct bt_ctf_stream_class *sc;
36 struct bt_ctf_event_class *ec;
37};
38
39/**
40 * Returns a structure containing the following fields:
41 * - uint8_t payload_8;
42 * - uint16_t payload_16;
43 * - uint32_t payload_32;
44 */
45static struct bt_ctf_field_type *create_integer_struct(void)
46{
47 int ret;
48 struct bt_ctf_field_type *structure = NULL;
49 struct bt_ctf_field_type *ui8 = NULL, *ui16 = NULL, *ui32 = NULL;
50
51 structure = bt_ctf_field_type_structure_create();
52 if (!structure) {
53 goto error;
54 }
55
56 ui8 = bt_ctf_field_type_integer_create(8);
57 if (!ui8) {
58 diag("Failed to create uint8_t type");
59 goto error;
60 }
61 ret = bt_ctf_field_type_structure_add_field(structure, ui8,
62 "payload_8");
63 if (ret) {
64 diag("Failed to add uint8_t to structure");
65 goto error;
66 }
67 ui16 = bt_ctf_field_type_integer_create(16);
68 if (!ui16) {
69 diag("Failed to create uint16_t type");
70 goto error;
71 }
72 ret = bt_ctf_field_type_structure_add_field(structure, ui16,
73 "payload_16");
74 if (ret) {
75 diag("Failed to add uint16_t to structure");
76 goto error;
77 }
78 ui32 = bt_ctf_field_type_integer_create(32);
79 if (!ui32) {
80 diag("Failed to create uint32_t type");
81 goto error;
82 }
83 ret = bt_ctf_field_type_structure_add_field(structure, ui32,
84 "payload_32");
85 if (ret) {
86 diag("Failed to add uint32_t to structure");
87 goto error;
88 }
89end:
90 BT_PUT(ui8);
91 BT_PUT(ui16);
92 BT_PUT(ui32);
93 return structure;
94error:
95 BT_PUT(structure);
96 goto end;
97}
98
99/**
100 * A simple event has the following payload:
101 * - uint8_t payload_8;
102 * - uint16_t payload_16;
103 * - uint32_t payload_32;
104 */
105static struct bt_ctf_event_class *create_simple_event(const char *name)
106{
107 int ret;
108 struct bt_ctf_event_class *event = NULL;
109 struct bt_ctf_field_type *payload = NULL;
110
111 assert(name);
112 event = bt_ctf_event_class_create(name);
113 if (!event) {
114 diag("Failed to create simple event");
115 goto error;
116 }
117
118 payload = create_integer_struct();
119 if (!payload) {
120 diag("Failed to initialize integer structure");
121 goto error;
122 }
123
124 ret = bt_ctf_event_class_set_payload_type(event, payload);
125 if (ret) {
126 diag("Failed to set simple event payload");
127 goto error;
128 }
129end:
130 BT_PUT(payload);
131 return event;
132error:
133 BT_PUT(event);
134 goto end;;
135}
136
137/**
138 * A complex event has the following payload:
139 * - uint8_t payload_8;
140 * - uint16_t payload_16;
141 * - uint32_t payload_32;
142 * - struct payload_struct:
143 * - uint8_t payload_8;
144 * - uint16_t payload_16;
145 * - uint32_t payload_32;
146 */
147static struct bt_ctf_event_class *create_complex_event(const char *name)
148{
149 int ret;
150 struct bt_ctf_event_class *event = NULL;
151 struct bt_ctf_field_type *inner = NULL, *outer = NULL;
152
153 assert(name);
154 event = bt_ctf_event_class_create(name);
155 if (!event) {
156 diag("Failed to create complex event");
157 goto error;
158 }
159
160 outer = create_integer_struct();
161 if (!outer) {
162 diag("Failed to initialize integer structure");
163 goto error;
164 }
165
166 inner = create_integer_struct();
167 if (!inner) {
168 diag("Failed to initialize integer structure");
169 goto error;
170 }
171
172 ret = bt_ctf_field_type_structure_add_field(outer, inner,
173 "payload_struct");
174 if (ret) {
175 diag("Failed to add inner structure to outer structure");
176 goto error;
177 }
178
179 ret = bt_ctf_event_class_set_payload_type(event, outer);
180 if (ret) {
181 diag("Failed to set complex event payload");
182 goto error;
183 }
184end:
185 BT_PUT(inner);
186 BT_PUT(outer);
187 return event;
188error:
189 BT_PUT(event);
190 goto end;;
191}
192
193static struct bt_ctf_stream_class *create_sc1(void)
194{
195 int ret;
196 struct bt_ctf_event_class *ec1 = NULL, *ec2 = NULL;
197 struct bt_ctf_stream_class *sc1 = NULL, *ret_stream = NULL;
198
199 sc1 = bt_ctf_stream_class_create("sc1");
200 if (!sc1) {
201 diag("Failed to create Stream Class");
202 goto error;
203 }
204
205 ec1 = create_complex_event("ec1");
206 if (!ec1) {
207 diag("Failed to create complex event EC1");
208 goto error;
209 }
210 ret = bt_ctf_stream_class_add_event_class(sc1, ec1);
211 if (ret) {
212 diag("Failed to add EC1 to SC1");
213 goto error;
214 }
215
216 ec2 = create_simple_event("ec2");
217 if (!ec2) {
218 diag("Failed to create simple event EC2");
219 goto error;
220 }
221 ret = bt_ctf_stream_class_add_event_class(sc1, ec2);
222 if (ret) {
223 diag("Failed to add EC1 to SC1");
224 goto error;
225 }
226
227 ret_stream = bt_ctf_event_class_get_stream_class(ec1);
228 ok(ret_stream == sc1, "Get parent stream SC1 from EC1");
229 BT_PUT(ret_stream);
230
231 ret_stream = bt_ctf_event_class_get_stream_class(ec2);
232 ok(ret_stream == sc1, "Get parent stream SC1 from EC2");
233end:
234 BT_PUT(ret_stream);
235 BT_PUT(ec1);
236 BT_PUT(ec2);
237 return sc1;
238error:
239 BT_PUT(sc1);
240 goto end;
241}
242
243static struct bt_ctf_stream_class *create_sc2(void)
244{
245 int ret;
246 struct bt_ctf_event_class *ec3 = NULL;
247 struct bt_ctf_stream_class *sc2 = NULL, *ret_stream = NULL;
248
249 sc2 = bt_ctf_stream_class_create("sc2");
250 if (!sc2) {
251 diag("Failed to create Stream Class");
252 goto error;
253 }
254
255 ec3 = create_simple_event("ec3");
256 if (!ec3) {
257 diag("Failed to create simple event EC3");
258 goto error;
259 }
260 ret = bt_ctf_stream_class_add_event_class(sc2, ec3);
261 if (ret) {
262 diag("Failed to add EC3 to SC2");
263 goto error;
264 }
265
266 ret_stream = bt_ctf_event_class_get_stream_class(ec3);
267 ok(ret_stream == sc2, "Get parent stream SC2 from EC3");
268end:
269 BT_PUT(ret_stream);
270 BT_PUT(ec3);
271 return sc2;
272error:
273 BT_PUT(sc2);
274 goto end;
275}
276
277static struct bt_ctf_trace *create_tc1(void)
278{
279 int ret;
280 struct bt_ctf_trace *tc1 = NULL;
281 struct bt_ctf_stream_class *sc1 = NULL, *sc2 = NULL;
282
283 tc1 = bt_ctf_trace_create();
284 if (!tc1) {
285 diag("bt_ctf_trace_create returned NULL");
286 goto error;
287 }
288
289 sc1 = create_sc1();
290 ok(sc1, "Create SC1");
291 if (!sc1) {
292 goto error;
293 }
294 ret = bt_ctf_trace_add_stream_class(tc1, sc1);
295 ok(!ret, "Add SC1 to TC1");
296 if (ret) {
297 goto error;
298 }
299
300 sc2 = create_sc2();
301 ok(sc2, "Create SC2");
302 if (!sc2) {
303 goto error;
304 }
305 ret = bt_ctf_trace_add_stream_class(tc1, sc2);
306 ok(!ret, "Add SC2 to TC1");
307 if (ret) {
308 goto error;
309 }
310end:
311 BT_PUT(sc1);
312 BT_PUT(sc2);
313 return tc1;
314error:
315 BT_PUT(tc1);
316 goto end;
317}
318
319static void init_weak_refs(struct bt_ctf_trace *tc,
320 struct bt_ctf_trace **tc1,
321 struct bt_ctf_stream_class **sc1,
322 struct bt_ctf_stream_class **sc2,
323 struct bt_ctf_event_class **ec1,
324 struct bt_ctf_event_class **ec2,
325 struct bt_ctf_event_class **ec3)
326{
327 *tc1 = tc;
328 *sc1 = bt_ctf_trace_get_stream_class(tc, 0);
329 *sc2 = bt_ctf_trace_get_stream_class(tc, 1);
330 *ec1 = bt_ctf_stream_class_get_event_class(*sc1, 0);
331 *ec2 = bt_ctf_stream_class_get_event_class(*sc1, 1);
332 *ec3 = bt_ctf_stream_class_get_event_class(*sc2, 0);
333 bt_put(*sc1);
334 bt_put(*sc2);
335 bt_put(*ec1);
336 bt_put(*ec2);
337 bt_put(*ec3);
338}
339
340/**
341 * The objective of this test is to implement and expand upon the scenario
342 * described in the reference counting documentation and ensure that any node of
343 * the Trace, Stream Class, Event Class, Stream and Event hiearchy keeps all
344 * other "alive" and reachable.
345 *
346 * External tools (e.g. valgrind) should be used to confirm that this
347 * known-good test does not leak memory.
348 */
349int main(int argc, char **argv)
350{
351 /**
352 * Weak pointers to CTF-IR objects are to be used very carefully.
353 * This is NOT a good practice and is strongly discouraged; this
354 * is only done to facilitate the validation of expected reference
355 * counts without affecting them by taking "real" references to the
356 * objects.
357 */
358 struct bt_ctf_trace *tc1 = NULL, *weak_tc1 = NULL;
359 struct bt_ctf_stream_class *weak_sc1 = NULL, *weak_sc2 = NULL;
360 struct bt_ctf_event_class *weak_ec1 = NULL, *weak_ec2 = NULL,
361 *weak_ec3 = NULL;
362 struct user user_a = { 0 }, user_b = { 0 }, user_c = { 0 };
363
8bbe269d
MJ
364 /* Initialize tap harness before any tests */
365 plan_tests(NR_TESTS);
366
c9b3f44b
JG
367 /* The only reference which exists at this point is on TC1. */
368 tc1 = create_tc1();
369 ok(tc1, "Initialize trace");
370 if (!tc1) {
371 goto end;
372 }
373
374 init_weak_refs(tc1, &weak_tc1, &weak_sc1, &weak_sc2, &weak_ec1,
375 &weak_ec2, &weak_ec3);
c9b3f44b
JG
376
377 ok(bt_object_get_ref_count(weak_sc1) == 0,
378 "Initial SC1 reference count is 0");
379 ok(bt_object_get_ref_count(weak_sc2) == 0,
380 "Initial SC2 reference count is 0");
381 ok(bt_object_get_ref_count(weak_ec1) == 0,
382 "Initial EC1 reference count is 0");
383 ok(bt_object_get_ref_count(weak_ec2) == 0,
384 "Initial EC2 reference count is 0");
385 ok(bt_object_get_ref_count(weak_ec3) == 0,
386 "Initial EC3 reference count is 0");
387
388 /* User A has ownership of the trace. */
389 BT_MOVE(user_a.tc, tc1);
390 ok(bt_object_get_ref_count(user_a.tc) == 1,
391 "TC1 reference count is 1");
392
393 /* User A acquires a reference to SC2 from TC1. */
394 user_a.sc = bt_ctf_trace_get_stream_class(user_a.tc, 1);
395 ok(user_a.sc, "User A acquires SC2 from TC1");
396 ok(bt_object_get_ref_count(weak_tc1) == 2,
397 "TC1 reference count is 2");
398 ok(bt_object_get_ref_count(weak_sc2) == 1,
399 "SC2 reference count is 1");
400
401 /* User A acquires a reference to EC3 from SC2. */
402 user_a.ec = bt_ctf_stream_class_get_event_class(user_a.sc, 0);
403 ok(user_a.ec, "User A acquires EC3 from SC2");
404 ok(bt_object_get_ref_count(weak_tc1) == 2,
405 "TC1 reference count is 2");
406 ok(bt_object_get_ref_count(weak_sc2) == 2,
407 "SC2 reference count is 2");
408 ok(bt_object_get_ref_count(weak_ec3) == 1,
409 "EC3 reference count is 1");
410
411 /* User A releases its reference to SC2. */
412 diag("User A releases SC2");
413 BT_PUT(user_a.sc);
414 /*
415 * We keep the pointer to SC2 around to validate its reference
416 * count.
417 */
418 ok(bt_object_get_ref_count(weak_tc1) == 2,
419 "TC1 reference count is 2");
420 ok(bt_object_get_ref_count(weak_sc2) == 1,
421 "SC2 reference count is 1");
422 ok(bt_object_get_ref_count(weak_ec3) == 1,
423 "EC3 reference count is 1");
424
425 /* User A releases its reference to TC1. */
426 diag("User A releases TC1");
427 BT_PUT(user_a.tc);
428 /*
429 * We keep the pointer to TC1 around to validate its reference
430 * count.
431 */
432 ok(bt_object_get_ref_count(weak_tc1) == 1,
433 "TC1 reference count is 1");
434 ok(bt_object_get_ref_count(weak_sc2) == 1,
435 "SC2 reference count is 1");
436 ok(bt_object_get_ref_count(weak_ec3) == 1,
437 "EC3 reference count is 1");
438
439 /* User B acquires a reference to SC1. */
440 diag("User B acquires a reference to SC1");
441 user_b.sc = bt_get(weak_sc1);
442 ok(bt_object_get_ref_count(weak_tc1) == 2,
443 "TC1 reference count is 2");
444 ok(bt_object_get_ref_count(weak_sc1) == 1,
445 "SC1 reference count is 1");
446
447 /* User C acquires a reference to EC1. */
448 diag("User C acquires a reference to EC1");
449 user_c.ec = bt_ctf_stream_class_get_event_class(user_b.sc, 0);
450 ok(bt_object_get_ref_count(weak_ec1) == 1,
451 "EC1 reference count is 1");
452 ok(bt_object_get_ref_count(weak_sc1) == 2,
453 "SC1 reference count is 2");
454
455 /* User A releases its reference on EC3. */
456 diag("User A releases its reference on EC3");
457 BT_PUT(user_a.ec);
458 ok(bt_object_get_ref_count(weak_ec3) == 0,
459 "EC3 reference count is 1");
460 ok(bt_object_get_ref_count(weak_sc2) == 0,
461 "SC2 reference count is 0");
462 ok(bt_object_get_ref_count(weak_tc1) == 1,
463 "TC1 reference count is 1");
464
465 /* User B releases its reference on SC1. */
466 diag("User B releases its reference on SC1");
467 BT_PUT(user_b.sc);
468 ok(bt_object_get_ref_count(weak_sc1) == 1,
469 "SC1 reference count is 1");
470
471 /*
472 * User C is the sole owner of an object and is keeping the whole
473 * trace hierarchy "alive" by holding a reference to EC1.
474 */
475 ok(bt_object_get_ref_count(weak_tc1) == 1,
476 "TC1 reference count is 1");
477 ok(bt_object_get_ref_count(weak_sc1) == 1,
478 "SC1 reference count is 1");
479 ok(bt_object_get_ref_count(weak_sc2) == 0,
480 "SC2 reference count is 0");
481 ok(bt_object_get_ref_count(weak_ec1) == 1,
482 "EC1 reference count is 1");
483 ok(bt_object_get_ref_count(weak_ec2) == 0,
484 "EC2 reference count is 0");
485 ok(bt_object_get_ref_count(weak_ec3) == 0,
486 "EC3 reference count is 0");
487
488 /* Reclaim last reference held by User C. */
489 BT_PUT(user_c.ec);
490end:
491 return exit_status();
492}
This page took 0.041806 seconds and 4 git commands to generate.