Move to kernel style SPDX license identifiers
[babeltrace.git] / src / lib / trace-ir / trace.c
1 /*
2 * SPDX-License-Identifier: MIT
3 *
4 * Copyright 2017-2018 Philippe Proulx <pproulx@efficios.com>
5 * Copyright 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 */
7
8 #define BT_LOG_TAG "LIB/TRACE"
9 #include "lib/logging.h"
10
11 #include "lib/assert-pre.h"
12 #include "lib/assert-post.h"
13 #include <babeltrace2/trace-ir/trace.h>
14 #include <babeltrace2/trace-ir/event-class.h>
15 #include "ctf-writer/functor.h"
16 #include "ctf-writer/clock.h"
17 #include "compat/compiler.h"
18 #include <babeltrace2/value.h>
19 #include "lib/value.h"
20 #include <babeltrace2/types.h>
21 #include "compat/endian.h"
22 #include "common/assert.h"
23 #include "compat/glib.h"
24 #include <inttypes.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <stdbool.h>
28 #include <stdlib.h>
29
30 #include "attributes.h"
31 #include "clock-class.h"
32 #include "event-class.h"
33 #include "event.h"
34 #include "field-class.h"
35 #include "field-wrapper.h"
36 #include "resolve-field-path.h"
37 #include "stream-class.h"
38 #include "stream.h"
39 #include "trace-class.h"
40 #include "trace.h"
41 #include "utils.h"
42 #include "lib/value.h"
43 #include "lib/func-status.h"
44
45 struct bt_trace_destruction_listener_elem {
46 bt_trace_destruction_listener_func func;
47 void *data;
48 };
49
50 #define BT_ASSERT_PRE_DEV_TRACE_HOT(_trace) \
51 BT_ASSERT_PRE_DEV_HOT((_trace), "Trace", ": %!+t", (_trace))
52
53 static
54 void destroy_trace(struct bt_object *obj)
55 {
56 struct bt_trace *trace = (void *) obj;
57
58 BT_LIB_LOGD("Destroying trace object: %!+t", trace);
59 BT_OBJECT_PUT_REF_AND_RESET(trace->user_attributes);
60
61 /*
62 * Call destruction listener functions so that everything else
63 * still exists in the trace.
64 */
65 if (trace->destruction_listeners) {
66 uint64_t i;
67 const struct bt_error *saved_error;
68
69 BT_LIB_LOGD("Calling trace destruction listener(s): %!+t", trace);
70
71 /*
72 * The trace's reference count is 0 if we're here. Increment
73 * it to avoid a double-destroy (possibly infinitely recursive).
74 * This could happen for example if a destruction listener did
75 * bt_object_get_ref() (or anything that causes
76 * bt_object_get_ref() to be called) on the trace (ref.
77 * count goes from 0 to 1), and then bt_object_put_ref(): the
78 * reference count would go from 1 to 0 again and this function
79 * would be called again.
80 */
81 trace->base.ref_count++;
82
83 saved_error = bt_current_thread_take_error();
84
85 /* Call all the trace destruction listeners */
86 for (i = 0; i < trace->destruction_listeners->len; i++) {
87 struct bt_trace_destruction_listener_elem elem =
88 g_array_index(trace->destruction_listeners,
89 struct bt_trace_destruction_listener_elem, i);
90
91 if (elem.func) {
92 elem.func(trace, elem.data);
93 BT_ASSERT_POST_NO_ERROR();
94 }
95
96 /*
97 * The destruction listener should not have kept a
98 * reference to the trace.
99 */
100 BT_ASSERT_POST(trace->base.ref_count == 1, "Destruction listener kept a reference to the trace being destroyed: %![trace-]+t", trace);
101 }
102 g_array_free(trace->destruction_listeners, TRUE);
103 trace->destruction_listeners = NULL;
104
105 if (saved_error) {
106 BT_CURRENT_THREAD_MOVE_ERROR_AND_RESET(saved_error);
107 }
108 }
109
110 if (trace->name.str) {
111 g_string_free(trace->name.str, TRUE);
112 trace->name.str = NULL;
113 trace->name.value = NULL;
114 }
115
116 if (trace->environment) {
117 BT_LOGD_STR("Destroying environment attributes.");
118 bt_attributes_destroy(trace->environment);
119 trace->environment = NULL;
120 }
121
122 if (trace->streams) {
123 BT_LOGD_STR("Destroying streams.");
124 g_ptr_array_free(trace->streams, TRUE);
125 trace->streams = NULL;
126 }
127
128 if (trace->stream_classes_stream_count) {
129 g_hash_table_destroy(trace->stream_classes_stream_count);
130 trace->stream_classes_stream_count = NULL;
131 }
132
133 BT_LOGD_STR("Putting trace's class.");
134 bt_object_put_ref(trace->class);
135 trace->class = NULL;
136 g_free(trace);
137 }
138
139 struct bt_trace *bt_trace_create(struct bt_trace_class *tc)
140 {
141 struct bt_trace *trace = NULL;
142
143 BT_ASSERT_PRE_NO_ERROR();
144
145 BT_LIB_LOGD("Creating trace object: %![tc-]+T", tc);
146 trace = g_new0(struct bt_trace, 1);
147 if (!trace) {
148 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one trace.");
149 goto error;
150 }
151
152 bt_object_init_shared(&trace->base, destroy_trace);
153 trace->user_attributes = bt_value_map_create();
154 if (!trace->user_attributes) {
155 BT_LIB_LOGE_APPEND_CAUSE(
156 "Failed to create a map value object.");
157 goto error;
158 }
159
160 trace->streams = g_ptr_array_new_with_free_func(
161 (GDestroyNotify) bt_object_try_spec_release);
162 if (!trace->streams) {
163 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GPtrArray.");
164 goto error;
165 }
166
167 trace->stream_classes_stream_count = g_hash_table_new(g_direct_hash,
168 g_direct_equal);
169 if (!trace->stream_classes_stream_count) {
170 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GHashTable.");
171 goto error;
172 }
173
174 trace->name.str = g_string_new(NULL);
175 if (!trace->name.str) {
176 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GString.");
177 goto error;
178 }
179
180 trace->environment = bt_attributes_create();
181 if (!trace->environment) {
182 BT_LIB_LOGE_APPEND_CAUSE("Cannot create empty attributes object.");
183 goto error;
184 }
185
186 trace->destruction_listeners = g_array_new(FALSE, TRUE,
187 sizeof(struct bt_trace_destruction_listener_elem));
188 if (!trace->destruction_listeners) {
189 BT_LIB_LOGE_APPEND_CAUSE("Failed to allocate one GArray.");
190 goto error;
191 }
192
193 trace->class = tc;
194 bt_object_get_ref_no_null_check(trace->class);
195 BT_LIB_LOGD("Created trace object: %!+t", trace);
196 goto end;
197
198 error:
199 BT_OBJECT_PUT_REF_AND_RESET(trace);
200
201 end:
202 return trace;
203 }
204
205 const char *bt_trace_get_name(const struct bt_trace *trace)
206 {
207 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
208 return trace->name.value;
209 }
210
211 enum bt_trace_set_name_status bt_trace_set_name(struct bt_trace *trace,
212 const char *name)
213 {
214 BT_ASSERT_PRE_NO_ERROR();
215 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
216 BT_ASSERT_PRE_NON_NULL(name, "Name");
217 BT_ASSERT_PRE_DEV_TRACE_HOT(trace);
218 g_string_assign(trace->name.str, name);
219 trace->name.value = trace->name.str->str;
220 BT_LIB_LOGD("Set trace's name: %!+t", trace);
221 return BT_FUNC_STATUS_OK;
222 }
223
224 bt_uuid bt_trace_get_uuid(const struct bt_trace *trace)
225 {
226 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
227 return trace->uuid.value;
228 }
229
230 void bt_trace_set_uuid(struct bt_trace *trace, bt_uuid uuid)
231 {
232 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
233 BT_ASSERT_PRE_NON_NULL(uuid, "UUID");
234 BT_ASSERT_PRE_DEV_TRACE_HOT(trace);
235 bt_uuid_copy(trace->uuid.uuid, uuid);
236 trace->uuid.value = trace->uuid.uuid;
237 BT_LIB_LOGD("Set trace's UUID: %!+t", trace);
238 }
239
240 static
241 bool trace_has_environment_entry(const struct bt_trace *trace, const char *name)
242 {
243 BT_ASSERT(trace);
244
245 return bt_attributes_borrow_field_value_by_name(
246 trace->environment, name);
247 }
248
249 static
250 enum bt_trace_set_environment_entry_status set_environment_entry(
251 struct bt_trace *trace,
252 const char *name, struct bt_value *value)
253 {
254 int ret;
255
256 BT_ASSERT(trace);
257 BT_ASSERT(name);
258 BT_ASSERT(value);
259 BT_ASSERT_PRE(!trace->frozen ||
260 !trace_has_environment_entry(trace, name),
261 "Trace is frozen: cannot replace environment entry: "
262 "%![trace-]+t, entry-name=\"%s\"", trace, name);
263 ret = bt_attributes_set_field_value(trace->environment, name,
264 value);
265 if (ret) {
266 ret = BT_FUNC_STATUS_MEMORY_ERROR;
267 BT_LIB_LOGE_APPEND_CAUSE(
268 "Cannot set trace's environment entry: "
269 "%![trace-]+t, entry-name=\"%s\"", trace, name);
270 } else {
271 bt_value_freeze(value);
272 BT_LIB_LOGD("Set trace's environment entry: "
273 "%![trace-]+t, entry-name=\"%s\"", trace, name);
274 }
275
276 return ret;
277 }
278
279 enum bt_trace_set_environment_entry_status
280 bt_trace_set_environment_entry_string(
281 struct bt_trace *trace, const char *name, const char *value)
282 {
283 int ret;
284 struct bt_value *value_obj;
285
286 BT_ASSERT_PRE_NO_ERROR();
287 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
288 BT_ASSERT_PRE_NON_NULL(name, "Name");
289 BT_ASSERT_PRE_NON_NULL(value, "Value");
290
291 value_obj = bt_value_string_create_init(value);
292 if (!value_obj) {
293 BT_LIB_LOGE_APPEND_CAUSE(
294 "Cannot create a string value object.");
295 ret = -1;
296 goto end;
297 }
298
299 /* set_environment_entry() logs errors */
300 ret = set_environment_entry(trace, name, value_obj);
301
302 end:
303 bt_object_put_ref(value_obj);
304 return ret;
305 }
306
307 enum bt_trace_set_environment_entry_status
308 bt_trace_set_environment_entry_integer(
309 struct bt_trace *trace, const char *name, int64_t value)
310 {
311 int ret;
312 struct bt_value *value_obj;
313
314 BT_ASSERT_PRE_NO_ERROR();
315 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
316 BT_ASSERT_PRE_NON_NULL(name, "Name");
317
318 value_obj = bt_value_integer_signed_create_init(value);
319 if (!value_obj) {
320 BT_LIB_LOGE_APPEND_CAUSE(
321 "Cannot create an integer value object.");
322 ret = BT_FUNC_STATUS_MEMORY_ERROR;
323 goto end;
324 }
325
326 /* set_environment_entry() logs errors */
327 ret = set_environment_entry(trace, name, value_obj);
328
329 end:
330 bt_object_put_ref(value_obj);
331 return ret;
332 }
333
334 uint64_t bt_trace_get_environment_entry_count(const struct bt_trace *trace)
335 {
336 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
337 return bt_attributes_get_count(trace->environment);
338 }
339
340 void bt_trace_borrow_environment_entry_by_index_const(
341 const struct bt_trace *trace, uint64_t index,
342 const char **name, const struct bt_value **value)
343 {
344 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
345 BT_ASSERT_PRE_DEV_NON_NULL(name, "Name");
346 BT_ASSERT_PRE_DEV_NON_NULL(value, "Value");
347 BT_ASSERT_PRE_DEV_VALID_INDEX(index,
348 bt_attributes_get_count(trace->environment));
349 *value = bt_attributes_borrow_field_value(trace->environment, index);
350 BT_ASSERT(*value);
351 *name = bt_attributes_get_field_name(trace->environment, index);
352 BT_ASSERT(*name);
353 }
354
355 const struct bt_value *bt_trace_borrow_environment_entry_value_by_name_const(
356 const struct bt_trace *trace, const char *name)
357 {
358 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
359 BT_ASSERT_PRE_DEV_NON_NULL(name, "Name");
360 return bt_attributes_borrow_field_value_by_name(trace->environment,
361 name);
362 }
363
364 uint64_t bt_trace_get_stream_count(const struct bt_trace *trace)
365 {
366 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
367 return (uint64_t) trace->streams->len;
368 }
369
370 struct bt_stream *bt_trace_borrow_stream_by_index(
371 struct bt_trace *trace, uint64_t index)
372 {
373 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
374 BT_ASSERT_PRE_DEV_VALID_INDEX(index, trace->streams->len);
375 return g_ptr_array_index(trace->streams, index);
376 }
377
378 const struct bt_stream *bt_trace_borrow_stream_by_index_const(
379 const struct bt_trace *trace, uint64_t index)
380 {
381 return bt_trace_borrow_stream_by_index((void *) trace, index);
382 }
383
384 struct bt_stream *bt_trace_borrow_stream_by_id(struct bt_trace *trace,
385 uint64_t id)
386 {
387 struct bt_stream *stream = NULL;
388 uint64_t i;
389
390 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
391
392 for (i = 0; i < trace->streams->len; i++) {
393 struct bt_stream *stream_candidate =
394 g_ptr_array_index(trace->streams, i);
395
396 if (stream_candidate->id == id) {
397 stream = stream_candidate;
398 goto end;
399 }
400 }
401
402 end:
403 return stream;
404 }
405
406 const struct bt_stream *bt_trace_borrow_stream_by_id_const(
407 const struct bt_trace *trace, uint64_t id)
408 {
409 return bt_trace_borrow_stream_by_id((void *) trace, id);
410 }
411
412 enum bt_trace_add_listener_status bt_trace_add_destruction_listener(
413 const struct bt_trace *c_trace,
414 bt_trace_destruction_listener_func listener,
415 void *data, bt_listener_id *listener_id)
416 {
417 struct bt_trace *trace = (void *) c_trace;
418 uint64_t i;
419 struct bt_trace_destruction_listener_elem new_elem = {
420 .func = listener,
421 .data = data,
422 };
423
424 BT_ASSERT_PRE_NO_ERROR();
425 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
426 BT_ASSERT_PRE_NON_NULL(listener, "Listener");
427
428 /* Find the next available spot */
429 for (i = 0; i < trace->destruction_listeners->len; i++) {
430 struct bt_trace_destruction_listener_elem elem =
431 g_array_index(trace->destruction_listeners,
432 struct bt_trace_destruction_listener_elem, i);
433
434 if (!elem.func) {
435 break;
436 }
437 }
438
439 if (i == trace->destruction_listeners->len) {
440 g_array_append_val(trace->destruction_listeners, new_elem);
441 } else {
442 g_array_insert_val(trace->destruction_listeners, i, new_elem);
443 }
444
445 if (listener_id) {
446 *listener_id = i;
447 }
448
449 BT_LIB_LOGD("Added destruction listener: " "%![trace-]+t, "
450 "listener-id=%" PRIu64, trace, i);
451 return BT_FUNC_STATUS_OK;
452 }
453
454 static
455 bool has_listener_id(const struct bt_trace *trace, uint64_t listener_id)
456 {
457 BT_ASSERT(listener_id < trace->destruction_listeners->len);
458 return (&g_array_index(trace->destruction_listeners,
459 struct bt_trace_destruction_listener_elem,
460 listener_id))->func;
461 }
462
463 enum bt_trace_remove_listener_status bt_trace_remove_destruction_listener(
464 const struct bt_trace *c_trace, bt_listener_id listener_id)
465 {
466 struct bt_trace *trace = (void *) c_trace;
467 struct bt_trace_destruction_listener_elem *elem;
468
469 BT_ASSERT_PRE_NO_ERROR();
470 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
471 BT_ASSERT_PRE(has_listener_id(trace, listener_id),
472 "Trace has no such trace destruction listener ID: "
473 "%![trace-]+t, %" PRIu64, trace, listener_id);
474 elem = &g_array_index(trace->destruction_listeners,
475 struct bt_trace_destruction_listener_elem,
476 listener_id);
477 BT_ASSERT(elem->func);
478
479 elem->func = NULL;
480 elem->data = NULL;
481 BT_LIB_LOGD("Removed \"trace destruction listener: "
482 "%![trace-]+t, listener-id=%" PRIu64,
483 trace, listener_id);
484 return BT_FUNC_STATUS_OK;
485 }
486
487 BT_HIDDEN
488 void _bt_trace_freeze(const struct bt_trace *trace)
489 {
490 BT_ASSERT(trace);
491 BT_LIB_LOGD("Freezing trace's class: %!+T", trace->class);
492 bt_trace_class_freeze(trace->class);
493 BT_LIB_LOGD("Freezing trace's user attributes: %!+v",
494 trace->user_attributes);
495 bt_value_freeze(trace->user_attributes);
496 BT_LIB_LOGD("Freezing trace: %!+t", trace);
497 ((struct bt_trace *) trace)->frozen = true;
498 }
499
500 BT_HIDDEN
501 void bt_trace_add_stream(struct bt_trace *trace, struct bt_stream *stream)
502 {
503 guint count = 0;
504
505 bt_object_set_parent(&stream->base, &trace->base);
506 g_ptr_array_add(trace->streams, stream);
507 bt_trace_freeze(trace);
508
509 if (bt_g_hash_table_contains(trace->stream_classes_stream_count,
510 stream->class)) {
511 count = GPOINTER_TO_UINT(g_hash_table_lookup(
512 trace->stream_classes_stream_count, stream->class));
513 }
514
515 g_hash_table_insert(trace->stream_classes_stream_count,
516 stream->class, GUINT_TO_POINTER(count + 1));
517 }
518
519 BT_HIDDEN
520 uint64_t bt_trace_get_automatic_stream_id(const struct bt_trace *trace,
521 const struct bt_stream_class *stream_class)
522 {
523 gpointer orig_key;
524 gpointer value;
525 uint64_t id = 0;
526
527 BT_ASSERT(stream_class);
528 BT_ASSERT(trace);
529 if (g_hash_table_lookup_extended(trace->stream_classes_stream_count,
530 stream_class, &orig_key, &value)) {
531 id = (uint64_t) GPOINTER_TO_UINT(value);
532 }
533
534 return id;
535 }
536
537 struct bt_trace_class *bt_trace_borrow_class(struct bt_trace *trace)
538 {
539 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
540 return trace->class;
541 }
542
543 const struct bt_trace_class *bt_trace_borrow_class_const(
544 const struct bt_trace *trace)
545 {
546 return bt_trace_borrow_class((void *) trace);
547 }
548
549 const struct bt_value *bt_trace_borrow_user_attributes_const(
550 const struct bt_trace *trace)
551 {
552 BT_ASSERT_PRE_DEV_NON_NULL(trace, "Trace");
553 return trace->user_attributes;
554 }
555
556 struct bt_value *bt_trace_borrow_user_attributes(struct bt_trace *trace)
557 {
558 return (void *) bt_trace_borrow_user_attributes_const((void *) trace);
559 }
560
561 void bt_trace_set_user_attributes(
562 struct bt_trace *trace,
563 const struct bt_value *user_attributes)
564 {
565 BT_ASSERT_PRE_NON_NULL(trace, "Trace");
566 BT_ASSERT_PRE_NON_NULL(user_attributes, "User attributes");
567 BT_ASSERT_PRE(user_attributes->type == BT_VALUE_TYPE_MAP,
568 "User attributes object is not a map value object.");
569 BT_ASSERT_PRE_DEV_TRACE_HOT(trace);
570 bt_object_put_ref_no_null_check(trace->user_attributes);
571 trace->user_attributes = (void *) user_attributes;
572 bt_object_get_ref_no_null_check(trace->user_attributes);
573 }
574
575 void bt_trace_get_ref(const struct bt_trace *trace)
576 {
577 bt_object_get_ref(trace);
578 }
579
580 void bt_trace_put_ref(const struct bt_trace *trace)
581 {
582 bt_object_put_ref(trace);
583 }
This page took 0.040416 seconds and 4 git commands to generate.