lib: replace trace is_static with destruction listeners
[babeltrace.git] / lib / trace-ir / trace-class.c
index 7fa6a2f515b62ed2fda8f977e1b1a6cc474afdd0..3aa398fb94904744f0906925bfdbbe457c3ea76a 100644 (file)
 #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))
 
@@ -63,6 +68,26 @@ void destroy_trace_class(struct bt_object *obj)
        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);
+               /* 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);
+                       }
+               }
+               g_array_free(tc->destruction_listeners, TRUE);
+               tc->destruction_listeners = NULL;
+       }
 
        if (tc->environment) {
                BT_LOGD_STR("Destroying environment attributes.");
@@ -118,6 +143,13 @@ struct bt_trace_class *bt_trace_class_create(bt_self_component *self_comp)
                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;
@@ -163,6 +195,80 @@ void bt_trace_class_set_uuid(struct bt_trace_class *tc, bt_uuid uuid)
        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)
This page took 0.023542 seconds and 4 git commands to generate.