*/
#define BT_LOG_TAG "TRACE"
-#include <babeltrace/lib-logging-internal.h>
-
-#include <babeltrace/assert-pre-internal.h>
-#include <babeltrace/trace-ir/trace-class.h>
-#include <babeltrace/trace-ir/trace-class-const.h>
-#include <babeltrace/trace-ir/trace-internal.h>
-#include <babeltrace/trace-ir/clock-class-internal.h>
-#include <babeltrace/trace-ir/stream-internal.h>
-#include <babeltrace/trace-ir/stream-class-internal.h>
-#include <babeltrace/trace-ir/event-internal.h>
-#include <babeltrace/trace-ir/event-class.h>
-#include <babeltrace/trace-ir/event-class-internal.h>
-#include <babeltrace/ctf-writer/functor-internal.h>
-#include <babeltrace/ctf-writer/clock-internal.h>
-#include <babeltrace/trace-ir/field-wrapper-internal.h>
-#include <babeltrace/trace-ir/field-class-internal.h>
-#include <babeltrace/trace-ir/attributes-internal.h>
-#include <babeltrace/trace-ir/utils-internal.h>
-#include <babeltrace/trace-ir/resolve-field-path-internal.h>
-#include <babeltrace/compiler-internal.h>
-#include <babeltrace/value.h>
-#include <babeltrace/value-const.h>
-#include <babeltrace/value-internal.h>
-#include <babeltrace/types.h>
-#include <babeltrace/endian-internal.h>
-#include <babeltrace/assert-internal.h>
-#include <babeltrace/compat/glib-internal.h>
+#include <babeltrace2/lib-logging-internal.h>
+
+#include <babeltrace2/assert-pre-internal.h>
+#include <babeltrace2/trace-ir/trace-class.h>
+#include <babeltrace2/trace-ir/trace-class-const.h>
+#include <babeltrace2/trace-ir/trace-internal.h>
+#include <babeltrace2/trace-ir/clock-class-internal.h>
+#include <babeltrace2/trace-ir/stream-internal.h>
+#include <babeltrace2/trace-ir/stream-class-internal.h>
+#include <babeltrace2/trace-ir/event-internal.h>
+#include <babeltrace2/trace-ir/event-class.h>
+#include <babeltrace2/trace-ir/event-class-internal.h>
+#include <babeltrace2/ctf-writer/functor-internal.h>
+#include <babeltrace2/ctf-writer/clock-internal.h>
+#include <babeltrace2/trace-ir/field-wrapper-internal.h>
+#include <babeltrace2/trace-ir/field-class-internal.h>
+#include <babeltrace2/trace-ir/attributes-internal.h>
+#include <babeltrace2/trace-ir/utils-internal.h>
+#include <babeltrace2/trace-ir/resolve-field-path-internal.h>
+#include <babeltrace2/compiler-internal.h>
+#include <babeltrace2/value.h>
+#include <babeltrace2/value-const.h>
+#include <babeltrace2/value-internal.h>
+#include <babeltrace2/types.h>
+#include <babeltrace2/endian-internal.h>
+#include <babeltrace2/assert-internal.h>
+#include <babeltrace2/compat/glib-internal.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
+struct bt_trace_class_destruction_listener_elem {
+ bt_trace_class_destruction_listener_func func;
+ void *data;
+};
+
#define BT_ASSERT_PRE_TRACE_CLASS_HOT(_tc) \
BT_ASSERT_PRE_HOT((_tc), "Trace class", ": %!+T", (_tc))
struct bt_trace_class *tc = (void *) obj;
BT_LIB_LOGD("Destroying trace class object: %!+T", tc);
+ /*
+ * Call destruction listener functions so that everything else
+ * still exists in the trace class.
+ */
+ if (tc->destruction_listeners) {
+ uint64_t i;
+ BT_LIB_LOGV("Calling trace class destruction listener(s): %!+T", tc);
+
+ /*
+ * The trace class' reference count is 0 if we're here. Increment
+ * it to avoid a double-destroy (possibly infinitely recursive).
+ * This could happen for example if a destruction listener did
+ * bt_object_get_ref() (or anything that causes
+ * bt_object_get_ref() to be called) on the trace class (ref.
+ * count goes from 0 to 1), and then bt_object_put_ref(): the
+ * reference count would go from 1 to 0 again and this function
+ * would be called again.
+ */
+ tc->base.ref_count++;
+
+ /* Call all the trace class destruction listeners */
+ for (i = 0; i < tc->destruction_listeners->len; i++) {
+ struct bt_trace_class_destruction_listener_elem elem =
+ g_array_index(tc->destruction_listeners,
+ struct bt_trace_class_destruction_listener_elem, i);
+
+ if (elem.func) {
+ elem.func(tc, elem.data);
+ }
+
+ /*
+ * The destruction listener should not have kept a
+ * reference to the trace class.
+ */
+ BT_ASSERT_PRE(tc->base.ref_count == 1, "Destruction listener kept a reference to the trace class being destroyed: %![tc-]+T", tc);
+ }
+ g_array_free(tc->destruction_listeners, TRUE);
+ tc->destruction_listeners = NULL;
+ }
if (tc->environment) {
BT_LOGD_STR("Destroying environment attributes.");
goto error;
}
+ tc->destruction_listeners = g_array_new(FALSE, TRUE,
+ sizeof(struct bt_trace_class_destruction_listener_elem));
+ if (!tc->destruction_listeners) {
+ BT_LOGE_STR("Failed to allocate one GArray.");
+ goto error;
+ }
+
tc->assigns_automatic_stream_class_id = true;
BT_LIB_LOGD("Created trace class object: %!+T", tc);
goto end;
BT_LIB_LOGV("Set trace class's UUID: %!+T", tc);
}
+enum bt_trace_class_status bt_trace_class_add_destruction_listener(
+ const struct bt_trace_class *_tc,
+ bt_trace_class_destruction_listener_func listener,
+ void *data, uint64_t *listener_id)
+{
+ struct bt_trace_class *tc = (void *) _tc;
+ uint64_t i;
+ struct bt_trace_class_destruction_listener_elem new_elem = {
+ .func = listener,
+ .data = data,
+ };
+
+ BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+ BT_ASSERT_PRE_NON_NULL(listener, "Listener");
+
+ /* Find the next available spot */
+ for (i = 0; i < tc->destruction_listeners->len; i++) {
+ struct bt_trace_class_destruction_listener_elem elem =
+ g_array_index(tc->destruction_listeners,
+ struct bt_trace_class_destruction_listener_elem, i);
+
+ if (!elem.func) {
+ break;
+ }
+ }
+
+ if (i == tc->destruction_listeners->len) {
+ g_array_append_val(tc->destruction_listeners, new_elem);
+ } else {
+ g_array_insert_val(tc->destruction_listeners, i, new_elem);
+ }
+
+ if (listener_id) {
+ *listener_id = i;
+ }
+
+ BT_LIB_LOGV("Added trace class destruction listener: %![tc-]+T, "
+ "listener-id=%" PRIu64, tc, i);
+ return BT_TRACE_CLASS_STATUS_OK;
+}
+
+BT_ASSERT_PRE_FUNC
+static
+bool has_listener_id(const struct bt_trace_class *tc, uint64_t listener_id)
+{
+ BT_ASSERT(listener_id < tc->destruction_listeners->len);
+ return (&g_array_index(tc->destruction_listeners,
+ struct bt_trace_class_destruction_listener_elem,
+ listener_id))->func != NULL;
+}
+
+enum bt_trace_class_status bt_trace_class_remove_destruction_listener(
+ const struct bt_trace_class *_tc, uint64_t listener_id)
+{
+ struct bt_trace_class *tc = (void *) _tc;
+ struct bt_trace_class_destruction_listener_elem *elem;
+
+ BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
+ BT_ASSERT_PRE(has_listener_id(tc, listener_id),
+ "Trace class has no such trace class destruction listener ID: "
+ "%![tc-]+T, %" PRIu64, tc, listener_id);
+ elem = &g_array_index(tc->destruction_listeners,
+ struct bt_trace_class_destruction_listener_elem,
+ listener_id);
+ BT_ASSERT(elem->func);
+
+ elem->func = NULL;
+ elem->data = NULL;
+ BT_LIB_LOGV("Removed trace class destruction listener: "
+ "%![tc-]+T, listener-id=%" PRIu64,
+ tc, listener_id);
+ return BT_TRACE_CLASS_STATUS_OK;
+}
+
BT_ASSERT_FUNC
static
bool trace_has_environment_entry(const struct bt_trace_class *tc, const char *name)
struct bt_value *value_obj;
BT_ASSERT_PRE_NON_NULL(tc, "Trace class");
BT_ASSERT_PRE_NON_NULL(name, "Name");
- value_obj = bt_value_integer_create_init(value);
+ value_obj = bt_value_signed_integer_create_init(value);
if (!value_obj) {
BT_LOGE_STR("Cannot create an integer value object.");
ret = BT_TRACE_CLASS_STATUS_NOMEM;