assert-pre-internal.h: add BT_ASSERT_PRE_VALID_INDEX()
[babeltrace.git] / lib / ctf-ir / trace.c
CommitLineData
bc37ae52
JG
1/*
2 * trace.c
3 *
4 * Babeltrace CTF IR - Trace
5 *
6 * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
e011d2c1
PP
29#define BT_LOG_TAG "TRACE"
30#include <babeltrace/lib-logging-internal.h>
31
3dca2276 32#include <babeltrace/assert-pre-internal.h>
bc37ae52 33#include <babeltrace/ctf-ir/trace-internal.h>
ac0c6bdd 34#include <babeltrace/ctf-ir/clock-class-internal.h>
bc37ae52
JG
35#include <babeltrace/ctf-ir/stream-internal.h>
36#include <babeltrace/ctf-ir/stream-class-internal.h>
09840de5 37#include <babeltrace/ctf-ir/event-internal.h>
272df73e
PP
38#include <babeltrace/ctf-ir/event-class.h>
39#include <babeltrace/ctf-ir/event-class-internal.h>
bc37ae52 40#include <babeltrace/ctf-writer/functor-internal.h>
ac0c6bdd 41#include <babeltrace/ctf-writer/clock-internal.h>
312c056a 42#include <babeltrace/ctf-ir/field-wrapper-internal.h>
2e33ac5a 43#include <babeltrace/ctf-ir/field-types-internal.h>
44e0a4f5 44#include <babeltrace/ctf-ir/attributes-internal.h>
09840de5 45#include <babeltrace/ctf-ir/validation-internal.h>
8bf65fbd 46#include <babeltrace/ctf-ir/visitor-internal.h>
654c1444 47#include <babeltrace/ctf-ir/utils.h>
726106d3 48#include <babeltrace/ctf-ir/utils-internal.h>
3d9990ac 49#include <babeltrace/compiler-internal.h>
dac5c838 50#include <babeltrace/values.h>
95c09b3a 51#include <babeltrace/values-internal.h>
83509119 52#include <babeltrace/ref.h>
c55a9f58 53#include <babeltrace/types.h>
3d9990ac 54#include <babeltrace/endian-internal.h>
f6ccaed9 55#include <babeltrace/assert-internal.h>
dc3fffef 56#include <inttypes.h>
544d0515 57#include <stdint.h>
4a32fda0 58#include <string.h>
0fbb9a9f 59#include <stdlib.h>
bc37ae52
JG
60
61#define DEFAULT_IDENTIFIER_SIZE 128
62#define DEFAULT_METADATA_STRING_SIZE 4096
63
50ad4244 64struct listener_wrapper {
50842bdc 65 bt_listener_cb listener;
2204c381
JG
66 void *data;
67};
68
50842bdc
PP
69struct bt_trace_is_static_listener_elem {
70 bt_trace_is_static_listener func;
71 bt_trace_listener_removed removed;
3602afb0
PP
72 void *data;
73};
74
cb6f1f7d
PP
75static inline
76void bt_trace_finalize(struct bt_trace *trace)
77{
78 BT_LOGD("Finalizing trace object: addr=%p, name=\"%s\"",
79 trace, bt_trace_get_name(trace));
80
81 if (trace->environment) {
82 BT_LOGD_STR("Destroying environment attributes.");
83 bt_attributes_destroy(trace->environment);
84 }
85
86 if (trace->name) {
87 g_string_free(trace->name, TRUE);
88 }
89
90 if (trace->clock_classes) {
91 BT_LOGD_STR("Putting clock classes.");
92 g_ptr_array_free(trace->clock_classes, TRUE);
93 }
94
95 if (trace->streams) {
96 BT_LOGD_STR("Destroying streams.");
97 g_ptr_array_free(trace->streams, TRUE);
98 }
99
100 if (trace->stream_classes) {
101 BT_LOGD_STR("Destroying stream classes.");
102 g_ptr_array_free(trace->stream_classes, TRUE);
103 }
104
105 BT_LOGD_STR("Putting packet header field type.");
106 bt_put(trace->packet_header_field_type);
107}
108
bc37ae52 109static
3dca2276
PP
110void bt_trace_destroy(struct bt_object *obj)
111{
112 struct bt_trace *trace = (void *) obj;
bc37ae52 113
3dca2276
PP
114 BT_LOGD("Destroying trace object: addr=%p, name=\"%s\"",
115 trace, bt_trace_get_name(trace));
bc37ae52 116
3dca2276
PP
117 /*
118 * Call remove listeners first so that everything else still
119 * exists in the trace.
120 */
121 if (trace->is_static_listeners) {
122 size_t i;
bc37ae52 123
3dca2276
PP
124 for (i = 0; i < trace->is_static_listeners->len; i++) {
125 struct bt_trace_is_static_listener_elem elem =
126 g_array_index(trace->is_static_listeners,
127 struct bt_trace_is_static_listener_elem, i);
bc37ae52 128
3dca2276
PP
129 if (elem.removed) {
130 elem.removed(trace, elem.data);
131 }
132 }
133
134 g_array_free(trace->is_static_listeners, TRUE);
bc37ae52
JG
135 }
136
3dca2276
PP
137 if (trace->listeners) {
138 g_ptr_array_free(trace->listeners, TRUE);
139 }
140
312c056a 141 bt_object_pool_finalize(&trace->packet_header_field_pool);
cb6f1f7d 142 bt_trace_finalize(trace);
3dca2276
PP
143 g_free(trace);
144}
145
cb6f1f7d
PP
146static inline
147int bt_trace_initialize(struct bt_trace *trace,
3dca2276
PP
148 bt_object_release_func release_func)
149{
150 int ret = 0;
151
cb6f1f7d 152 BT_LOGD_STR("Initializing trace object.");
50842bdc 153 trace->native_byte_order = BT_BYTE_ORDER_UNSPECIFIED;
3fea54f6 154 bt_object_init_shared_with_parent(&trace->base, release_func);
3dca2276 155 trace->clock_classes = g_ptr_array_new_with_free_func(
83509119 156 (GDestroyNotify) bt_put);
3dca2276 157 if (!trace->clock_classes) {
95c09b3a
PP
158 BT_LOGE_STR("Failed to allocate one GPtrArray.");
159 goto error;
160 }
161
bc37ae52 162 trace->streams = g_ptr_array_new_with_free_func(
3fea54f6 163 (GDestroyNotify) bt_object_try_spec_release);
95c09b3a
PP
164 if (!trace->streams) {
165 BT_LOGE_STR("Failed to allocate one GPtrArray.");
166 goto error;
167 }
168
bc37ae52 169 trace->stream_classes = g_ptr_array_new_with_free_func(
3fea54f6 170 (GDestroyNotify) bt_object_try_spec_release);
95c09b3a
PP
171 if (!trace->stream_classes) {
172 BT_LOGE_STR("Failed to allocate one GPtrArray.");
83509119 173 goto error;
bc37ae52
JG
174 }
175
7f800dc7 176 /* Create the environment array object */
50842bdc 177 trace->environment = bt_attributes_create();
7f800dc7 178 if (!trace->environment) {
95c09b3a 179 BT_LOGE_STR("Cannot create empty attributes object.");
83509119 180 goto error;
7f800dc7
PP
181 }
182
cb6f1f7d 183 BT_LOGD("Initialized trace object: addr=%p", trace);
3dca2276
PP
184 goto end;
185
186error:
187 ret = -1;
188
189end:
190 return ret;
191}
192
312c056a
PP
193static
194void free_packet_header_field(struct bt_field_wrapper *field_wrapper,
195 struct bt_trace *trace)
196{
197 bt_field_wrapper_destroy(field_wrapper);
198}
199
3dca2276
PP
200struct bt_trace *bt_trace_create(void)
201{
202 struct bt_trace *trace = NULL;
203 int ret;
204
205 BT_LOGD_STR("Creating trace object.");
206 trace = g_new0(struct bt_trace, 1);
207 if (!trace) {
208 BT_LOGE_STR("Failed to allocate one trace.");
209 goto error;
210 }
211
cb6f1f7d 212 ret = bt_trace_initialize(trace, bt_trace_destroy);
3dca2276 213 if (ret) {
cb6f1f7d 214 /* bt_trace_initialize() logs errors */
3dca2276
PP
215 goto error;
216 }
217
9b888ff3
JG
218 trace->listeners = g_ptr_array_new_with_free_func(
219 (GDestroyNotify) g_free);
220 if (!trace->listeners) {
95c09b3a 221 BT_LOGE_STR("Failed to allocate one GPtrArray.");
9b888ff3
JG
222 goto error;
223 }
224
3602afb0 225 trace->is_static_listeners = g_array_new(FALSE, TRUE,
50842bdc 226 sizeof(struct bt_trace_is_static_listener_elem));
3602afb0
PP
227 if (!trace->is_static_listeners) {
228 BT_LOGE_STR("Failed to allocate one GArray.");
229 goto error;
230 }
231
312c056a
PP
232 ret = bt_object_pool_initialize(&trace->packet_header_field_pool,
233 (bt_object_pool_new_object_func) bt_field_wrapper_new,
234 (bt_object_pool_destroy_object_func) free_packet_header_field,
235 trace);
236 if (ret) {
237 BT_LOGE("Failed to initialize packet header field pool: ret=%d",
238 ret);
239 goto error;
240 }
241
95c09b3a 242 BT_LOGD("Created trace object: addr=%p", trace);
bc37ae52
JG
243 return trace;
244
bc37ae52 245error:
83509119 246 BT_PUT(trace);
bc37ae52
JG
247 return trace;
248}
249
50842bdc 250const char *bt_trace_get_name(struct bt_trace *trace)
e96045d4 251{
cb6f1f7d
PP
252 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
253 return trace->name ? trace->name->str : NULL;
e96045d4
JG
254}
255
cb6f1f7d 256int bt_trace_set_name(struct bt_trace *trace, const char *name)
e96045d4
JG
257{
258 int ret = 0;
259
95c09b3a
PP
260 if (!trace) {
261 BT_LOGW_STR("Invalid parameter: trace is NULL.");
262 ret = -1;
263 goto end;
264 }
265
266 if (!name) {
267 BT_LOGW_STR("Invalid parameter: name is NULL.");
268 ret = -1;
269 goto end;
270 }
271
272 if (trace->frozen) {
273 BT_LOGW("Invalid parameter: trace is frozen: "
274 "addr=%p, name=\"%s\"",
cb6f1f7d 275 trace, bt_trace_get_name(trace));
e96045d4
JG
276 ret = -1;
277 goto end;
278 }
279
280 trace->name = trace->name ? g_string_assign(trace->name, name) :
281 g_string_new(name);
282 if (!trace->name) {
95c09b3a 283 BT_LOGE_STR("Failed to allocate one GString.");
e96045d4
JG
284 ret = -1;
285 goto end;
286 }
95c09b3a
PP
287
288 BT_LOGV("Set trace's name: addr=%p, name=\"%s\"", trace, name);
289
e96045d4
JG
290end:
291 return ret;
292}
293
50842bdc 294const unsigned char *bt_trace_get_uuid(struct bt_trace *trace)
4a32fda0 295{
cb6f1f7d
PP
296 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
297 return trace->uuid_set ? trace->uuid : NULL;
4a32fda0
PP
298}
299
cb6f1f7d 300int bt_trace_set_uuid(struct bt_trace *trace,
3dca2276 301 const unsigned char *uuid)
4a32fda0
PP
302{
303 int ret = 0;
304
95c09b3a
PP
305 if (!trace) {
306 BT_LOGW_STR("Invalid parameter: trace is NULL.");
307 ret = -1;
308 goto end;
309 }
310
311 if (!uuid) {
312 BT_LOGW_STR("Invalid parameter: UUID is NULL.");
313 ret = -1;
314 goto end;
315 }
316
317 if (trace->frozen) {
318 BT_LOGW("Invalid parameter: trace is frozen: "
319 "addr=%p, name=\"%s\"",
cb6f1f7d 320 trace, bt_trace_get_name(trace));
4a32fda0
PP
321 ret = -1;
322 goto end;
323 }
324
20eee76e 325 memcpy(trace->uuid, uuid, BABELTRACE_UUID_LEN);
c55a9f58 326 trace->uuid_set = BT_TRUE;
95c09b3a
PP
327 BT_LOGV("Set trace's UUID: addr=%p, name=\"%s\", "
328 "uuid=\"%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\"",
cb6f1f7d 329 trace, bt_trace_get_name(trace),
95c09b3a
PP
330 (unsigned int) uuid[0],
331 (unsigned int) uuid[1],
332 (unsigned int) uuid[2],
333 (unsigned int) uuid[3],
334 (unsigned int) uuid[4],
335 (unsigned int) uuid[5],
336 (unsigned int) uuid[6],
337 (unsigned int) uuid[7],
338 (unsigned int) uuid[8],
339 (unsigned int) uuid[9],
340 (unsigned int) uuid[10],
341 (unsigned int) uuid[11],
342 (unsigned int) uuid[12],
343 (unsigned int) uuid[13],
344 (unsigned int) uuid[14],
345 (unsigned int) uuid[15]);
4a32fda0
PP
346
347end:
348 return ret;
349}
350
cb6f1f7d 351int bt_trace_set_environment_field(struct bt_trace *trace,
dac5c838 352 const char *name, struct bt_value *value)
bc37ae52 353{
bc37ae52
JG
354 int ret = 0;
355
95c09b3a
PP
356 if (!trace) {
357 BT_LOGW_STR("Invalid parameter: trace is NULL.");
358 ret = -1;
359 goto end;
360 }
361
362 if (!name) {
363 BT_LOGW_STR("Invalid parameter: name is NULL.");
364 ret = -1;
365 goto end;
366 }
367
368 if (!value) {
369 BT_LOGW_STR("Invalid parameter: value is NULL.");
370 ret = -1;
371 goto end;
372 }
373
cb6f1f7d
PP
374 if (trace->is_static) {
375 BT_LOGW("Invalid parameter: trace is static: "
376 "addr=%p, name=\"%s\"",
377 trace, bt_trace_get_name(trace));
378 ret = -1;
379 goto end;
380 }
381
f4cc9a21 382 if (!bt_identifier_is_valid(name)) {
95c09b3a
PP
383 BT_LOGW("Invalid parameter: environment field's name is not a valid CTF identifier: "
384 "trace-addr=%p, trace-name=\"%s\", "
385 "env-name=\"%s\"",
cb6f1f7d 386 trace, bt_trace_get_name(trace), name);
bc37ae52 387 ret = -1;
7f800dc7 388 goto end;
bc37ae52
JG
389 }
390
95c09b3a
PP
391 if (!bt_value_is_integer(value) && !bt_value_is_string(value)) {
392 BT_LOGW("Invalid parameter: environment field's value is not an integer or string value: "
393 "trace-addr=%p, trace-name=\"%s\", "
394 "env-name=\"%s\", env-value-type=%s",
cb6f1f7d 395 trace, bt_trace_get_name(trace), name,
95c09b3a
PP
396 bt_value_type_string(bt_value_get_type(value)));
397 ret = -1;
398 goto end;
399 }
400
a0d12916
JG
401 if (trace->frozen) {
402 /*
403 * New environment fields may be added to a frozen trace,
404 * but existing fields may not be changed.
405 *
406 * The object passed is frozen like all other attributes.
407 */
dac5c838 408 struct bt_value *attribute =
094ff7c0 409 bt_attributes_borrow_field_value_by_name(
a0d12916
JG
410 trace->environment, name);
411
412 if (attribute) {
95c09b3a
PP
413 BT_LOGW("Invalid parameter: trace is frozen and environment field already exists with this name: "
414 "trace-addr=%p, trace-name=\"%s\", "
415 "env-name=\"%s\"",
cb6f1f7d 416 trace, bt_trace_get_name(trace), name);
a0d12916
JG
417 ret = -1;
418 goto end;
419 }
420
dac5c838 421 bt_value_freeze(value);
a0d12916
JG
422 }
423
50842bdc 424 ret = bt_attributes_set_field_value(trace->environment, name,
7f800dc7 425 value);
95c09b3a
PP
426 if (ret) {
427 BT_LOGE("Cannot set environment field's value: "
428 "trace-addr=%p, trace-name=\"%s\", "
429 "env-name=\"%s\"",
cb6f1f7d 430 trace, bt_trace_get_name(trace), name);
95c09b3a
PP
431 } else {
432 BT_LOGV("Set environment field's value: "
433 "trace-addr=%p, trace-name=\"%s\", "
434 "env-name=\"%s\", value-addr=%p",
cb6f1f7d 435 trace, bt_trace_get_name(trace), name, value);
95c09b3a 436 }
bc37ae52 437
7f800dc7
PP
438end:
439 return ret;
440}
bc37ae52 441
cb6f1f7d 442int bt_trace_set_environment_field_string(struct bt_trace *trace,
7f800dc7
PP
443 const char *name, const char *value)
444{
445 int ret = 0;
dac5c838 446 struct bt_value *env_value_string_obj = NULL;
7f800dc7 447
95c09b3a
PP
448 if (!value) {
449 BT_LOGW_STR("Invalid parameter: value is NULL.");
bc37ae52 450 ret = -1;
7f800dc7 451 goto end;
bc37ae52
JG
452 }
453
dac5c838 454 env_value_string_obj = bt_value_string_create_init(value);
7f800dc7 455 if (!env_value_string_obj) {
95c09b3a 456 BT_LOGE_STR("Cannot create string value object.");
7f800dc7
PP
457 ret = -1;
458 goto end;
bc37ae52
JG
459 }
460
cb6f1f7d
PP
461 /* bt_trace_set_environment_field() logs errors */
462 ret = bt_trace_set_environment_field(trace, name,
7f800dc7
PP
463 env_value_string_obj);
464
465end:
95c09b3a 466 bt_put(env_value_string_obj);
3487c9f3
JG
467 return ret;
468}
469
cb6f1f7d
PP
470int bt_trace_set_environment_field_integer(
471 struct bt_trace *trace, const char *name, int64_t value)
3487c9f3 472{
3487c9f3 473 int ret = 0;
dac5c838 474 struct bt_value *env_value_integer_obj = NULL;
3487c9f3 475
dac5c838 476 env_value_integer_obj = bt_value_integer_create_init(value);
7f800dc7 477 if (!env_value_integer_obj) {
95c09b3a 478 BT_LOGE_STR("Cannot create integer value object.");
3487c9f3 479 ret = -1;
7f800dc7 480 goto end;
3487c9f3
JG
481 }
482
cb6f1f7d
PP
483 /* bt_trace_set_environment_field() logs errors */
484 ret = bt_trace_set_environment_field(trace, name,
7f800dc7 485 env_value_integer_obj);
95c09b3a 486
7f800dc7 487end:
95c09b3a 488 bt_put(env_value_integer_obj);
bc37ae52
JG
489 return ret;
490}
491
3dca2276
PP
492int64_t bt_trace_get_environment_field_count(struct bt_trace *trace)
493{
cb6f1f7d
PP
494 int64_t ret;
495
496 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
497 ret = bt_attributes_get_count(trace->environment);
498 BT_ASSERT(ret >= 0);
499 return ret;
e6fa2160
JG
500}
501
502const char *
50842bdc 503bt_trace_get_environment_field_name_by_index(struct bt_trace *trace,
9ac68eb1 504 uint64_t index)
e6fa2160 505{
cb6f1f7d
PP
506 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
507 return bt_attributes_get_field_name(trace->environment, index);
e6fa2160
JG
508}
509
094ff7c0 510struct bt_value *bt_trace_borrow_environment_field_value_by_index(
50842bdc 511 struct bt_trace *trace, uint64_t index)
e6fa2160 512{
cb6f1f7d
PP
513 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
514 return bt_attributes_borrow_field_value(trace->environment, index);
e6fa2160
JG
515}
516
094ff7c0 517struct bt_value *bt_trace_borrow_environment_field_value_by_name(
50842bdc 518 struct bt_trace *trace, const char *name)
e6fa2160 519{
cb6f1f7d
PP
520 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
521 BT_ASSERT_PRE_NON_NULL(name, "Name");
522 return bt_attributes_borrow_field_value_by_name(trace->environment,
523 name);
e6fa2160
JG
524}
525
cb6f1f7d 526int bt_trace_add_clock_class(struct bt_trace *trace,
50842bdc 527 struct bt_clock_class *clock_class)
bc37ae52
JG
528{
529 int ret = 0;
bc37ae52 530
95c09b3a
PP
531 if (!trace) {
532 BT_LOGW_STR("Invalid parameter: trace is NULL.");
533 ret = -1;
534 goto end;
535 }
536
cb6f1f7d
PP
537 if (trace->is_static) {
538 BT_LOGW("Invalid parameter: trace is static: "
539 "addr=%p, name=\"%s\"",
540 trace, bt_trace_get_name(trace));
541 ret = -1;
542 goto end;
543 }
544
50842bdc 545 if (!bt_clock_class_is_valid(clock_class)) {
95c09b3a
PP
546 BT_LOGW("Invalid parameter: clock class is invalid: "
547 "trace-addr=%p, trace-name=\"%s\", "
548 "clock-class-addr=%p, clock-class-name=\"%s\"",
cb6f1f7d 549 trace, bt_trace_get_name(trace),
50842bdc 550 clock_class, bt_clock_class_get_name(clock_class));
bc37ae52
JG
551 ret = -1;
552 goto end;
553 }
554
ac0c6bdd 555 /* Check for duplicate clock classes */
cb6f1f7d 556 if (bt_trace_has_clock_class(trace, clock_class)) {
95c09b3a
PP
557 BT_LOGW("Invalid parameter: clock class already exists in trace: "
558 "trace-addr=%p, trace-name=\"%s\", "
559 "clock-class-addr=%p, clock-class-name=\"%s\"",
cb6f1f7d 560 trace, bt_trace_get_name(trace),
50842bdc 561 clock_class, bt_clock_class_get_name(clock_class));
bc37ae52
JG
562 ret = -1;
563 goto end;
564 }
565
ac0c6bdd 566 bt_get(clock_class);
3dca2276 567 g_ptr_array_add(trace->clock_classes, clock_class);
cfeb617e 568
6474e016 569 if (trace->frozen) {
95c09b3a 570 BT_LOGV_STR("Freezing added clock class because trace is frozen.");
50842bdc 571 bt_clock_class_freeze(clock_class);
6474e016 572 }
95c09b3a
PP
573
574 BT_LOGV("Added clock class to trace: "
575 "trace-addr=%p, trace-name=\"%s\", "
576 "clock-class-addr=%p, clock-class-name=\"%s\"",
cb6f1f7d 577 trace, bt_trace_get_name(trace),
50842bdc 578 clock_class, bt_clock_class_get_name(clock_class));
95c09b3a 579
bc37ae52
JG
580end:
581 return ret;
582}
583
50842bdc 584int64_t bt_trace_get_clock_class_count(struct bt_trace *trace)
884cd6c3 585{
cb6f1f7d
PP
586 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
587 return trace->clock_classes->len;
884cd6c3
JG
588}
589
094ff7c0 590struct bt_clock_class *bt_trace_borrow_clock_class_by_index(
50842bdc 591 struct bt_trace *trace, uint64_t index)
884cd6c3 592{
cb6f1f7d
PP
593 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
594 BT_ASSERT_PRE(index < trace->clock_classes->len,
595 "Index is out of bounds: index=%" PRIu64 ", "
596 "count=%u",
597 index, trace->clock_classes->len);
598 return g_ptr_array_index(trace->clock_classes, index);
884cd6c3
JG
599}
600
e011d2c1 601static
cb6f1f7d
PP
602bool packet_header_field_type_is_valid(struct bt_trace *trace,
603 struct bt_field_type *packet_header_type)
e011d2c1
PP
604{
605 int ret;
606 bool is_valid = true;
cb6f1f7d 607 struct bt_field_type *field_type = NULL;
e011d2c1
PP
608
609 if (!packet_header_type) {
610 /*
611 * No packet header field type: trace must have only
612 * one stream. At this point the stream class being
613 * added is not part of the trace yet, so we validate
614 * that the trace contains no stream classes yet.
615 */
616 if (trace->stream_classes->len >= 1) {
617 BT_LOGW_STR("Invalid packet header field type: "
618 "packet header field type does not exist but there's more than one stream class in the trace.");
619 goto invalid;
620 }
621
622 /* No packet header field type: valid at this point */
623 goto end;
624 }
625
626 /* Packet header field type, if it exists, must be a structure */
3dca2276 627 if (packet_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
e011d2c1
PP
628 BT_LOGW("Invalid packet header field type: must be a structure field type if it exists: "
629 "ft-addr=%p, ft-id=%s",
630 packet_header_type,
3dca2276 631 bt_common_field_type_id_string(packet_header_type->id));
e011d2c1
PP
632 goto invalid;
633 }
634
635 /*
636 * If there's a `magic` field, it must be a 32-bit unsigned
637 * integer field type. Also it must be the first field of the
638 * packet header field type.
639 */
cb6f1f7d 640 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
641 packet_header_type, "magic");
642 if (field_type) {
643 const char *field_name;
644
3dca2276 645 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
e011d2c1
PP
646 BT_LOGW("Invalid packet header field type: `magic` field must be an integer field type: "
647 "magic-ft-addr=%p, magic-ft-id=%s",
648 field_type,
3dca2276 649 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
650 goto invalid;
651 }
652
cb6f1f7d 653 if (bt_field_type_integer_is_signed(field_type)) {
e011d2c1
PP
654 BT_LOGW("Invalid packet header field type: `magic` field must be an unsigned integer field type: "
655 "magic-ft-addr=%p", field_type);
656 goto invalid;
657 }
658
cb6f1f7d 659 if (bt_field_type_integer_get_size(field_type) != 32) {
e011d2c1
PP
660 BT_LOGW("Invalid packet header field type: `magic` field must be a 32-bit unsigned integer field type: "
661 "magic-ft-addr=%p, magic-ft-size=%u",
662 field_type,
cb6f1f7d 663 bt_field_type_integer_get_size(field_type));
e011d2c1
PP
664 goto invalid;
665 }
666
cb6f1f7d 667 ret = bt_field_type_structure_borrow_field_by_index(
e011d2c1 668 packet_header_type, &field_name, NULL, 0);
f6ccaed9 669 BT_ASSERT(ret == 0);
e011d2c1
PP
670
671 if (strcmp(field_name, "magic") != 0) {
672 BT_LOGW("Invalid packet header field type: `magic` field must be the first field: "
673 "magic-ft-addr=%p, first-field-name=\"%s\"",
674 field_type, field_name);
675 goto invalid;
676 }
e011d2c1
PP
677 }
678
679 /*
680 * If there's a `uuid` field, it must be an array field type of
681 * length 16 with an 8-bit unsigned integer element field type.
682 */
cb6f1f7d 683 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
684 packet_header_type, "uuid");
685 if (field_type) {
cb6f1f7d 686 struct bt_field_type *elem_ft;
e011d2c1 687
3dca2276 688 if (field_type->id != BT_FIELD_TYPE_ID_ARRAY) {
e011d2c1
PP
689 BT_LOGW("Invalid packet header field type: `uuid` field must be an array field type: "
690 "uuid-ft-addr=%p, uuid-ft-id=%s",
691 field_type,
3dca2276 692 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
693 goto invalid;
694 }
695
cb6f1f7d 696 if (bt_field_type_array_get_length(field_type) != 16) {
e011d2c1
PP
697 BT_LOGW("Invalid packet header field type: `uuid` array field type's length must be 16: "
698 "uuid-ft-addr=%p, uuid-ft-length=%" PRId64,
699 field_type,
cb6f1f7d 700 bt_field_type_array_get_length(field_type));
e011d2c1
PP
701 goto invalid;
702 }
703
cb6f1f7d 704 elem_ft = bt_field_type_array_borrow_element_field_type(field_type);
f6ccaed9 705 BT_ASSERT(elem_ft);
e011d2c1 706
3dca2276 707 if (elem_ft->id != BT_FIELD_TYPE_ID_INTEGER) {
e011d2c1
PP
708 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an integer field type: "
709 "elem-ft-addr=%p, elem-ft-id=%s",
710 elem_ft,
3dca2276 711 bt_common_field_type_id_string(elem_ft->id));
e011d2c1
PP
712 goto invalid;
713 }
714
cb6f1f7d 715 if (bt_field_type_integer_is_signed(elem_ft)) {
e011d2c1
PP
716 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an unsigned integer field type: "
717 "elem-ft-addr=%p", elem_ft);
e011d2c1
PP
718 goto invalid;
719 }
720
cb6f1f7d 721 if (bt_field_type_integer_get_size(elem_ft) != 8) {
e011d2c1
PP
722 BT_LOGW("Invalid packet header field type: `uuid` field's element field type must be an 8-bit unsigned integer field type: "
723 "elem-ft-addr=%p, elem-ft-size=%u",
724 elem_ft,
cb6f1f7d 725 bt_field_type_integer_get_size(elem_ft));
e011d2c1
PP
726 goto invalid;
727 }
e011d2c1
PP
728 }
729
730 /*
731 * The `stream_id` field must exist if there's more than one
732 * stream classes in the trace.
733 */
cb6f1f7d 734 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
735 packet_header_type, "stream_id");
736
737 if (!field_type && trace->stream_classes->len >= 1) {
738 BT_LOGW_STR("Invalid packet header field type: "
739 "`stream_id` field does not exist but there's more than one stream class in the trace.");
740 goto invalid;
741 }
742
743 /*
744 * If there's a `stream_id` field, it must be an unsigned
745 * integer field type.
746 */
747 if (field_type) {
3dca2276 748 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
e011d2c1
PP
749 BT_LOGW("Invalid packet header field type: `stream_id` field must be an integer field type: "
750 "stream-id-ft-addr=%p, stream-id-ft-id=%s",
751 field_type,
3dca2276 752 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
753 goto invalid;
754 }
755
cb6f1f7d 756 if (bt_field_type_integer_is_signed(field_type)) {
e011d2c1
PP
757 BT_LOGW("Invalid packet header field type: `stream_id` field must be an unsigned integer field type: "
758 "stream-id-ft-addr=%p", field_type);
759 goto invalid;
760 }
e011d2c1
PP
761 }
762
708ab211
PP
763 /*
764 * If there's a `packet_seq_num` field, it must be an unsigned
765 * integer field type.
766 */
cb6f1f7d 767 field_type = bt_field_type_structure_borrow_field_type_by_name(
708ab211
PP
768 packet_header_type, "packet_seq_num");
769 if (field_type) {
3dca2276 770 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
708ab211
PP
771 BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an integer field type: "
772 "stream-id-ft-addr=%p, packet-seq-num-ft-id=%s",
773 field_type,
3dca2276 774 bt_common_field_type_id_string(field_type->id));
708ab211
PP
775 goto invalid;
776 }
777
cb6f1f7d 778 if (bt_field_type_integer_is_signed(field_type)) {
708ab211
PP
779 BT_LOGW("Invalid packet header field type: `packet_seq_num` field must be an unsigned integer field type: "
780 "packet-seq-num-ft-addr=%p", field_type);
781 goto invalid;
782 }
708ab211
PP
783 }
784
e011d2c1
PP
785 goto end;
786
787invalid:
788 is_valid = false;
789
790end:
e011d2c1
PP
791 return is_valid;
792}
793
794static
cb6f1f7d
PP
795bool packet_context_field_type_is_valid(struct bt_trace *trace,
796 struct bt_stream_class *stream_class,
797 struct bt_field_type *packet_context_type,
3dca2276 798 bool check_ts_begin_end_mapped)
e011d2c1
PP
799{
800 bool is_valid = true;
cb6f1f7d 801 struct bt_field_type *field_type = NULL;
e011d2c1
PP
802
803 if (!packet_context_type) {
804 /* No packet context field type: valid at this point */
805 goto end;
806 }
807
808 /* Packet context field type, if it exists, must be a structure */
3dca2276 809 if (packet_context_type->id != BT_FIELD_TYPE_ID_STRUCT) {
e011d2c1
PP
810 BT_LOGW("Invalid packet context field type: must be a structure field type if it exists: "
811 "ft-addr=%p, ft-id=%s",
812 packet_context_type,
3dca2276 813 bt_common_field_type_id_string(packet_context_type->id));
e011d2c1
PP
814 goto invalid;
815 }
816
817 /*
818 * If there's a `packet_size` field, it must be an unsigned
819 * integer field type.
820 */
cb6f1f7d 821 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
822 packet_context_type, "packet_size");
823 if (field_type) {
3dca2276 824 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
e011d2c1
PP
825 BT_LOGW("Invalid packet context field type: `packet_size` field must be an integer field type: "
826 "packet-size-ft-addr=%p, packet-size-ft-id=%s",
827 field_type,
3dca2276 828 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
829 goto invalid;
830 }
831
cb6f1f7d 832 if (bt_field_type_integer_is_signed(field_type)) {
e011d2c1
PP
833 BT_LOGW("Invalid packet context field type: `packet_size` field must be an unsigned integer field type: "
834 "packet-size-ft-addr=%p", field_type);
835 goto invalid;
836 }
e011d2c1
PP
837 }
838
839 /*
840 * If there's a `content_size` field, it must be an unsigned
841 * integer field type.
842 */
cb6f1f7d 843 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
844 packet_context_type, "content_size");
845 if (field_type) {
3dca2276 846 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
e011d2c1
PP
847 BT_LOGW("Invalid packet context field type: `content_size` field must be an integer field type: "
848 "content-size-ft-addr=%p, content-size-ft-id=%s",
849 field_type,
3dca2276 850 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
851 goto invalid;
852 }
853
cb6f1f7d 854 if (bt_field_type_integer_is_signed(field_type)) {
e011d2c1
PP
855 BT_LOGW("Invalid packet context field type: `content_size` field must be an unsigned integer field type: "
856 "content-size-ft-addr=%p", field_type);
857 goto invalid;
858 }
e011d2c1
PP
859 }
860
861 /*
862 * If there's a `events_discarded` field, it must be an unsigned
863 * integer field type.
864 */
cb6f1f7d 865 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
866 packet_context_type, "events_discarded");
867 if (field_type) {
3dca2276 868 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
e011d2c1
PP
869 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an integer field type: "
870 "events-discarded-ft-addr=%p, events-discarded-ft-id=%s",
871 field_type,
3dca2276 872 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
873 goto invalid;
874 }
875
cb6f1f7d 876 if (bt_field_type_integer_is_signed(field_type)) {
e011d2c1
PP
877 BT_LOGW("Invalid packet context field type: `events_discarded` field must be an unsigned integer field type: "
878 "events-discarded-ft-addr=%p", field_type);
879 goto invalid;
880 }
e011d2c1
PP
881 }
882
883 /*
884 * If there's a `timestamp_begin` field, it must be an unsigned
885 * integer field type. Also, if the trace is not a CTF writer's
886 * trace, then we cannot automatically set the mapped clock
887 * class of this field, so it must have a mapped clock class.
888 */
cb6f1f7d 889 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
890 packet_context_type, "timestamp_begin");
891 if (field_type) {
3dca2276 892 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
e011d2c1
PP
893 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an integer field type: "
894 "timestamp-begin-ft-addr=%p, timestamp-begin-ft-id=%s",
895 field_type,
3dca2276 896 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
897 goto invalid;
898 }
899
cb6f1f7d 900 if (bt_field_type_integer_is_signed(field_type)) {
e011d2c1
PP
901 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be an unsigned integer field type: "
902 "timestamp-begin-ft-addr=%p", field_type);
903 goto invalid;
904 }
905
3dca2276 906 if (check_ts_begin_end_mapped) {
50842bdc 907 struct bt_clock_class *clock_class =
cb6f1f7d 908 bt_field_type_integer_borrow_mapped_clock_class(
e011d2c1
PP
909 field_type);
910
e011d2c1
PP
911 if (!clock_class) {
912 BT_LOGW("Invalid packet context field type: `timestamp_begin` field must be mapped to a clock class: "
913 "timestamp-begin-ft-addr=%p", field_type);
914 goto invalid;
915 }
916 }
e011d2c1
PP
917 }
918
919 /*
920 * If there's a `timestamp_end` field, it must be an unsigned
921 * integer field type. Also, if the trace is not a CTF writer's
922 * trace, then we cannot automatically set the mapped clock
923 * class of this field, so it must have a mapped clock class.
924 */
cb6f1f7d 925 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
926 packet_context_type, "timestamp_end");
927 if (field_type) {
3dca2276 928 if (field_type->id != BT_FIELD_TYPE_ID_INTEGER) {
e011d2c1
PP
929 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an integer field type: "
930 "timestamp-end-ft-addr=%p, timestamp-end-ft-id=%s",
931 field_type,
3dca2276 932 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
933 goto invalid;
934 }
935
cb6f1f7d 936 if (bt_field_type_integer_is_signed(field_type)) {
e011d2c1
PP
937 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be an unsigned integer field type: "
938 "timestamp-end-ft-addr=%p", field_type);
939 goto invalid;
940 }
941
3dca2276 942 if (check_ts_begin_end_mapped) {
50842bdc 943 struct bt_clock_class *clock_class =
cb6f1f7d 944 bt_field_type_integer_borrow_mapped_clock_class(
e011d2c1
PP
945 field_type);
946
e011d2c1
PP
947 if (!clock_class) {
948 BT_LOGW("Invalid packet context field type: `timestamp_end` field must be mapped to a clock class: "
949 "timestamp-end-ft-addr=%p", field_type);
950 goto invalid;
951 }
952 }
e011d2c1
PP
953 }
954
955 goto end;
956
957invalid:
958 is_valid = false;
959
960end:
e011d2c1
PP
961 return is_valid;
962}
963
964static
cb6f1f7d
PP
965bool event_header_field_type_is_valid(struct bt_trace *trace,
966 struct bt_stream_class *stream_class,
967 struct bt_field_type *event_header_type)
e011d2c1
PP
968{
969 bool is_valid = true;
cb6f1f7d 970 struct bt_field_type *field_type = NULL;
e011d2c1
PP
971
972 /*
973 * We do not validate that the `timestamp` field exists here
974 * because CTF does not require this exact name to be mapped to
975 * a clock class.
976 */
977
978 if (!event_header_type) {
979 /*
980 * No event header field type: stream class must have
981 * only one event class.
982 */
cb6f1f7d 983 if (bt_stream_class_get_event_class_count(stream_class) > 1) {
e011d2c1
PP
984 BT_LOGW_STR("Invalid event header field type: "
985 "event header field type does not exist but there's more than one event class in the stream class.");
986 goto invalid;
987 }
988
989 /* No event header field type: valid at this point */
990 goto end;
991 }
992
993 /* Event header field type, if it exists, must be a structure */
3dca2276 994 if (event_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
e011d2c1
PP
995 BT_LOGW("Invalid event header field type: must be a structure field type if it exists: "
996 "ft-addr=%p, ft-id=%s",
997 event_header_type,
3dca2276 998 bt_common_field_type_id_string(event_header_type->id));
e011d2c1
PP
999 goto invalid;
1000 }
1001
1002 /*
1003 * If there's an `id` field, it must be an unsigned integer
1004 * field type or an enumeration field type with an unsigned
1005 * integer container field type.
1006 */
cb6f1f7d 1007 field_type = bt_field_type_structure_borrow_field_type_by_name(
e011d2c1
PP
1008 event_header_type, "id");
1009 if (field_type) {
cb6f1f7d 1010 struct bt_field_type *int_ft;
e011d2c1 1011
3dca2276 1012 if (field_type->id == BT_FIELD_TYPE_ID_INTEGER) {
094ff7c0 1013 int_ft = field_type;
3dca2276 1014 } else if (field_type->id == BT_FIELD_TYPE_ID_ENUM) {
cb6f1f7d 1015 int_ft = bt_field_type_enumeration_borrow_container_field_type(
e011d2c1
PP
1016 field_type);
1017 } else {
1018 BT_LOGW("Invalid event header field type: `id` field must be an integer or enumeration field type: "
1019 "id-ft-addr=%p, id-ft-id=%s",
1020 field_type,
3dca2276 1021 bt_common_field_type_id_string(field_type->id));
e011d2c1
PP
1022 goto invalid;
1023 }
1024
f6ccaed9 1025 BT_ASSERT(int_ft);
cb6f1f7d 1026 if (bt_field_type_integer_is_signed(int_ft)) {
e011d2c1
PP
1027 BT_LOGW("Invalid event header field type: `id` field must be an unsigned integer or enumeration field type: "
1028 "id-ft-addr=%p", int_ft);
1029 goto invalid;
1030 }
e011d2c1
PP
1031 }
1032
1033 goto end;
1034
1035invalid:
1036 is_valid = false;
1037
1038end:
e011d2c1
PP
1039 return is_valid;
1040}
1041
726106d3 1042static
cb6f1f7d 1043int check_packet_header_type_has_no_clock_class(struct bt_trace *trace)
726106d3
PP
1044{
1045 int ret = 0;
1046
3dca2276 1047 if (trace->packet_header_field_type) {
726106d3
PP
1048 struct bt_clock_class *clock_class = NULL;
1049
cb6f1f7d 1050 ret = bt_field_type_validate_single_clock_class(
3dca2276 1051 trace->packet_header_field_type,
726106d3
PP
1052 &clock_class);
1053 bt_put(clock_class);
1054 if (ret || clock_class) {
1055 BT_LOGW("Trace's packet header field type cannot "
1056 "contain a field type which is mapped to "
1057 "a clock class: "
1058 "trace-addr=%p, trace-name=\"%s\", "
1059 "clock-class-name=\"%s\"",
cb6f1f7d 1060 trace, bt_trace_get_name(trace),
726106d3
PP
1061 clock_class ?
1062 bt_clock_class_get_name(clock_class) :
1063 NULL);
1064 ret = -1;
1065 }
1066 }
1067
1068 return ret;
1069}
1070
cb6f1f7d
PP
1071int bt_trace_add_stream_class(struct bt_trace *trace,
1072 struct bt_stream_class *stream_class)
ef0c4a15 1073{
544d0515
PP
1074 int ret;
1075 int64_t i;
ef0c4a15 1076 int64_t stream_id;
50842bdc
PP
1077 struct bt_validation_output trace_sc_validation_output = { 0 };
1078 struct bt_validation_output *ec_validation_outputs = NULL;
1079 const enum bt_validation_flag trace_sc_validation_flags =
1080 BT_VALIDATION_FLAG_TRACE |
1081 BT_VALIDATION_FLAG_STREAM;
1082 const enum bt_validation_flag ec_validation_flags =
1083 BT_VALIDATION_FLAG_EVENT;
cb6f1f7d
PP
1084 struct bt_field_type *packet_header_type = NULL;
1085 struct bt_field_type *packet_context_type = NULL;
1086 struct bt_field_type *event_header_type = NULL;
1087 struct bt_field_type *stream_event_ctx_type = NULL;
544d0515 1088 int64_t event_class_count;
cb6f1f7d
PP
1089 struct bt_trace *current_parent_trace = NULL;
1090 struct bt_clock_class *expected_clock_class = NULL;
ef0c4a15 1091
95c09b3a
PP
1092 if (!trace) {
1093 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1094 ret = -1;
1095 goto end;
1096 }
1097
cb6f1f7d
PP
1098 if (trace->is_static) {
1099 BT_LOGW_STR("Invalid parameter: trace is static.");
1100 ret = -1;
1101 goto end;
1102 }
1103
95c09b3a
PP
1104 if (!stream_class) {
1105 BT_LOGW_STR("Invalid parameter: stream class is NULL.");
1106 ret = -1;
1107 goto end;
1108 }
1109
95c09b3a
PP
1110 BT_LOGD("Adding stream class to trace: "
1111 "trace-addr=%p, trace-name=\"%s\", "
1112 "stream-class-addr=%p, stream-class-name=\"%s\", "
1113 "stream-class-id=%" PRId64,
cb6f1f7d
PP
1114 trace, bt_trace_get_name(trace),
1115 stream_class, bt_stream_class_get_name(stream_class),
1116 bt_stream_class_get_id(stream_class));
95c09b3a 1117
cb6f1f7d 1118 current_parent_trace = bt_stream_class_borrow_trace(stream_class);
2789e5d9
JG
1119 if (current_parent_trace) {
1120 /* Stream class is already associated to a trace, abort. */
95c09b3a
PP
1121 BT_LOGW("Invalid parameter: stream class is already part of a trace: "
1122 "stream-class-trace-addr=%p, "
1123 "stream-class-trace-name=\"%s\"",
1124 current_parent_trace,
cb6f1f7d 1125 bt_trace_get_name(current_parent_trace));
2789e5d9
JG
1126 ret = -1;
1127 goto end;
1128 }
1129
09840de5 1130 event_class_count =
cb6f1f7d 1131 bt_stream_class_get_event_class_count(stream_class);
f6ccaed9 1132 BT_ASSERT(event_class_count >= 0);
09840de5 1133
2a3ced3c
PP
1134 if (!stream_class->frozen) {
1135 /*
1136 * Stream class is not frozen yet. Validate that the
1137 * stream class contains at most a single clock class
1138 * because the previous
cb6f1f7d 1139 * bt_stream_class_add_event_class() calls did
3dca2276
PP
1140 * not make this validation since the stream class's
1141 * direct field types (packet context, event header,
1142 * event context) could change afterwards. This stream
1143 * class is about to be frozen and those field types
1144 * won't be changed if this function succeeds.
2a3ced3c
PP
1145 *
1146 * At this point we're also sure that the stream class's
1147 * clock, if any, has the same class as the stream
1148 * class's expected clock class, if any. This is why, if
cb6f1f7d 1149 * bt_stream_class_validate_single_clock_class()
2a3ced3c
PP
1150 * succeeds below, the call to
1151 * bt_stream_class_map_clock_class() at the end of this
1152 * function is safe because it maps to the same, single
1153 * clock class.
1154 */
cb6f1f7d 1155 ret = bt_stream_class_validate_single_clock_class(
3dca2276 1156 stream_class, &expected_clock_class);
2a3ced3c
PP
1157 if (ret) {
1158 BT_LOGW("Invalid parameter: stream class or one of its "
1159 "event classes contains a field type which is "
1160 "not recursively mapped to the expected "
1161 "clock class: "
1162 "stream-class-addr=%p, "
1163 "stream-class-id=%" PRId64 ", "
1164 "stream-class-name=\"%s\", "
1165 "expected-clock-class-addr=%p, "
1166 "expected-clock-class-name=\"%s\"",
cb6f1f7d
PP
1167 stream_class, bt_stream_class_get_id(stream_class),
1168 bt_stream_class_get_name(stream_class),
2a3ced3c
PP
1169 expected_clock_class,
1170 expected_clock_class ?
1171 bt_clock_class_get_name(expected_clock_class) :
1172 NULL);
1173 goto end;
1174 }
fe13b5c0
PP
1175 }
1176
726106d3
PP
1177 ret = check_packet_header_type_has_no_clock_class(trace);
1178 if (ret) {
1179 /* check_packet_header_type_has_no_clock_class() logs errors */
1180 goto end;
1181 }
1182
09840de5
PP
1183 /*
1184 * We're about to freeze both the trace and the stream class.
1185 * Also, each event class contained in this stream class are
1186 * already frozen.
1187 *
1188 * This trace, this stream class, and all its event classes
1189 * should be valid at this point.
1190 *
1191 * Validate trace and stream class first, then each event
1192 * class of this stream class can be validated individually.
1193 */
1194 packet_header_type =
cb6f1f7d 1195 bt_trace_borrow_packet_header_field_type(trace);
09840de5 1196 packet_context_type =
cb6f1f7d 1197 bt_stream_class_borrow_packet_context_field_type(stream_class);
09840de5 1198 event_header_type =
cb6f1f7d 1199 bt_stream_class_borrow_event_header_field_type(stream_class);
09840de5 1200 stream_event_ctx_type =
cb6f1f7d 1201 bt_stream_class_borrow_event_context_field_type(stream_class);
95c09b3a
PP
1202
1203 BT_LOGD("Validating trace and stream class field types.");
50842bdc 1204 ret = bt_validate_class_types(trace->environment,
09840de5
PP
1205 packet_header_type, packet_context_type, event_header_type,
1206 stream_event_ctx_type, NULL, NULL, trace->valid,
1207 stream_class->valid, 1, &trace_sc_validation_output,
cb6f1f7d 1208 trace_sc_validation_flags, bt_field_type_copy);
09840de5 1209
2bd7f864 1210 if (ret) {
09840de5
PP
1211 /*
1212 * This means something went wrong during the validation
1213 * process, not that the objects are invalid.
1214 */
95c09b3a
PP
1215 BT_LOGE("Failed to validate trace and stream class field types: "
1216 "ret=%d", ret);
2bd7f864
JG
1217 goto end;
1218 }
1219
09840de5
PP
1220 if ((trace_sc_validation_output.valid_flags &
1221 trace_sc_validation_flags) !=
1222 trace_sc_validation_flags) {
1223 /* Invalid trace/stream class */
95c09b3a
PP
1224 BT_LOGW("Invalid trace or stream class field types: "
1225 "valid-flags=0x%x",
1226 trace_sc_validation_output.valid_flags);
09840de5
PP
1227 ret = -1;
1228 goto end;
1229 }
1230
1231 if (event_class_count > 0) {
50842bdc 1232 ec_validation_outputs = g_new0(struct bt_validation_output,
09840de5
PP
1233 event_class_count);
1234 if (!ec_validation_outputs) {
95c09b3a 1235 BT_LOGE_STR("Failed to allocate one validation output structure.");
09840de5
PP
1236 ret = -1;
1237 goto end;
1238 }
1239 }
1240
1241 /* Validate each event class individually */
6474e016 1242 for (i = 0; i < event_class_count; i++) {
cb6f1f7d
PP
1243 struct bt_event_class *event_class =
1244 bt_stream_class_borrow_event_class_by_index(
9ac68eb1 1245 stream_class, i);
cb6f1f7d
PP
1246 struct bt_field_type *event_context_type = NULL;
1247 struct bt_field_type *event_payload_type = NULL;
09840de5
PP
1248
1249 event_context_type =
cb6f1f7d 1250 bt_event_class_borrow_context_field_type(
094ff7c0 1251 event_class);
09840de5 1252 event_payload_type =
cb6f1f7d 1253 bt_event_class_borrow_payload_field_type(
094ff7c0 1254 event_class);
09840de5
PP
1255
1256 /*
1257 * It is important to use the field types returned by
1258 * the previous trace and stream class validation here
1259 * because copies could have been made.
1260 */
95c09b3a
PP
1261 BT_LOGD("Validating event class's field types: "
1262 "addr=%p, name=\"%s\", id=%" PRId64,
cb6f1f7d
PP
1263 event_class, bt_event_class_get_name(event_class),
1264 bt_event_class_get_id(event_class));
50842bdc 1265 ret = bt_validate_class_types(trace->environment,
09840de5
PP
1266 trace_sc_validation_output.packet_header_type,
1267 trace_sc_validation_output.packet_context_type,
1268 trace_sc_validation_output.event_header_type,
1269 trace_sc_validation_output.stream_event_ctx_type,
1270 event_context_type, event_payload_type,
1271 1, 1, event_class->valid, &ec_validation_outputs[i],
cb6f1f7d 1272 ec_validation_flags, bt_field_type_copy);
09840de5
PP
1273
1274 if (ret) {
95c09b3a
PP
1275 BT_LOGE("Failed to validate event class field types: "
1276 "ret=%d", ret);
09840de5
PP
1277 goto end;
1278 }
1279
1280 if ((ec_validation_outputs[i].valid_flags &
1281 ec_validation_flags) != ec_validation_flags) {
1282 /* Invalid event class */
95c09b3a
PP
1283 BT_LOGW("Invalid event class field types: "
1284 "valid-flags=0x%x",
1285 ec_validation_outputs[i].valid_flags);
09840de5
PP
1286 ret = -1;
1287 goto end;
1288 }
1289 }
1290
cb6f1f7d 1291 stream_id = bt_stream_class_get_id(stream_class);
ef0c4a15
JG
1292 if (stream_id < 0) {
1293 stream_id = trace->next_stream_id++;
9ac68eb1 1294 if (stream_id < 0) {
95c09b3a 1295 BT_LOGE_STR("No more stream class IDs available.");
9ac68eb1
PP
1296 ret = -1;
1297 goto end;
1298 }
ef0c4a15
JG
1299
1300 /* Try to assign a new stream id */
1301 for (i = 0; i < trace->stream_classes->len; i++) {
cb6f1f7d 1302 if (stream_id == bt_stream_class_get_id(
ef0c4a15
JG
1303 trace->stream_classes->pdata[i])) {
1304 /* Duplicate stream id found */
95c09b3a
PP
1305 BT_LOGW("Duplicate stream class ID: "
1306 "id=%" PRId64, (int64_t) stream_id);
ef0c4a15
JG
1307 ret = -1;
1308 goto end;
1309 }
1310 }
1311
cb6f1f7d 1312 if (bt_stream_class_set_id_no_check(stream_class,
95c09b3a 1313 stream_id)) {
ef0c4a15 1314 /* TODO Should retry with a different stream id */
95c09b3a
PP
1315 BT_LOGE("Cannot set stream class's ID: "
1316 "id=%" PRId64, (int64_t) stream_id);
ef0c4a15
JG
1317 ret = -1;
1318 goto end;
1319 }
1320 }
1321
e011d2c1
PP
1322 /*
1323 * At this point all the field types in the validation output
1324 * are valid. Validate the semantics of some scopes according to
1325 * the CTF specification.
1326 */
1327 if (!packet_header_field_type_is_valid(trace,
1328 trace_sc_validation_output.packet_header_type)) {
95c09b3a 1329 BT_LOGW_STR("Invalid trace's packet header field type.");
e011d2c1
PP
1330 ret = -1;
1331 goto end;
1332 }
1333
1334 if (!packet_context_field_type_is_valid(trace,
1335 stream_class,
cb6f1f7d 1336 trace_sc_validation_output.packet_context_type, true)) {
95c09b3a 1337 BT_LOGW_STR("Invalid stream class's packet context field type.");
e011d2c1
PP
1338 ret = -1;
1339 goto end;
1340 }
1341
1342 if (!event_header_field_type_is_valid(trace,
1343 stream_class,
1344 trace_sc_validation_output.event_header_type)) {
95c09b3a 1345 BT_LOGW_STR("Invalid steam class's event header field type.");
e011d2c1
PP
1346 ret = -1;
1347 goto end;
1348 }
1349
3fea54f6 1350 bt_object_set_parent(&stream_class->base, &trace->base);
ef0c4a15
JG
1351 g_ptr_array_add(trace->stream_classes, stream_class);
1352
1353 /*
09840de5
PP
1354 * At this point we know that the function will be successful.
1355 * Therefore we can replace the trace and stream class field
1356 * types with what's in their validation output structure and
1357 * mark them as valid. We can also replace the field types of
1358 * all the event classes of the stream class and mark them as
1359 * valid.
1360 */
50842bdc 1361 bt_validation_replace_types(trace, stream_class, NULL,
09840de5
PP
1362 &trace_sc_validation_output, trace_sc_validation_flags);
1363 trace->valid = 1;
1364 stream_class->valid = 1;
1365
1366 /*
50842bdc 1367 * Put what was not moved in bt_validation_replace_types().
09840de5 1368 */
50842bdc 1369 bt_validation_output_put_types(&trace_sc_validation_output);
09840de5 1370
6474e016 1371 for (i = 0; i < event_class_count; i++) {
cb6f1f7d
PP
1372 struct bt_event_class *event_class =
1373 bt_stream_class_borrow_event_class_by_index(
9ac68eb1 1374 stream_class, i);
09840de5 1375
50842bdc 1376 bt_validation_replace_types(NULL, NULL, event_class,
09840de5
PP
1377 &ec_validation_outputs[i], ec_validation_flags);
1378 event_class->valid = 1;
09840de5
PP
1379
1380 /*
1381 * Put what was not moved in
50842bdc 1382 * bt_validation_replace_types().
09840de5 1383 */
50842bdc 1384 bt_validation_output_put_types(&ec_validation_outputs[i]);
09840de5
PP
1385 }
1386
09840de5
PP
1387 /*
1388 * Freeze the trace and the stream class.
1389 */
cb6f1f7d
PP
1390 bt_stream_class_freeze(stream_class);
1391 bt_trace_freeze(trace);
09840de5 1392
2a3ced3c
PP
1393 /*
1394 * It is safe to set the stream class's unique clock class
1395 * now because the stream class is frozen.
1396 */
1397 if (expected_clock_class) {
1398 BT_MOVE(stream_class->clock_class, expected_clock_class);
1399 }
1400
cb6f1f7d
PP
1401 /* Notify listeners of the trace's schema modification. */
1402 bt_stream_class_visit(stream_class,
1403 bt_trace_object_modification, trace);
95c09b3a
PP
1404 BT_LOGD("Added stream class to trace: "
1405 "trace-addr=%p, trace-name=\"%s\", "
1406 "stream-class-addr=%p, stream-class-name=\"%s\", "
1407 "stream-class-id=%" PRId64,
cb6f1f7d
PP
1408 trace, bt_trace_get_name(trace),
1409 stream_class, bt_stream_class_get_name(stream_class),
1410 bt_stream_class_get_id(stream_class));
95c09b3a 1411
ef0c4a15 1412end:
d3814b54 1413 if (ret) {
3fea54f6 1414 bt_object_set_parent(&stream_class->base, NULL);
09840de5
PP
1415
1416 if (ec_validation_outputs) {
6474e016 1417 for (i = 0; i < event_class_count; i++) {
50842bdc 1418 bt_validation_output_put_types(
09840de5
PP
1419 &ec_validation_outputs[i]);
1420 }
1421 }
d3814b54 1422 }
09840de5
PP
1423
1424 g_free(ec_validation_outputs);
50842bdc 1425 bt_validation_output_put_types(&trace_sc_validation_output);
2a3ced3c 1426 bt_put(expected_clock_class);
ef0c4a15
JG
1427 return ret;
1428}
1429
50842bdc 1430int64_t bt_trace_get_stream_count(struct bt_trace *trace)
c1e730fe 1431{
cb6f1f7d
PP
1432 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1433 return (int64_t) trace->streams->len;
c1e730fe
PP
1434}
1435
094ff7c0
PP
1436struct bt_stream *bt_trace_borrow_stream_by_index(
1437 struct bt_trace *trace, uint64_t index)
c1e730fe 1438{
cb6f1f7d
PP
1439 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1440 BT_ASSERT_PRE(index < trace->streams->len,
1441 "Index is out of bounds: index=%" PRIu64 ", "
1442 "count=%u",
1443 index, trace->streams->len);
1444 return g_ptr_array_index(trace->streams, index);
c1e730fe
PP
1445}
1446
50842bdc 1447int64_t bt_trace_get_stream_class_count(struct bt_trace *trace)
ef0c4a15 1448{
cb6f1f7d
PP
1449 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1450 return (int64_t) trace->stream_classes->len;
ef0c4a15
JG
1451}
1452
094ff7c0 1453struct bt_stream_class *bt_trace_borrow_stream_class_by_index(
50842bdc 1454 struct bt_trace *trace, uint64_t index)
ef0c4a15 1455{
cb6f1f7d
PP
1456 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1457 BT_ASSERT_PRE(index < trace->stream_classes->len,
1458 "Index is out of bounds: index=%" PRIu64 ", "
1459 "count=%u",
1460 index, trace->stream_classes->len);
1461 return g_ptr_array_index(trace->stream_classes, index);
ef0c4a15
JG
1462}
1463
094ff7c0 1464struct bt_stream_class *bt_trace_borrow_stream_class_by_id(
cb6f1f7d 1465 struct bt_trace *trace, uint64_t id_param)
4841ccc1 1466{
cb6f1f7d
PP
1467 int i;
1468 struct bt_stream_class *stream_class = NULL;
1469 int64_t id = (int64_t) id_param;
1470
1471 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1472 BT_ASSERT_PRE(id >= 0,
1473 "Invalid stream class ID: %" PRIu64, id_param);
1474
1475 for (i = 0; i < trace->stream_classes->len; i++) {
1476 struct bt_stream_class *stream_class_candidate;
1477
1478 stream_class_candidate =
1479 g_ptr_array_index(trace->stream_classes, i);
1480
1481 if (bt_stream_class_get_id(stream_class_candidate) ==
1482 (int64_t) id) {
1483 stream_class = stream_class_candidate;
1484 goto end;
1485 }
1486 }
1487
1488end:
1489 return stream_class;
4841ccc1
PP
1490}
1491
094ff7c0 1492struct bt_clock_class *bt_trace_borrow_clock_class_by_name(
50842bdc 1493 struct bt_trace *trace, const char *name)
7e4347a3 1494{
cb6f1f7d
PP
1495 size_t i;
1496 struct bt_clock_class *clock_class = NULL;
1497
1498 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1499 BT_ASSERT_PRE_NON_NULL(name, "Name");
1500
1501 for (i = 0; i < trace->clock_classes->len; i++) {
1502 struct bt_clock_class *cur_clk =
1503 g_ptr_array_index(trace->clock_classes, i);
1504 const char *cur_clk_name = bt_clock_class_get_name(cur_clk);
1505
1506 if (!cur_clk_name) {
1507 goto end;
1508 }
1509
1510 if (!strcmp(cur_clk_name, name)) {
1511 clock_class = cur_clk;
1512 goto end;
1513 }
1514 }
1515
1516end:
1517 return clock_class;
7e4347a3
PP
1518}
1519
c9d90a34 1520BT_HIDDEN
cb6f1f7d 1521bt_bool bt_trace_has_clock_class(struct bt_trace *trace,
50842bdc 1522 struct bt_clock_class *clock_class)
c9d90a34
PP
1523{
1524 struct search_query query = { .value = clock_class, .found = 0 };
1525
f6ccaed9
PP
1526 BT_ASSERT(trace);
1527 BT_ASSERT(clock_class);
c9d90a34 1528
3dca2276 1529 g_ptr_array_foreach(trace->clock_classes, value_exists, &query);
c9d90a34
PP
1530 return query.found;
1531}
1532
50842bdc
PP
1533enum bt_byte_order bt_trace_get_native_byte_order(
1534 struct bt_trace *trace)
4ed90fb3 1535{
cb6f1f7d
PP
1536 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1537 return trace->native_byte_order;
4ed90fb3
JG
1538}
1539
cb6f1f7d
PP
1540int bt_trace_set_native_byte_order(struct bt_trace *trace,
1541 enum bt_byte_order byte_order)
bc37ae52
JG
1542{
1543 int ret = 0;
bc37ae52 1544
95c09b3a
PP
1545 if (!trace) {
1546 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1547 ret = -1;
1548 goto end;
1549 }
1550
1551 if (trace->frozen) {
1552 BT_LOGW("Invalid parameter: trace is frozen: "
1553 "addr=%p, name=\"%s\"",
cb6f1f7d 1554 trace, bt_trace_get_name(trace));
d41cff38
PP
1555 ret = -1;
1556 goto end;
1557 }
1558
50842bdc
PP
1559 if (byte_order != BT_BYTE_ORDER_LITTLE_ENDIAN &&
1560 byte_order != BT_BYTE_ORDER_BIG_ENDIAN &&
1561 byte_order != BT_BYTE_ORDER_NETWORK) {
95c09b3a
PP
1562 BT_LOGW("Invalid parameter: invalid byte order: "
1563 "addr=%p, name=\"%s\", bo=%s",
cb6f1f7d 1564 trace, bt_trace_get_name(trace),
3dca2276 1565 bt_common_byte_order_string(byte_order));
bc37ae52
JG
1566 ret = -1;
1567 goto end;
1568 }
1569
dc3fffef 1570 trace->native_byte_order = byte_order;
95c09b3a
PP
1571 BT_LOGV("Set trace's native byte order: "
1572 "addr=%p, name=\"%s\", bo=%s",
cb6f1f7d 1573 trace, bt_trace_get_name(trace),
3dca2276 1574 bt_common_byte_order_string(byte_order));
dc3fffef 1575
bc37ae52
JG
1576end:
1577 return ret;
1578}
1579
094ff7c0 1580struct bt_field_type *bt_trace_borrow_packet_header_field_type(
50842bdc 1581 struct bt_trace *trace)
d246b111 1582{
cb6f1f7d
PP
1583 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1584 return trace->packet_header_field_type;
d246b111
JG
1585}
1586
cb6f1f7d
PP
1587int bt_trace_set_packet_header_field_type(struct bt_trace *trace,
1588 struct bt_field_type *packet_header_type)
d246b111
JG
1589{
1590 int ret = 0;
1591
95c09b3a
PP
1592 if (!trace) {
1593 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1594 ret = -1;
1595 goto end;
1596 }
1597
1598 if (trace->frozen) {
1599 BT_LOGW("Invalid parameter: trace is frozen: "
1600 "addr=%p, name=\"%s\"",
cb6f1f7d 1601 trace, bt_trace_get_name(trace));
d246b111
JG
1602 ret = -1;
1603 goto end;
1604 }
1605
835b2d10
JG
1606 /* packet_header_type must be a structure. */
1607 if (packet_header_type &&
3dca2276 1608 packet_header_type->id != BT_FIELD_TYPE_ID_STRUCT) {
95c09b3a
PP
1609 BT_LOGW("Invalid parameter: packet header field type must be a structure field type if it exists: "
1610 "addr=%p, name=\"%s\", ft-addr=%p, ft-id=%s",
cb6f1f7d 1611 trace, bt_trace_get_name(trace),
95c09b3a 1612 packet_header_type,
3dca2276 1613 bt_common_field_type_id_string(packet_header_type->id));
d246b111
JG
1614 ret = -1;
1615 goto end;
1616 }
1617
3dca2276
PP
1618 bt_put(trace->packet_header_field_type);
1619 trace->packet_header_field_type = bt_get(packet_header_type);
95c09b3a
PP
1620 BT_LOGV("Set trace's packet header field type: "
1621 "addr=%p, name=\"%s\", packet-context-ft-addr=%p",
cb6f1f7d 1622 trace, bt_trace_get_name(trace), packet_header_type);
d246b111
JG
1623end:
1624 return ret;
1625}
1626
8bf65fbd 1627static
544d0515 1628int64_t get_stream_class_count(void *element)
8bf65fbd 1629{
50842bdc
PP
1630 return bt_trace_get_stream_class_count(
1631 (struct bt_trace *) element);
8bf65fbd
JG
1632}
1633
1634static
1635void *get_stream_class(void *element, int i)
1636{
50842bdc
PP
1637 return bt_trace_get_stream_class_by_index(
1638 (struct bt_trace *) element, i);
8bf65fbd
JG
1639}
1640
1641static
50842bdc 1642int visit_stream_class(void *object, bt_visitor visitor,void *data)
8bf65fbd 1643{
50842bdc 1644 return bt_stream_class_visit(object, visitor, data);
8bf65fbd
JG
1645}
1646
50842bdc
PP
1647int bt_trace_visit(struct bt_trace *trace,
1648 bt_visitor visitor, void *data)
8bf65fbd
JG
1649{
1650 int ret;
50842bdc
PP
1651 struct bt_visitor_object obj = {
1652 .object = trace,
1653 .type = BT_VISITOR_OBJECT_TYPE_TRACE
1654 };
8bf65fbd 1655
95c09b3a
PP
1656 if (!trace) {
1657 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1658 ret = -1;
1659 goto end;
1660 }
1661
1662 if (!visitor) {
1663 BT_LOGW_STR("Invalid parameter: visitor is NULL.");
8bf65fbd
JG
1664 ret = -1;
1665 goto end;
1666 }
1667
95c09b3a 1668 BT_LOGV("Visiting trace: addr=%p, name=\"%s\"",
50842bdc 1669 trace, bt_trace_get_name(trace));
d9a13d86 1670 ret = visitor_helper(&obj, get_stream_class_count,
8bf65fbd
JG
1671 get_stream_class, visit_stream_class, visitor, data);
1672end:
1673 return ret;
1674}
1675
1676static
50842bdc 1677int invoke_listener(struct bt_visitor_object *object, void *data)
8bf65fbd 1678{
9b888ff3 1679 struct listener_wrapper *listener_wrapper = data;
8bf65fbd 1680
d9a13d86 1681 listener_wrapper->listener(object, listener_wrapper->data);
9b888ff3 1682 return 0;
8bf65fbd
JG
1683}
1684
95c09b3a 1685// TODO: add logging to this function once we use it internally.
50842bdc
PP
1686int bt_trace_add_listener(struct bt_trace *trace,
1687 bt_listener_cb listener, void *listener_data)
2204c381
JG
1688{
1689 int ret = 0;
50ad4244
JG
1690 struct listener_wrapper *listener_wrapper =
1691 g_new0(struct listener_wrapper, 1);
2204c381 1692
50ad4244 1693 if (!trace || !listener || !listener_wrapper) {
2204c381
JG
1694 ret = -1;
1695 goto error;
1696 }
1697
50ad4244
JG
1698 listener_wrapper->listener = listener;
1699 listener_wrapper->data = listener_data;
8bf65fbd 1700
50ad4244 1701 /* Visit the current schema. */
50842bdc 1702 ret = bt_trace_visit(trace, invoke_listener, listener_wrapper);
8bf65fbd
JG
1703 if (ret) {
1704 goto error;
1705 }
1706
50ad4244
JG
1707 /*
1708 * Add listener to the array of callbacks which will be invoked on
1709 * schema changes.
1710 */
1711 g_ptr_array_add(trace->listeners, listener_wrapper);
2204c381
JG
1712 return ret;
1713error:
50ad4244 1714 g_free(listener_wrapper);
2204c381
JG
1715 return ret;
1716}
1717
bc37ae52 1718BT_HIDDEN
50842bdc 1719int bt_trace_object_modification(struct bt_visitor_object *object,
9b888ff3
JG
1720 void *trace_ptr)
1721{
1722 size_t i;
50842bdc 1723 struct bt_trace *trace = trace_ptr;
9b888ff3 1724
f6ccaed9
PP
1725 BT_ASSERT(trace);
1726 BT_ASSERT(object);
9b888ff3
JG
1727
1728 if (trace->listeners->len == 0) {
1729 goto end;
1730 }
1731
1732 for (i = 0; i < trace->listeners->len; i++) {
1733 struct listener_wrapper *listener =
1734 g_ptr_array_index(trace->listeners, i);
1735
d9a13d86 1736 listener->listener(object, listener->data);
9b888ff3
JG
1737 }
1738end:
1739 return 0;
1740}
1741
50842bdc 1742bt_bool bt_trace_is_static(struct bt_trace *trace)
5acf2ae6 1743{
d975f66c
PP
1744 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
1745 return trace->is_static;
5acf2ae6
PP
1746}
1747
50842bdc 1748int bt_trace_set_is_static(struct bt_trace *trace)
5acf2ae6
PP
1749{
1750 int ret = 0;
3602afb0 1751 size_t i;
5acf2ae6
PP
1752
1753 if (!trace) {
95c09b3a 1754 BT_LOGW_STR("Invalid parameter: trace is NULL.");
5acf2ae6
PP
1755 ret = -1;
1756 goto end;
1757 }
1758
cb6f1f7d 1759 ret = check_packet_header_type_has_no_clock_class(trace);
726106d3
PP
1760 if (ret) {
1761 /* check_packet_header_type_has_no_clock_class() logs errors */
1762 goto end;
1763 }
1764
c55a9f58 1765 trace->is_static = BT_TRUE;
cb6f1f7d 1766 bt_trace_freeze(trace);
95c09b3a 1767 BT_LOGV("Set trace static: addr=%p, name=\"%s\"",
50842bdc 1768 trace, bt_trace_get_name(trace));
5acf2ae6 1769
3602afb0
PP
1770 /* Call all the "trace is static" listeners */
1771 for (i = 0; i < trace->is_static_listeners->len; i++) {
50842bdc 1772 struct bt_trace_is_static_listener_elem elem =
3602afb0 1773 g_array_index(trace->is_static_listeners,
50842bdc 1774 struct bt_trace_is_static_listener_elem, i);
3602afb0
PP
1775
1776 if (elem.func) {
1777 elem.func(trace, elem.data);
1778 }
1779 }
1780
1781end:
1782 return ret;
1783}
1784
50842bdc
PP
1785int bt_trace_add_is_static_listener(struct bt_trace *trace,
1786 bt_trace_is_static_listener listener,
1787 bt_trace_listener_removed listener_removed, void *data)
3602afb0
PP
1788{
1789 int i;
50842bdc 1790 struct bt_trace_is_static_listener_elem new_elem = {
3602afb0 1791 .func = listener,
8480c8cc 1792 .removed = listener_removed,
3602afb0
PP
1793 .data = data,
1794 };
1795
1796 if (!trace) {
1797 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1798 i = -1;
1799 goto end;
1800 }
1801
1802 if (!listener) {
1803 BT_LOGW_STR("Invalid parameter: listener is NULL.");
1804 i = -1;
1805 goto end;
1806 }
1807
1808 if (trace->is_static) {
1809 BT_LOGW("Invalid parameter: trace is already static: "
1810 "addr=%p, name=\"%s\"",
50842bdc 1811 trace, bt_trace_get_name(trace));
3602afb0
PP
1812 i = -1;
1813 goto end;
1814 }
1815
8480c8cc
PP
1816 if (trace->in_remove_listener) {
1817 BT_LOGW("Cannot call this function during the execution of a remove listener: "
1818 "addr=%p, name=\"%s\"",
50842bdc 1819 trace, bt_trace_get_name(trace));
8480c8cc
PP
1820 i = -1;
1821 goto end;
1822 }
1823
3602afb0
PP
1824 /* Find the next available spot */
1825 for (i = 0; i < trace->is_static_listeners->len; i++) {
50842bdc 1826 struct bt_trace_is_static_listener_elem elem =
3602afb0 1827 g_array_index(trace->is_static_listeners,
50842bdc 1828 struct bt_trace_is_static_listener_elem, i);
3602afb0
PP
1829
1830 if (!elem.func) {
1831 break;
1832 }
1833 }
1834
1835 if (i == trace->is_static_listeners->len) {
1836 g_array_append_val(trace->is_static_listeners, new_elem);
1837 } else {
1838 g_array_insert_val(trace->is_static_listeners, i, new_elem);
1839 }
1840
1841 BT_LOGV("Added \"trace is static\" listener: "
1842 "trace-addr=%p, trace-name=\"%s\", func-addr=%p, "
1843 "data-addr=%p, listener-id=%d",
50842bdc 1844 trace, bt_trace_get_name(trace), listener, data, i);
3602afb0
PP
1845
1846end:
1847 return i;
1848}
1849
50842bdc
PP
1850int bt_trace_remove_is_static_listener(
1851 struct bt_trace *trace, int listener_id)
3602afb0
PP
1852{
1853 int ret = 0;
50842bdc 1854 struct bt_trace_is_static_listener_elem *elem;
3602afb0
PP
1855
1856 if (!trace) {
1857 BT_LOGW_STR("Invalid parameter: trace is NULL.");
1858 ret = -1;
1859 goto end;
1860 }
1861
8480c8cc
PP
1862 if (trace->in_remove_listener) {
1863 BT_LOGW("Cannot call this function during the execution of a remove listener: "
1864 "addr=%p, name=\"%s\", listener-id=%d",
50842bdc 1865 trace, bt_trace_get_name(trace),
8480c8cc
PP
1866 listener_id);
1867 ret = -1;
1868 goto end;
1869 }
1870
3602afb0
PP
1871 if (listener_id < 0) {
1872 BT_LOGW("Invalid listener ID: must be zero or positive: "
1873 "listener-id=%d", listener_id);
1874 ret = -1;
1875 goto end;
1876 }
1877
1878 if (listener_id >= trace->is_static_listeners->len) {
1879 BT_LOGW("Invalid parameter: no listener with this listener ID: "
1880 "addr=%p, name=\"%s\", listener-id=%d",
50842bdc 1881 trace, bt_trace_get_name(trace),
3602afb0
PP
1882 listener_id);
1883 ret = -1;
1884 goto end;
1885 }
1886
1887 elem = &g_array_index(trace->is_static_listeners,
50842bdc 1888 struct bt_trace_is_static_listener_elem,
3602afb0
PP
1889 listener_id);
1890 if (!elem->func) {
1891 BT_LOGW("Invalid parameter: no listener with this listener ID: "
1892 "addr=%p, name=\"%s\", listener-id=%d",
50842bdc 1893 trace, bt_trace_get_name(trace),
3602afb0
PP
1894 listener_id);
1895 ret = -1;
1896 goto end;
1897 }
1898
8480c8cc
PP
1899 if (elem->removed) {
1900 /* Call remove listener */
1901 BT_LOGV("Calling remove listener: "
1902 "trace-addr=%p, trace-name=\"%s\", "
50842bdc 1903 "listener-id=%d", trace, bt_trace_get_name(trace),
8480c8cc
PP
1904 listener_id);
1905 trace->in_remove_listener = BT_TRUE;
1906 elem->removed(trace, elem->data);
1907 trace->in_remove_listener = BT_FALSE;
1908 }
1909
3602afb0 1910 elem->func = NULL;
8480c8cc 1911 elem->removed = NULL;
3602afb0
PP
1912 elem->data = NULL;
1913 BT_LOGV("Removed \"trace is static\" listener: "
1914 "trace-addr=%p, trace-name=\"%s\", "
50842bdc 1915 "listener-id=%d", trace, bt_trace_get_name(trace),
3602afb0
PP
1916 listener_id);
1917
5acf2ae6
PP
1918end:
1919 return ret;
1920}
312c056a
PP
1921
1922struct bt_packet_header_field *bt_trace_create_packet_header_field(
1923 struct bt_trace *trace)
1924{
1925 struct bt_field_wrapper *field_wrapper;
1926
1927 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
cb6f1f7d 1928 BT_ASSERT_PRE(trace->packet_header_field_type,
312c056a
PP
1929 "Trace has no packet header field type: %!+t",
1930 trace);
1931 field_wrapper = bt_field_wrapper_create(
1932 &trace->packet_header_field_pool,
cb6f1f7d 1933 (void *) trace->packet_header_field_type);
312c056a
PP
1934 if (!field_wrapper) {
1935 BT_LIB_LOGE("Cannot allocate one packet header field from trace: "
1936 "%![trace-]+t", trace);
1937 goto error;
1938 }
1939
1940 BT_ASSERT(field_wrapper->field);
cb6f1f7d 1941 bt_trace_freeze(trace);
312c056a
PP
1942 goto end;
1943
1944error:
1945 if (field_wrapper) {
1946 bt_field_wrapper_destroy(field_wrapper);
1947 field_wrapper = NULL;
1948 }
1949
1950end:
1951 return (void *) field_wrapper;
1952}
This page took 0.183514 seconds and 4 git commands to generate.