GPtrArray *listeners; /* Array of struct listener_wrapper */
GArray *is_static_listeners;
bt_bool is_static;
+ bt_bool in_remove_listener;
};
struct metadata_context {
typedef void (* bt_ctf_trace_is_static_listener)(
struct bt_ctf_trace *trace_class, void *data);
+/**
+@brief User function type to use with
+ bt_ctf_trace_add_is_static_listener().
+
+@param[in] trace_class Trace class to which the listener was added.
+@param[in] data User data as passed to
+ bt_ctf_trace_add_is_static_listener() when
+ you added the listener.
+
+@prenotnull{trace_class}
+*/
+typedef void (* bt_ctf_trace_listener_removed)(
+ struct bt_ctf_trace *trace_class, void *data);
+
/**
@name Creation function
@{
\p listener is called with \p data, the user data, the first time
bt_ctf_trace_set_is_static() is called on \p trace_class.
+When the trace is destroyed, or when you remove the added listener with
+bt_ctf_trace_remove_is_static_listener(), \p listener_removed is called
+if it's not \c NULL. You can use \p listener_removed to free any dynamic
+data which exists only for the added listener. You cannot call
+any function which modifies \p trace_class during the execution of
+\p listener_removed, including bt_ctf_trace_remove_is_static_listener().
+
This function fails if \p trace_class is already static: you need to
check the condition first with bt_ctf_trace_is_static().
specific listener you added with
bt_ctf_trace_remove_is_static_listener().
-@param[in] trace_class Trace class to which to add the listener.
-@param[in] listener Listener to add to \p trace_class.
-@param[in] data User data passed when \p listener is called.
-@returns A unique numeric identifier for this listener
- on success (0 or greater), or a negative value
- on error.
+@param[in] trace_class Trace class to which to add the
+ listener.
+@param[in] listener Listener to add to \p trace_class.
+@param[in] listener_removed Remove listener called when \p listener
+ is removed from \p trace_class, or
+ \c NULL if you don't need a remove
+ listener.
+@param[in] data User data passed when \p listener or
+ \p listener_removed is called.
+@returns A unique numeric identifier for this
+ listener on success (0 or greater), or a
+ negative value on error.
@prenotnull{trace_class}
@prenotnull{listener}
*/
extern int bt_ctf_trace_add_is_static_listener(
struct bt_ctf_trace *trace_class,
- bt_ctf_trace_is_static_listener listener, void *data);
+ bt_ctf_trace_is_static_listener listener,
+ bt_ctf_trace_listener_removed listener_removed, void *data);
/**
@brief Removes the "trace is static" listener identified by
struct bt_ctf_trace_is_static_listener_elem {
bt_ctf_trace_is_static_listener func;
+ bt_ctf_trace_listener_removed removed;
void *data;
};
BT_LOGD("Destroying trace object: addr=%p, name=\"%s\"",
trace, bt_ctf_trace_get_name(trace));
+ /*
+ * Call remove listeners first so that everything else still
+ * exists in the trace.
+ */
+ if (trace->is_static_listeners) {
+ size_t i;
+
+ for (i = 0; i < trace->is_static_listeners->len; i++) {
+ struct bt_ctf_trace_is_static_listener_elem elem =
+ g_array_index(trace->is_static_listeners,
+ struct bt_ctf_trace_is_static_listener_elem, i);
+
+ if (elem.removed) {
+ elem.removed(trace, elem.data);
+ }
+ }
+
+ g_array_free(trace->is_static_listeners, TRUE);
+ }
+
+ if (trace->listeners) {
+ g_ptr_array_free(trace->listeners, TRUE);
+ }
+
if (trace->environment) {
BT_LOGD_STR("Destroying environment attributes.");
bt_ctf_attributes_destroy(trace->environment);
g_ptr_array_free(trace->stream_classes, TRUE);
}
- if (trace->listeners) {
- g_ptr_array_free(trace->listeners, TRUE);
- }
-
- if (trace->is_static_listeners) {
- g_array_free(trace->is_static_listeners, TRUE);
- }
-
BT_LOGD_STR("Putting packet header field type.");
bt_put(trace->packet_header_type);
g_free(trace);
}
int bt_ctf_trace_add_is_static_listener(struct bt_ctf_trace *trace,
- bt_ctf_trace_is_static_listener listener, void *data)
+ bt_ctf_trace_is_static_listener listener,
+ bt_ctf_trace_listener_removed listener_removed, void *data)
{
int i;
struct bt_ctf_trace_is_static_listener_elem new_elem = {
.func = listener,
+ .removed = listener_removed,
.data = data,
};
goto end;
}
+ if (trace->in_remove_listener) {
+ BT_LOGW("Cannot call this function during the execution of a remove listener: "
+ "addr=%p, name=\"%s\"",
+ trace, bt_ctf_trace_get_name(trace));
+ i = -1;
+ goto end;
+ }
+
/* Find the next available spot */
for (i = 0; i < trace->is_static_listeners->len; i++) {
struct bt_ctf_trace_is_static_listener_elem elem =
goto end;
}
+ if (trace->in_remove_listener) {
+ BT_LOGW("Cannot call this function during the execution of a remove listener: "
+ "addr=%p, name=\"%s\", listener-id=%d",
+ trace, bt_ctf_trace_get_name(trace),
+ listener_id);
+ ret = -1;
+ goto end;
+ }
+
if (listener_id < 0) {
BT_LOGW("Invalid listener ID: must be zero or positive: "
"listener-id=%d", listener_id);
goto end;
}
+ if (elem->removed) {
+ /* Call remove listener */
+ BT_LOGV("Calling remove listener: "
+ "trace-addr=%p, trace-name=\"%s\", "
+ "listener-id=%d", trace, bt_ctf_trace_get_name(trace),
+ listener_id);
+ trace->in_remove_listener = BT_TRUE;
+ elem->removed(trace, elem->data);
+ trace->in_remove_listener = BT_FALSE;
+ }
+
elem->func = NULL;
+ elem->removed = NULL;
elem->data = NULL;
BT_LOGV("Removed \"trace is static\" listener: "
"trace-addr=%p, trace-name=\"%s\", "
fs_writer->static_listener_id = -1;
} else {
ret = bt_ctf_trace_add_is_static_listener(trace,
- trace_is_static_listener, fs_writer);
+ trace_is_static_listener, NULL, fs_writer);
assert(ret >= 0);
fs_writer->static_listener_id = ret;
}
bt_ctf_trace_set_is_static(writer_trace);
} else {
ret = bt_ctf_trace_add_is_static_listener(trace,
- trace_is_static_listener, di_trace);
+ trace_is_static_listener, NULL, di_trace);
assert(ret >= 0);
di_trace->static_listener_id = ret;
}
#define DEFAULT_CLOCK_TIME 0
#define DEFAULT_CLOCK_VALUE 0
-#define NR_TESTS 622
+#define NR_TESTS 623
static int64_t current_time = 42;
static unsigned int packet_resize_test_length = PACKET_RESIZE_TEST_DEF_LENGTH;
static
void trace_is_static_listener(struct bt_ctf_trace *trace, void *data)
{
- *((int *) data) = 1;
+ *((int *) data) |= 1;
+}
+
+static
+void trace_listener_removed(struct bt_ctf_trace *trace, void *data)
+{
+ *((int *) data) |= 2;
}
static
trace = bt_ctf_trace_create();
assert(trace);
ret = bt_ctf_trace_add_is_static_listener(NULL,
- trace_is_static_listener, &called1);
+ trace_is_static_listener, trace_listener_removed, &called1);
ok(ret < 0, "bt_ctf_trace_add_is_static_listener() handles NULL (trace)");
- ret = bt_ctf_trace_add_is_static_listener(trace, NULL, &called1);
+ ret = bt_ctf_trace_add_is_static_listener(trace, NULL,
+ trace_listener_removed, &called1);
ok(ret < 0, "bt_ctf_trace_add_is_static_listener() handles NULL (listener)");
listener1_id = bt_ctf_trace_add_is_static_listener(trace,
- trace_is_static_listener, &called1);
+ trace_is_static_listener, trace_listener_removed, &called1);
ok(listener1_id >= 0, "bt_ctf_trace_add_is_static_listener() succeeds (1)");
listener2_id = bt_ctf_trace_add_is_static_listener(trace,
- trace_is_static_listener, &called2);
+ trace_is_static_listener, trace_listener_removed, &called2);
ok(listener2_id >= 0, "bt_ctf_trace_add_is_static_listener() succeeds (2)");
listener3_id = bt_ctf_trace_add_is_static_listener(trace,
- trace_is_static_listener, &called3);
+ trace_is_static_listener, trace_listener_removed, &called3);
ok(listener3_id >= 0, "bt_ctf_trace_add_is_static_listener() succeeds (3)");
ret = bt_ctf_trace_remove_is_static_listener(NULL, 0);
ok(ret < 0, "bt_ctf_trace_remove_is_static_listener() handles NULL (trace)");
ok(ret < 0, "bt_ctf_trace_remove_is_static_listener() handles invalid ID (non existing)");
ret = bt_ctf_trace_remove_is_static_listener(trace, listener2_id);
ok(ret == 0, "bt_ctf_trace_remove_is_static_listener() succeeds");
+ ok(called2 == 2, "bt_ctf_trace_remove_is_static_listener() calls the remove listener");
listener4_id = bt_ctf_trace_add_is_static_listener(trace,
- trace_is_static_listener, &called4);
+ trace_is_static_listener, NULL, &called4);
ok(listener4_id >= 0, "bt_ctf_trace_add_is_static_listener() succeeds (4)");
ok(called1 == 0, "\"trace is static\" listener not called before the trace is made static (1)");
- ok(called2 == 0, "\"trace is static\" listener not called before the trace is made static (2)");
+ ok(called2 == 2, "\"trace is static\" listener not called before the trace is made static (2)");
ok(called3 == 0, "\"trace is static\" listener not called before the trace is made static (3)");
ok(called4 == 0, "\"trace is static\" listener not called before the trace is made static (4)");
ret = bt_ctf_trace_set_is_static(trace);
assert(ret == 0);
ret = bt_ctf_trace_add_is_static_listener(trace,
- trace_is_static_listener, &called1);
+ trace_is_static_listener, trace_listener_removed, &called1);
ok(ret < 0,
"bt_ctf_trace_add_is_static_listener() fails when the trace is static");
ok(called1 == 1, "\"trace is static\" listener called when the trace is made static (1)");
- ok(called2 == 0, "\"trace is static\" listener not called when the trace is made static (2)");
+ ok(called2 == 2, "\"trace is static\" listener not called when the trace is made static (2)");
ok(called3 == 1, "\"trace is static\" listener called when the trace is made static (3)");
ok(called4 == 1, "\"trace is static\" listener called when the trace is made static (4)");
called1 = 0;
called3 = 0;
called4 = 0;
bt_put(trace);
- ok(called1 == 0, "\"trace is static\" listener not called after the trace is put (1)");
+ ok(called1 == 2, "\"trace is static\" listener not called after the trace is put (1)");
ok(called2 == 0, "\"trace is static\" listener not called after the trace is put (2)");
- ok(called3 == 0, "\"trace is static\" listener not called after the trace is put (3)");
+ ok(called3 == 2, "\"trace is static\" listener not called after the trace is put (3)");
ok(called4 == 0, "\"trace is static\" listener not called after the trace is put (4)");
}