gstreamer/gst/gsttracerutils.c
Sebastian Dröge 9d91ad0b85 tracer: Use GST_DISABLE_GST_TRACER_HOOKS instead of GST_DISABLE_GST_DEBUG everywhere
Previously we used the latter one still for the tracer utility code, causing
undefined references in the resulting binary if the debugging system was
disabled but the tracer system not.
2016-01-07 18:46:21 +02:00

187 lines
5.6 KiB
C

/* GStreamer
* Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
*
* gsttracerutils.c: tracing subsystem
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
/**
* SECTION:gsttracerutils
* @short_description: 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.
*/
#define GST_USE_UNSTABLE_API
#include "gst_private.h"
#include "gsttracer.h"
#include "gsttracerfactory.h"
#include "gsttracerutils.h"
#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"
};
GQuark _priv_gst_tracer_quark_table[GST_TRACER_QUARK_MAX];
/* tracing helpers */
gboolean _priv_tracer_enabled = FALSE;
GHashTable *_priv_tracers = NULL;
/* Initialize the tracing system */
void
_priv_gst_tracing_init (void)
{
const gchar *env = g_getenv ("GST_TRACER_PLUGINS");
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);
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]);
}
_priv_tracers = g_hash_table_new (NULL, NULL);
i = 0;
while (t[i]) {
// check t[i] for params
if ((params = strchr (t[i], '('))) {
gchar *end = strchr (&params[1], ')');
*params = '\0';
params++;
if (end)
*end = '\0';
} else {
params = NULL;
}
GST_INFO ("checking tracer: '%s'", t[i]);
if ((feature = gst_registry_lookup_feature (registry, t[i]))) {
factory = GST_TRACER_FACTORY (gst_plugin_feature_load (feature));
if (factory) {
GST_INFO_OBJECT (factory, "creating tracer: type-id=%u",
(guint) factory->type);
/* tracers register them self to the hooks */
gst_object_unref (g_object_new (factory->type, "params", params,
NULL));
} else {
GST_WARNING_OBJECT (feature,
"loading plugin containing feature %s failed!", t[i]);
}
} else {
GST_WARNING ("no tracer named '%s'", t[i]);
}
i++;
}
g_strfreev (t);
}
}
void
_priv_gst_tracing_deinit (void)
{
GList *h_list, *h_node, *t_node;
GstTracerHook *hook;
_priv_tracer_enabled = FALSE;
if (!_priv_tracers)
return;
/* shutdown tracers for final reports */
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 (h_node->data);
}
g_list_free (h_list);
g_hash_table_destroy (_priv_tracers);
_priv_tracers = NULL;
}
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;
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_tracing_register_hook (GstTracer * tracer, const gchar * detail,
GCallback func)
{
gst_tracing_register_hook_id (tracer, g_quark_try_string (detail), func);
}
#endif /* GST_DISABLE_GST_DEBUG */