* Boston, MA 02110-1301, USA.
*/
-/**
- * SECTION:gsttracerutils
- * @short_description: Tracing subsystem
+/* Tracing subsystem:
*
* The tracing subsystem provides hooks in the core library and API for modules
* to attach to them.
*
* The user can activate tracers by setting the environment variable GST_TRACE
* to a ';' separated list of tracers.
+ *
+ * Note that instantiating tracers at runtime is possible but is not thread safe
+ * and needs to be done before any pipeline state is set to PAUSED.
*/
#define GST_USE_UNSTABLE_API
#include "gsttracerfactory.h"
#include "gsttracerutils.h"
-#ifndef GST_DISABLE_GST_DEBUG
+#ifndef GST_DISABLE_GST_TRACER_HOOKS
+
+/* tracer quarks */
+
+/* These strings must match order and number declared in the GstTracerQuarkId
+ * enum in gsttracerutils.h! */
+static const gchar *_quark_strings[] = {
+ "pad-push-pre", "pad-push-post", "pad-push-list-pre", "pad-push-list-post",
+ "pad-pull-range-pre", "pad-pull-range-post", "pad-push-event-pre",
+ "pad-push-event-post", "pad-query-pre", "pad-query-post",
+ "element-post-message-pre",
+ "element-post-message-post", "element-query-pre", "element-query-post",
+ "element-new", "element-add-pad", "element-remove-pad",
+ "bin-add-pre", "bin-add-post", "bin-remove-pre", "bin-remove-post",
+ "pad-link-pre", "pad-link-post", "pad-unlink-pre", "pad-unlink-post",
+ "element-change-state-pre", "element-change-state-post",
+ "mini-object-created", "mini-object-destroyed", "object-created",
+ "object-destroyed", "mini-object-reffed", "mini-object-unreffed",
+ "object-reffed", "object-unreffed",
+};
+
+GQuark _priv_gst_tracer_quark_table[GST_TRACER_QUARK_MAX];
/* tracing helpers */
gboolean _priv_tracer_enabled = FALSE;
-/* TODO(ensonic): use array of GPtrArray* ? */
-GList *_priv_tracers[GST_TRACER_HOOK_ID_LAST] = { NULL, };
-
-typedef struct
-{
- GstTracer *tracer;
- GstTracerHookFunction func;
-} GstTracerHook;
+GHashTable *_priv_tracers = NULL;
/* Initialize the tracing system */
void
-_priv_gst_tracer_init (void)
+_priv_gst_tracing_init (void)
{
- const gchar *env = g_getenv ("GST_TRACE");
+ gint i = 0;
+ const gchar *env = g_getenv ("GST_TRACERS");
+
+ /* We initialize the tracer sub system even if the end
+ * user did not activate it through the env variable
+ * so that external tools can use it anyway */
+ GST_DEBUG ("Initializing GstTracer");
+ _priv_tracers = g_hash_table_new (NULL, NULL);
+
+ if (G_N_ELEMENTS (_quark_strings) != GST_TRACER_QUARK_MAX)
+ g_warning ("the quark table is not consistent! %d != %d",
+ (gint) G_N_ELEMENTS (_quark_strings), GST_TRACER_QUARK_MAX);
+
+ for (i = 0; i < GST_TRACER_QUARK_MAX; i++) {
+ _priv_gst_tracer_quark_table[i] =
+ g_quark_from_static_string (_quark_strings[i]);
+ }
if (env != NULL && *env != '\0') {
GstRegistry *registry = gst_registry_get ();
GstPluginFeature *feature;
GstTracerFactory *factory;
gchar **t = g_strsplit_set (env, ";", 0);
- gint i = 0;
gchar *params;
GST_INFO ("enabling tracers: '%s'", env);
-
+ i = 0;
while (t[i]) {
// check t[i] for params
if ((params = strchr (t[i], '('))) {
if ((feature = gst_registry_lookup_feature (registry, t[i]))) {
factory = GST_TRACER_FACTORY (gst_plugin_feature_load (feature));
if (factory) {
+ GstTracer *tracer;
+
GST_INFO_OBJECT (factory, "creating tracer: type-id=%u",
(guint) factory->type);
+ tracer = g_object_new (factory->type, "params", params, NULL);
+
+ /* Clear floating flag */
+ gst_object_ref_sink (tracer);
+
/* tracers register them self to the hooks */
- gst_object_unref (g_object_new (factory->type, "params", params,
- NULL));
+ gst_object_unref (tracer);
} else {
GST_WARNING_OBJECT (feature,
"loading plugin containing feature %s failed!", t[i]);
}
void
-_priv_gst_tracer_deinit (void)
+_priv_gst_tracing_deinit (void)
{
- gint i;
- GList *node;
+ GList *h_list, *h_node, *t_node;
GstTracerHook *hook;
+ _priv_tracer_enabled = FALSE;
+ if (!_priv_tracers)
+ return;
+
/* shutdown tracers for final reports */
- for (i = 0; i < GST_TRACER_HOOK_ID_LAST; i++) {
- for (node = _priv_tracers[i]; node; node = g_list_next (node)) {
- hook = (GstTracerHook *) node->data;
+ h_list = g_hash_table_get_values (_priv_tracers);
+ for (h_node = h_list; h_node; h_node = g_list_next (h_node)) {
+ for (t_node = h_node->data; t_node; t_node = g_list_next (t_node)) {
+ hook = (GstTracerHook *) t_node->data;
gst_object_unref (hook->tracer);
g_slice_free (GstTracerHook, hook);
}
- g_list_free (_priv_tracers[i]);
- _priv_tracers[i] = NULL;
+ g_list_free (h_node->data);
}
- _priv_tracer_enabled = FALSE;
+ g_list_free (h_list);
+ g_hash_table_destroy (_priv_tracers);
+ _priv_tracers = NULL;
}
-void
-gst_tracer_register_hook (GstTracer * tracer, GstTracerHookId id,
- GstTracerHookFunction func)
+static void
+gst_tracing_register_hook_id (GstTracer * tracer, GQuark detail, GCallback func)
{
+ gpointer key = GINT_TO_POINTER (detail);
+ GList *list = g_hash_table_lookup (_priv_tracers, key);
GstTracerHook *hook = g_slice_new0 (GstTracerHook);
hook->tracer = gst_object_ref (tracer);
hook->func = func;
- _priv_tracers[id] = g_list_prepend (_priv_tracers[id], hook);
- GST_DEBUG_OBJECT (tracer, "added tracer to hook %d", id);
+
+ list = g_list_prepend (list, hook);
+ g_hash_table_replace (_priv_tracers, key, list);
+ GST_DEBUG ("registering tracer for '%s', list.len=%d",
+ (detail ? g_quark_to_string (detail) : "*"), g_list_length (list));
_priv_tracer_enabled = TRUE;
}
+/**
+ * gst_tracing_register_hook:
+ * @tracer: the tracer
+ * @detail: the detailed hook
+ * @func: (scope async): the callback
+ *
+ * Register @func to be called when the trace hook @detail is getting invoked.
+ * Use %NULL for @detail to register to all hooks.
+ */
void
-gst_tracer_dispatch (GstTracerHookId id, ...)
+gst_tracing_register_hook (GstTracer * tracer, const gchar * detail,
+ GCallback func)
{
- va_list var_args;
- GList *node;
- GstTracerHook *hook;
+ gst_tracing_register_hook_id (tracer, g_quark_try_string (detail), func);
+}
- for (node = _priv_tracers[id]; node; node = g_list_next (node)) {
- hook = (GstTracerHook *) node->data;
- va_start (var_args, id);
- hook->func (hook->tracer, var_args);
- va_end (var_args);
- }
+#else /* !GST_DISABLE_GST_TRACER_HOOKS */
+
+void
+gst_tracing_register_hook (GstTracer * tracer, const gchar * detail,
+ GCallback func)
+{
}
-#endif /* GST_DISABLE_GST_DEBUG */
+#endif /* GST_DISABLE_GST_TRACER_HOOKS */