tracer: use GQuark or strings for the hook id
[platform/upstream/gstreamer.git] / gst / gsttracerutils.c
1 /* GStreamer
2  * Copyright (C) 2013 Stefan Sauer <ensonic@users.sf.net>
3  *
4  * gsttracerutils.c: tracing subsystem
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  */
21
22 /**
23  * SECTION:gsttracerutils
24  * @short_description: Tracing subsystem
25  *
26  * The tracing subsystem provides hooks in the core library and API for modules
27  * to attach to them.
28  *
29  * The user can activate tracers by setting the environment variable GST_TRACE
30  * to a ';' separated list of tracers.
31  */
32
33 #define GST_USE_UNSTABLE_API
34
35 #include "gst_private.h"
36 #include "gsttracer.h"
37 #include "gsttracerfactory.h"
38 #include "gsttracerutils.h"
39
40 #ifndef GST_DISABLE_GST_DEBUG
41
42 /* tracer quarks */
43
44 /* These strings must match order and number declared in the GstTracerQuarkId
45  * enum in gsttracerutils.h! */
46 static const gchar *_quark_strings[] = {
47   "pad-push-pre", "pad-push-post", "pad-push-list-pre", "pad-push-list-post",
48   "pad-pull-range-pre", "pad-pull-range-post", "pad-push-event-pre",
49   "pad-push-event-post", "element-post-message-pre",
50   "element-post-message-post", "element-query-pre", "element-query-post"
51 };
52
53 GQuark _priv_gst_tracer_quark_table[GST_TRACER_QUARK_MAX];
54
55 /* tracing helpers */
56
57 gboolean _priv_tracer_enabled = FALSE;
58 GHashTable *_priv_tracers = NULL;
59
60 typedef struct
61 {
62   GstTracer *tracer;
63   GstTracerHookFunction func;
64 } GstTracerHook;
65
66 /* Initialize the tracing system */
67 void
68 _priv_gst_tracer_init (void)
69 {
70   const gchar *env = g_getenv ("GST_TRACE");
71
72   if (env != NULL && *env != '\0') {
73     GstRegistry *registry = gst_registry_get ();
74     GstPluginFeature *feature;
75     GstTracerFactory *factory;
76     gchar **t = g_strsplit_set (env, ";", 0);
77     gint i = 0;
78     gchar *params;
79
80     GST_INFO ("enabling tracers: '%s'", env);
81
82     if (G_N_ELEMENTS (_quark_strings) != GST_TRACER_QUARK_MAX)
83       g_warning ("the quark table is not consistent! %d != %d",
84           (gint) G_N_ELEMENTS (_quark_strings), GST_TRACER_QUARK_MAX);
85
86     for (i = 0; i < GST_TRACER_QUARK_MAX; i++) {
87       _priv_gst_tracer_quark_table[i] =
88           g_quark_from_static_string (_quark_strings[i]);
89     }
90
91     _priv_tracers = g_hash_table_new (NULL, NULL);
92
93     i = 0;
94     while (t[i]) {
95       // check t[i] for params
96       if ((params = strchr (t[i], '('))) {
97         gchar *end = strchr (&params[1], ')');
98         *params = '\0';
99         params++;
100         if (end)
101           *end = '\0';
102       } else {
103         params = NULL;
104       }
105
106       GST_INFO ("checking tracer: '%s'", t[i]);
107
108       if ((feature = gst_registry_lookup_feature (registry, t[i]))) {
109         factory = GST_TRACER_FACTORY (gst_plugin_feature_load (feature));
110         if (factory) {
111           GST_INFO_OBJECT (factory, "creating tracer: type-id=%u",
112               (guint) factory->type);
113
114           /* tracers register them self to the hooks */
115           gst_object_unref (g_object_new (factory->type, "params", params,
116                   NULL));
117         } else {
118           GST_WARNING_OBJECT (feature,
119               "loading plugin containing feature %s failed!", t[i]);
120         }
121       } else {
122         GST_WARNING ("no tracer named '%s'", t[i]);
123       }
124       i++;
125     }
126     g_strfreev (t);
127   }
128 }
129
130 void
131 _priv_gst_tracer_deinit (void)
132 {
133   GList *h_list, *h_node, *t_node;
134   GstTracerHook *hook;
135
136   _priv_tracer_enabled = FALSE;
137   if (!_priv_tracers)
138     return;
139
140   /* shutdown tracers for final reports */
141   h_list = g_hash_table_get_values (_priv_tracers);
142   for (h_node = h_list; h_node; h_node = g_list_next (h_node)) {
143     for (t_node = h_node->data; t_node; t_node = g_list_next (t_node)) {
144       hook = (GstTracerHook *) t_node->data;
145       gst_object_unref (hook->tracer);
146       g_slice_free (GstTracerHook, hook);
147     }
148     g_list_free (h_node->data);
149   }
150   g_list_free (h_list);
151   g_hash_table_destroy (_priv_tracers);
152   _priv_tracers = NULL;
153 }
154
155 void
156 gst_tracer_register_hook_id (GstTracer * tracer, GQuark detail,
157     GstTracerHookFunction func)
158 {
159   gpointer key = GINT_TO_POINTER (detail);
160   GList *list = g_hash_table_lookup (_priv_tracers, key);
161   GstTracerHook *hook = g_slice_new0 (GstTracerHook);
162   hook->tracer = gst_object_ref (tracer);
163   hook->func = func;
164
165   list = g_list_prepend (list, hook);
166   g_hash_table_replace (_priv_tracers, key, list);
167   GST_DEBUG ("registering tracer for '%s', list.len=%d",
168       (detail ? g_quark_to_string (detail) : "*"), g_list_length (list));
169   _priv_tracer_enabled = TRUE;
170 }
171
172 void
173 gst_tracer_register_hook (GstTracer * tracer, const gchar * detail,
174     GstTracerHookFunction func)
175 {
176   gst_tracer_register_hook_id (tracer, g_quark_try_string (detail), func);
177 }
178
179 void
180 gst_tracer_dispatch (GQuark detail, ...)
181 {
182   va_list var_args;
183   gpointer key = GINT_TO_POINTER (detail);
184   GList *list, *node;
185   GstTracerHook *hook;
186
187   list = g_hash_table_lookup (_priv_tracers, key);
188   GST_DEBUG ("calling %d tracers for '%s'", g_list_length (list),
189       g_quark_to_string (detail));
190   for (node = list; node; node = g_list_next (node)) {
191     hook = (GstTracerHook *) node->data;
192     va_start (var_args, detail);
193     hook->func (hook->tracer, var_args);
194     va_end (var_args);
195   }
196   list = g_hash_table_lookup (_priv_tracers, NULL);
197   GST_DEBUG ("calling %d tracers for '*'", g_list_length (list));
198   for (node = list; node; node = g_list_next (node)) {
199     hook = (GstTracerHook *) node->data;
200     va_start (var_args, detail);
201     hook->func (hook->tracer, var_args);
202     va_end (var_args);
203   }
204 }
205
206 #endif /* GST_DISABLE_GST_DEBUG */