1 | /* GStreamer |
---|
2 | * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu> |
---|
3 | * 2000 Wim Taymans <wtay@chello.be> |
---|
4 | * 2003 Benjamin Otte <in7y118@public.uni-hamburg.de> |
---|
5 | * |
---|
6 | * gstinfo.c: debugging functions |
---|
7 | * |
---|
8 | * This library is free software; you can redistribute it and/or |
---|
9 | * modify it under the terms of the GNU Library General Public |
---|
10 | * License as published by the Free Software Foundation; either |
---|
11 | * version 2 of the License, or (at your option) any later version. |
---|
12 | * |
---|
13 | * This library is distributed in the hope that it will be useful, |
---|
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
16 | * Library General Public License for more details. |
---|
17 | * |
---|
18 | * You should have received a copy of the GNU Library General Public |
---|
19 | * License along with this library; if not, write to the |
---|
20 | * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
21 | * Boston, MA 02111-1307, USA. |
---|
22 | */ |
---|
23 | |
---|
24 | #include "gst_private.h" |
---|
25 | #include "gstinfo.h" |
---|
26 | |
---|
27 | #ifndef GST_DISABLE_GST_DEBUG |
---|
28 | |
---|
29 | #ifdef HAVE_DLFCN_H |
---|
30 | #include <dlfcn.h> |
---|
31 | #endif |
---|
32 | #ifdef HAVE_PRINTF_EXTENSION |
---|
33 | #include <printf.h> |
---|
34 | #endif |
---|
35 | #include <stdio.h> /* fprintf */ |
---|
36 | #ifdef HAVE_UNISTD_H |
---|
37 | #include <unistd.h> |
---|
38 | #endif |
---|
39 | #include <string.h> /* G_VA_COPY */ |
---|
40 | #include "gstelement.h" |
---|
41 | #include "gstpad.h" |
---|
42 | #include "gstscheduler.h" |
---|
43 | #include "gst_private.h" |
---|
44 | #ifdef HAVE_VALGRIND |
---|
45 | #include <valgrind/valgrind.h> |
---|
46 | #endif |
---|
47 | |
---|
48 | /* underscore is to prevent conflict with GST_CAT_DEBUG define */ |
---|
49 | GST_DEBUG_CATEGORY_STATIC (_GST_CAT_DEBUG); |
---|
50 | |
---|
51 | #if 0 |
---|
52 | #if defined __sgi__ |
---|
53 | #include <rld_interface.h> |
---|
54 | typedef struct DL_INFO |
---|
55 | { |
---|
56 | const char *dli_fname; |
---|
57 | void *dli_fbase; |
---|
58 | const char *dli_sname; |
---|
59 | void *dli_saddr; |
---|
60 | int dli_version; |
---|
61 | int dli_reserved1; |
---|
62 | long dli_reserved[4]; |
---|
63 | } |
---|
64 | Dl_info; |
---|
65 | |
---|
66 | #define _RLD_DLADDR 14 |
---|
67 | int dladdr (void *address, Dl_info * dl); |
---|
68 | |
---|
69 | int |
---|
70 | dladdr (void *address, Dl_info * dl) |
---|
71 | { |
---|
72 | void *v; |
---|
73 | |
---|
74 | v = _rld_new_interface (_RLD_DLADDR, address, dl); |
---|
75 | return (int) v; |
---|
76 | } |
---|
77 | #endif /* __sgi__ */ |
---|
78 | #endif |
---|
79 | |
---|
80 | static void gst_debug_reset_threshold (gpointer category, gpointer unused); |
---|
81 | static void gst_debug_reset_all_thresholds (void); |
---|
82 | |
---|
83 | #ifdef HAVE_PRINTF_EXTENSION |
---|
84 | static int _gst_info_printf_extension (FILE * stream, |
---|
85 | const struct printf_info *info, const void *const *args); |
---|
86 | static int _gst_info_printf_extension_arginfo (const struct printf_info *info, |
---|
87 | size_t n, int *argtypes); |
---|
88 | #endif |
---|
89 | |
---|
90 | struct _GstDebugMessage |
---|
91 | { |
---|
92 | gchar *message; |
---|
93 | const gchar *format; |
---|
94 | va_list arguments; |
---|
95 | }; |
---|
96 | |
---|
97 | /* list of all name/level pairs from --gst-debug and GST_DEBUG */ |
---|
98 | static GStaticMutex __level_name_mutex = G_STATIC_MUTEX_INIT; |
---|
99 | static GSList *__level_name = NULL; |
---|
100 | typedef struct |
---|
101 | { |
---|
102 | GPatternSpec *pat; |
---|
103 | GstDebugLevel level; |
---|
104 | } |
---|
105 | LevelNameEntry; |
---|
106 | |
---|
107 | /* list of all categories */ |
---|
108 | static GStaticMutex __cat_mutex = G_STATIC_MUTEX_INIT; |
---|
109 | static GSList *__categories = NULL; |
---|
110 | |
---|
111 | /* all registered debug handlers */ |
---|
112 | typedef struct |
---|
113 | { |
---|
114 | GstLogFunction func; |
---|
115 | gpointer user_data; |
---|
116 | } |
---|
117 | LogFuncEntry; |
---|
118 | static GStaticMutex __log_func_mutex = G_STATIC_MUTEX_INIT; |
---|
119 | static GSList *__log_functions = NULL; |
---|
120 | |
---|
121 | static GstAtomicInt __default_level; |
---|
122 | static GstAtomicInt __use_color; |
---|
123 | gboolean __gst_debug_enabled = TRUE; |
---|
124 | |
---|
125 | |
---|
126 | GstDebugCategory *GST_CAT_DEFAULT = NULL; |
---|
127 | |
---|
128 | GstDebugCategory *GST_CAT_GST_INIT = NULL; |
---|
129 | GstDebugCategory *GST_CAT_COTHREADS = NULL; |
---|
130 | GstDebugCategory *GST_CAT_COTHREAD_SWITCH = NULL; |
---|
131 | GstDebugCategory *GST_CAT_AUTOPLUG = NULL; |
---|
132 | GstDebugCategory *GST_CAT_AUTOPLUG_ATTEMPT = NULL; |
---|
133 | GstDebugCategory *GST_CAT_PARENTAGE = NULL; |
---|
134 | GstDebugCategory *GST_CAT_STATES = NULL; |
---|
135 | GstDebugCategory *GST_CAT_PLANNING = NULL; |
---|
136 | GstDebugCategory *GST_CAT_SCHEDULING = NULL; |
---|
137 | |
---|
138 | /* FIXME: remove GST_CAT_DATAFLOW in 0.9 */ |
---|
139 | GstDebugCategory *GST_CAT_DATAFLOW = NULL; |
---|
140 | GstDebugCategory *GST_CAT_BUFFER = NULL; |
---|
141 | GstDebugCategory *GST_CAT_CAPS = NULL; |
---|
142 | GstDebugCategory *GST_CAT_CLOCK = NULL; |
---|
143 | GstDebugCategory *GST_CAT_ELEMENT_PADS = NULL; |
---|
144 | GstDebugCategory *GST_CAT_PADS = NULL; |
---|
145 | GstDebugCategory *GST_CAT_PIPELINE = NULL; |
---|
146 | GstDebugCategory *GST_CAT_PLUGIN_LOADING = NULL; |
---|
147 | GstDebugCategory *GST_CAT_PLUGIN_INFO = NULL; |
---|
148 | GstDebugCategory *GST_CAT_PROPERTIES = NULL; |
---|
149 | GstDebugCategory *GST_CAT_THREAD = NULL; |
---|
150 | GstDebugCategory *GST_CAT_TYPES = NULL; |
---|
151 | GstDebugCategory *GST_CAT_XML = NULL; |
---|
152 | GstDebugCategory *GST_CAT_NEGOTIATION = NULL; |
---|
153 | GstDebugCategory *GST_CAT_REFCOUNTING = NULL; |
---|
154 | GstDebugCategory *GST_CAT_ERROR_SYSTEM = NULL; |
---|
155 | GstDebugCategory *GST_CAT_EVENT = NULL; |
---|
156 | GstDebugCategory *GST_CAT_PARAMS = NULL; |
---|
157 | GstDebugCategory *GST_CAT_CALL_TRACE = NULL; |
---|
158 | GstDebugCategory *GST_CAT_SEEK = NULL; |
---|
159 | GstDebugCategory *GST_CAT_SIGNAL = NULL; |
---|
160 | GstDebugCategory *GST_CAT_PROBE = NULL; |
---|
161 | |
---|
162 | /* FIXME: export this? */ |
---|
163 | gboolean |
---|
164 | __gst_in_valgrind (void) |
---|
165 | { |
---|
166 | static enum |
---|
167 | { |
---|
168 | GST_VG_UNCHECKED, |
---|
169 | GST_VG_NO_VALGRIND, |
---|
170 | GST_VG_INSIDE |
---|
171 | } |
---|
172 | in_valgrind = GST_VG_UNCHECKED; |
---|
173 | |
---|
174 | if (in_valgrind == GST_VG_UNCHECKED) { |
---|
175 | #ifdef HAVE_VALGRIND |
---|
176 | if (RUNNING_ON_VALGRIND) { |
---|
177 | GST_CAT_INFO (GST_CAT_GST_INIT, "we're running inside valgrind"); |
---|
178 | VALGRIND_PRINTF |
---|
179 | ("GStreamer has detected that it is running inside valgrind."); |
---|
180 | VALGRIND_PRINTF |
---|
181 | ("It might now take different code paths to ease debugging."); |
---|
182 | VALGRIND_PRINTF ("Of course, this may also lead to different bugs."); |
---|
183 | in_valgrind = GST_VG_INSIDE; |
---|
184 | } else { |
---|
185 | GST_CAT_LOG (GST_CAT_GST_INIT, "not doing extra valgrind stuff"); |
---|
186 | in_valgrind = GST_VG_NO_VALGRIND; |
---|
187 | } |
---|
188 | #else |
---|
189 | in_valgrind = GST_VG_NO_VALGRIND; |
---|
190 | #endif |
---|
191 | g_assert (in_valgrind == GST_VG_NO_VALGRIND || |
---|
192 | in_valgrind == GST_VG_INSIDE); |
---|
193 | } |
---|
194 | return (in_valgrind == GST_VG_INSIDE) ? TRUE : FALSE; |
---|
195 | } |
---|
196 | |
---|
197 | /** |
---|
198 | * _gst_debug_init: |
---|
199 | * |
---|
200 | * Initializes the debugging system. |
---|
201 | * Normally you don't want to call this, because gst_init does it for you. |
---|
202 | */ |
---|
203 | void |
---|
204 | _gst_debug_init (void) |
---|
205 | { |
---|
206 | gst_atomic_int_init (&__default_level, GST_LEVEL_DEFAULT); |
---|
207 | gst_atomic_int_init (&__use_color, 1); |
---|
208 | |
---|
209 | #ifdef HAVE_PRINTF_EXTENSION |
---|
210 | register_printf_function (GST_PTR_FORMAT[0], _gst_info_printf_extension, |
---|
211 | _gst_info_printf_extension_arginfo); |
---|
212 | #endif |
---|
213 | |
---|
214 | /* do NOT use a single debug function before this line has been run */ |
---|
215 | GST_CAT_DEFAULT = _gst_debug_category_new ("default", |
---|
216 | GST_DEBUG_UNDERLINE, NULL); |
---|
217 | _GST_CAT_DEBUG = _gst_debug_category_new ("GST_DEBUG", |
---|
218 | GST_DEBUG_BOLD | GST_DEBUG_FG_YELLOW, "debugging subsystem"); |
---|
219 | |
---|
220 | gst_debug_add_log_function (gst_debug_log_default, NULL); |
---|
221 | |
---|
222 | /* FIXME: add descriptions here */ |
---|
223 | GST_CAT_GST_INIT = _gst_debug_category_new ("GST_INIT", |
---|
224 | GST_DEBUG_BOLD | GST_DEBUG_FG_RED, NULL); |
---|
225 | GST_CAT_COTHREADS = _gst_debug_category_new ("GST_COTHREADS", |
---|
226 | GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN, NULL); |
---|
227 | GST_CAT_COTHREAD_SWITCH = _gst_debug_category_new ("GST_COTHREAD_SWITCH", |
---|
228 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_GREEN, NULL); |
---|
229 | GST_CAT_AUTOPLUG = _gst_debug_category_new ("GST_AUTOPLUG", |
---|
230 | GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, NULL); |
---|
231 | GST_CAT_AUTOPLUG_ATTEMPT = _gst_debug_category_new ("GST_AUTOPLUG_ATTEMPT", |
---|
232 | GST_DEBUG_BOLD | GST_DEBUG_FG_CYAN | GST_DEBUG_BG_BLUE, NULL); |
---|
233 | GST_CAT_PARENTAGE = _gst_debug_category_new ("GST_PARENTAGE", |
---|
234 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL); |
---|
235 | GST_CAT_STATES = _gst_debug_category_new ("GST_STATES", |
---|
236 | GST_DEBUG_BOLD | GST_DEBUG_FG_RED, NULL); |
---|
237 | GST_CAT_PLANNING = _gst_debug_category_new ("GST_PLANNING", |
---|
238 | GST_DEBUG_BOLD | GST_DEBUG_FG_MAGENTA, NULL); |
---|
239 | GST_CAT_SCHEDULING = _gst_debug_category_new ("GST_SCHEDULING", |
---|
240 | GST_DEBUG_BOLD | GST_DEBUG_FG_MAGENTA, NULL); |
---|
241 | /* FIXME: remove GST_CAT_DATAFLOW in 0.9 */ |
---|
242 | GST_CAT_DATAFLOW = _gst_debug_category_new ("GST_DATAFLOW", |
---|
243 | GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN, "dataflow inside pads"); |
---|
244 | GST_CAT_BUFFER = _gst_debug_category_new ("GST_BUFFER", |
---|
245 | GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN, NULL); |
---|
246 | GST_CAT_CAPS = _gst_debug_category_new ("GST_CAPS", |
---|
247 | GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, NULL); |
---|
248 | GST_CAT_CLOCK = _gst_debug_category_new ("GST_CLOCK", |
---|
249 | GST_DEBUG_BOLD | GST_DEBUG_FG_YELLOW, NULL); |
---|
250 | GST_CAT_ELEMENT_PADS = _gst_debug_category_new ("GST_ELEMENT_PADS", |
---|
251 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL); |
---|
252 | GST_CAT_PADS = _gst_debug_category_new ("GST_PADS", |
---|
253 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL); |
---|
254 | GST_CAT_PIPELINE = _gst_debug_category_new ("GST_PIPELINE", |
---|
255 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL); |
---|
256 | GST_CAT_PLUGIN_LOADING = _gst_debug_category_new ("GST_PLUGIN_LOADING", |
---|
257 | GST_DEBUG_BOLD | GST_DEBUG_FG_CYAN, NULL); |
---|
258 | GST_CAT_PLUGIN_INFO = _gst_debug_category_new ("GST_PLUGIN_INFO", |
---|
259 | GST_DEBUG_BOLD | GST_DEBUG_FG_CYAN, NULL); |
---|
260 | GST_CAT_PROPERTIES = _gst_debug_category_new ("GST_PROPERTIES", |
---|
261 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_BLUE, NULL); |
---|
262 | GST_CAT_THREAD = _gst_debug_category_new ("GST_THREAD", |
---|
263 | GST_DEBUG_BOLD | GST_DEBUG_FG_RED, NULL); |
---|
264 | GST_CAT_TYPES = _gst_debug_category_new ("GST_TYPES", |
---|
265 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL); |
---|
266 | GST_CAT_XML = _gst_debug_category_new ("GST_XML", |
---|
267 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL); |
---|
268 | GST_CAT_NEGOTIATION = _gst_debug_category_new ("GST_NEGOTIATION", |
---|
269 | GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, NULL); |
---|
270 | GST_CAT_REFCOUNTING = _gst_debug_category_new ("GST_REFCOUNTING", |
---|
271 | GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE | GST_DEBUG_BG_GREEN, NULL); |
---|
272 | GST_CAT_ERROR_SYSTEM = _gst_debug_category_new ("GST_ERROR_SYSTEM", |
---|
273 | GST_DEBUG_BOLD | GST_DEBUG_FG_RED | GST_DEBUG_BG_WHITE, NULL); |
---|
274 | |
---|
275 | GST_CAT_EVENT = _gst_debug_category_new ("GST_EVENT", |
---|
276 | GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, NULL); |
---|
277 | GST_CAT_PARAMS = _gst_debug_category_new ("GST_PARAMS", |
---|
278 | GST_DEBUG_BOLD | GST_DEBUG_FG_BLACK | GST_DEBUG_BG_YELLOW, NULL); |
---|
279 | GST_CAT_CALL_TRACE = _gst_debug_category_new ("GST_CALL_TRACE", |
---|
280 | GST_DEBUG_BOLD, NULL); |
---|
281 | /* FIXME: fold back to GST_CAT_EVENT in 0.9 */ |
---|
282 | GST_CAT_SEEK = _gst_debug_category_new ("GST_SEEK", |
---|
283 | GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE, |
---|
284 | "plugins reacting to seek events"); |
---|
285 | GST_CAT_SIGNAL = _gst_debug_category_new ("GST_SIGNAL", |
---|
286 | GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED, NULL); |
---|
287 | GST_CAT_PROBE = _gst_debug_category_new ("GST_PROBE", |
---|
288 | GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN, "pad probes"); |
---|
289 | |
---|
290 | |
---|
291 | /* print out the valgrind message if we're in valgrind */ |
---|
292 | __gst_in_valgrind (); |
---|
293 | } |
---|
294 | |
---|
295 | /* we can't do this further above, because we initialize the GST_CAT_DEFAULT struct */ |
---|
296 | #define GST_CAT_DEFAULT _GST_CAT_DEBUG |
---|
297 | |
---|
298 | /** |
---|
299 | * gst_debug_log: |
---|
300 | * @category: category to log |
---|
301 | * @level: level of the message is in |
---|
302 | * @file: the file that emitted the message, usually the __FILE__ identifier |
---|
303 | * @function: the function that emitted the message |
---|
304 | * @line: the line from that the message was emitted, usually __LINE__ |
---|
305 | * @object: the object this message relates to or NULL if none |
---|
306 | * @format: a printf style format string |
---|
307 | * @...: optional arguments for the format |
---|
308 | * |
---|
309 | * Logs the given message using the currently registered debugging handlers. |
---|
310 | */ |
---|
311 | void |
---|
312 | gst_debug_log (GstDebugCategory * category, GstDebugLevel level, |
---|
313 | const gchar * file, const gchar * function, gint line, |
---|
314 | GObject * object, const gchar * format, ...) |
---|
315 | { |
---|
316 | va_list var_args; |
---|
317 | |
---|
318 | va_start (var_args, format); |
---|
319 | gst_debug_log_valist (category, level, file, function, line, object, format, |
---|
320 | var_args); |
---|
321 | va_end (var_args); |
---|
322 | } |
---|
323 | |
---|
324 | /** |
---|
325 | * gst_debug_log_valist: |
---|
326 | * @category: category to log |
---|
327 | * @level: level of the message is in |
---|
328 | * @file: the file that emitted the message, usually the __FILE__ identifier |
---|
329 | * @function: the function that emitted the message |
---|
330 | * @line: the line from that the message was emitted, usually __LINE__ |
---|
331 | * @object: the object this message relates to or NULL if none |
---|
332 | * @format: a printf style format string |
---|
333 | * @args: optional arguments for the format |
---|
334 | * |
---|
335 | * Logs the given message using the currently registered debugging handlers. |
---|
336 | */ |
---|
337 | void |
---|
338 | gst_debug_log_valist (GstDebugCategory * category, GstDebugLevel level, |
---|
339 | const gchar * file, const gchar * function, gint line, |
---|
340 | GObject * object, const gchar * format, va_list args) |
---|
341 | { |
---|
342 | GstDebugMessage message; |
---|
343 | LogFuncEntry *entry; |
---|
344 | GSList *handler; |
---|
345 | |
---|
346 | g_return_if_fail (category != NULL); |
---|
347 | g_return_if_fail (file != NULL); |
---|
348 | g_return_if_fail (function != NULL); |
---|
349 | g_return_if_fail (format != NULL); |
---|
350 | |
---|
351 | message.message = NULL; |
---|
352 | message.format = format; |
---|
353 | G_VA_COPY (message.arguments, args); |
---|
354 | |
---|
355 | handler = __log_functions; |
---|
356 | while (handler) { |
---|
357 | entry = handler->data; |
---|
358 | handler = g_slist_next (handler); |
---|
359 | entry->func (category, level, file, function, line, object, &message, |
---|
360 | entry->user_data); |
---|
361 | } |
---|
362 | g_free (message.message); |
---|
363 | va_end (message.arguments); |
---|
364 | } |
---|
365 | |
---|
366 | /** |
---|
367 | * gst_debug_message_get: |
---|
368 | * @message: a debug message |
---|
369 | * |
---|
370 | * Gets the string representation of a #GstDebugMessage. This function is used |
---|
371 | * in debug handlers to extract the message. |
---|
372 | * |
---|
373 | * Returns: the string representation of a #GstDebugMessage. |
---|
374 | */ |
---|
375 | const gchar * |
---|
376 | gst_debug_message_get (GstDebugMessage * message) |
---|
377 | { |
---|
378 | if (message->message == NULL) { |
---|
379 | message->message = g_strdup_vprintf (message->format, message->arguments); |
---|
380 | } |
---|
381 | return message->message; |
---|
382 | } |
---|
383 | |
---|
384 | |
---|
385 | static gchar * |
---|
386 | gst_debug_print_object (gpointer ptr) |
---|
387 | { |
---|
388 | GObject *object = (GObject *) ptr; |
---|
389 | |
---|
390 | #ifdef unused |
---|
391 | /* This is a cute trick to detect unmapped memory, but is unportable, |
---|
392 | * slow, screws around with madvise, and not actually that useful. */ |
---|
393 | { |
---|
394 | int ret; |
---|
395 | |
---|
396 | ret = madvise ((void *) ((unsigned long) ptr & (~0xfff)), 4096, 0); |
---|
397 | if (ret == -1 && errno == ENOMEM) { |
---|
398 | buffer = g_strdup_printf ("%p (unmapped memory)", ptr); |
---|
399 | } |
---|
400 | } |
---|
401 | #endif |
---|
402 | |
---|
403 | /* nicely printed object */ |
---|
404 | if (object == NULL) { |
---|
405 | return g_strdup ("(NULL)"); |
---|
406 | } |
---|
407 | if (*(GType *) ptr == GST_TYPE_CAPS) { |
---|
408 | return gst_caps_to_string ((GstCaps *) ptr); |
---|
409 | } |
---|
410 | if (*(GType *) ptr == GST_TYPE_STRUCTURE) { |
---|
411 | return gst_structure_to_string ((GstStructure *) ptr); |
---|
412 | } |
---|
413 | #ifdef USE_POISONING |
---|
414 | if (*(guint32 *) ptr == 0xffffffff) { |
---|
415 | return g_strdup_printf ("<poisoned@%p>", ptr); |
---|
416 | } |
---|
417 | #endif |
---|
418 | if (GST_IS_PAD (object) && GST_OBJECT_NAME (object)) { |
---|
419 | return g_strdup_printf ("<%s:%s>", GST_DEBUG_PAD_NAME (object)); |
---|
420 | } |
---|
421 | if (GST_IS_OBJECT (object) && GST_OBJECT_NAME (object)) { |
---|
422 | return g_strdup_printf ("<%s>", GST_OBJECT_NAME (object)); |
---|
423 | } |
---|
424 | if (G_IS_OBJECT (object)) { |
---|
425 | return g_strdup_printf ("<%s@%p>", G_OBJECT_TYPE_NAME (object), object); |
---|
426 | } |
---|
427 | |
---|
428 | return g_strdup_printf ("%p", ptr); |
---|
429 | } |
---|
430 | |
---|
431 | /** |
---|
432 | * gst_debug_construct_term_color: |
---|
433 | * @colorinfo: the color info |
---|
434 | * |
---|
435 | * Constructs a string that can be used for getting the desired color in color |
---|
436 | * terminals. |
---|
437 | * You need to free the string after use. |
---|
438 | * |
---|
439 | * Returns: a string containing the color definition |
---|
440 | */ |
---|
441 | gchar * |
---|
442 | gst_debug_construct_term_color (guint colorinfo) |
---|
443 | { |
---|
444 | GString *color; |
---|
445 | gchar *ret; |
---|
446 | |
---|
447 | color = g_string_new ("\033[00"); |
---|
448 | |
---|
449 | if (colorinfo & GST_DEBUG_BOLD) { |
---|
450 | g_string_append (color, ";01"); |
---|
451 | } |
---|
452 | if (colorinfo & GST_DEBUG_UNDERLINE) { |
---|
453 | g_string_append (color, ";04"); |
---|
454 | } |
---|
455 | if (colorinfo & GST_DEBUG_FG_MASK) { |
---|
456 | g_string_append_printf (color, ";3%1d", colorinfo & GST_DEBUG_FG_MASK); |
---|
457 | } |
---|
458 | if (colorinfo & GST_DEBUG_BG_MASK) { |
---|
459 | g_string_append_printf (color, ";4%1d", |
---|
460 | (colorinfo & GST_DEBUG_BG_MASK) >> 4); |
---|
461 | } |
---|
462 | g_string_append (color, "m"); |
---|
463 | |
---|
464 | ret = color->str; |
---|
465 | g_string_free (color, FALSE); |
---|
466 | return ret; |
---|
467 | } |
---|
468 | |
---|
469 | /** |
---|
470 | * gst_debug_log_default: |
---|
471 | * @category: category to log |
---|
472 | * @level: level of the message |
---|
473 | * @file: the file that emitted the message, usually the __FILE__ identifier |
---|
474 | * @function: the function that emitted the message |
---|
475 | * @line: the line from that the message was emitted, usually __LINE__ |
---|
476 | * @message: the actual message |
---|
477 | * @object: the object this message relates to or NULL if none |
---|
478 | * @unused: an unused variable, reserved for some user_data. |
---|
479 | * |
---|
480 | * The default logging handler used by GStreamer. Logging functions get called |
---|
481 | * whenever a macro like GST_DEBUG or similar is used. This function outputs the |
---|
482 | * message and additional info using the glib error handler. |
---|
483 | * You can add other handlers by using #gst_debug_add_log_function. |
---|
484 | * And you can remove this handler by calling |
---|
485 | * gst_debug_remove_log_function (gst_debug_log_default); |
---|
486 | */ |
---|
487 | void |
---|
488 | gst_debug_log_default (GstDebugCategory * category, GstDebugLevel level, |
---|
489 | const gchar * file, const gchar * function, gint line, |
---|
490 | GObject * object, GstDebugMessage * message, gpointer unused) |
---|
491 | { |
---|
492 | gchar *color; |
---|
493 | gchar *clear; |
---|
494 | gchar *obj; |
---|
495 | gchar *pidcolor; |
---|
496 | gint pid; |
---|
497 | GTimeVal now; |
---|
498 | |
---|
499 | if (level > gst_debug_category_get_threshold (category)) |
---|
500 | return; |
---|
501 | |
---|
502 | pid = getpid (); |
---|
503 | |
---|
504 | /* color info */ |
---|
505 | if (gst_debug_is_colored ()) { |
---|
506 | color = |
---|
507 | gst_debug_construct_term_color (gst_debug_category_get_color |
---|
508 | (category)); |
---|
509 | clear = "\033[00m"; |
---|
510 | pidcolor = g_strdup_printf ("\033[3%1dm", pid % 6 + 31); |
---|
511 | } else { |
---|
512 | color = g_strdup (""); |
---|
513 | clear = ""; |
---|
514 | pidcolor = g_strdup (""); |
---|
515 | } |
---|
516 | |
---|
517 | obj = object ? gst_debug_print_object (object) : g_strdup (""); |
---|
518 | |
---|
519 | g_get_current_time (&now); |
---|
520 | g_printerr ("%s (%p - %" GST_TIME_FORMAT |
---|
521 | ") %s%15s%s(%s%5d%s) %s%s(%d):%s:%s%s %s\n", |
---|
522 | gst_debug_level_get_name (level), g_thread_self (), |
---|
523 | GST_TIME_ARGS (GST_TIMEVAL_TO_TIME (now)), color, |
---|
524 | gst_debug_category_get_name (category), clear, pidcolor, pid, clear, |
---|
525 | color, file, line, function, obj, clear, gst_debug_message_get (message)); |
---|
526 | |
---|
527 | g_free (color); |
---|
528 | g_free (pidcolor); |
---|
529 | g_free (obj); |
---|
530 | } |
---|
531 | |
---|
532 | /** |
---|
533 | * gst_debug_level_get_name: |
---|
534 | * @level: the level to get the name for |
---|
535 | * |
---|
536 | * Get the string trepresentation of a debugging level |
---|
537 | * |
---|
538 | * Returns: the name |
---|
539 | */ |
---|
540 | const gchar * |
---|
541 | gst_debug_level_get_name (GstDebugLevel level) |
---|
542 | { |
---|
543 | switch (level) { |
---|
544 | case GST_LEVEL_NONE: |
---|
545 | return ""; |
---|
546 | case GST_LEVEL_ERROR: |
---|
547 | return "ERROR"; |
---|
548 | case GST_LEVEL_WARNING: |
---|
549 | return "WARN "; |
---|
550 | case GST_LEVEL_INFO: |
---|
551 | return "INFO "; |
---|
552 | case GST_LEVEL_DEBUG: |
---|
553 | return "DEBUG"; |
---|
554 | case GST_LEVEL_LOG: |
---|
555 | return "LOG "; |
---|
556 | default: |
---|
557 | g_warning ("invalid level specified for gst_debug_level_get_name"); |
---|
558 | return ""; |
---|
559 | } |
---|
560 | } |
---|
561 | |
---|
562 | /** |
---|
563 | * gst_debug_add_log_function: |
---|
564 | * @func: the function to use |
---|
565 | * @data: user data |
---|
566 | * |
---|
567 | * Adds the logging function to the list of logging functions. |
---|
568 | * Be sure to use G_GNUC_NO_INSTRUMENT on that function, it is needed. |
---|
569 | */ |
---|
570 | void |
---|
571 | gst_debug_add_log_function (GstLogFunction func, gpointer data) |
---|
572 | { |
---|
573 | LogFuncEntry *entry; |
---|
574 | GSList *list; |
---|
575 | |
---|
576 | g_return_if_fail (func != NULL); |
---|
577 | |
---|
578 | entry = g_new (LogFuncEntry, 1); |
---|
579 | entry->func = func; |
---|
580 | entry->user_data = data; |
---|
581 | /* FIXME: we leak the old list here - other threads might access it right now |
---|
582 | * in gst_debug_logv. Another solution is to lock the mutex in gst_debug_logv, |
---|
583 | * but that is waaay costly. |
---|
584 | * It'd probably be clever to use some kind of RCU here, but I don't know |
---|
585 | * anything about that. |
---|
586 | */ |
---|
587 | g_static_mutex_lock (&__log_func_mutex); |
---|
588 | list = g_slist_copy (__log_functions); |
---|
589 | __log_functions = g_slist_prepend (list, entry); |
---|
590 | g_static_mutex_unlock (&__log_func_mutex); |
---|
591 | |
---|
592 | GST_DEBUG ("prepended log function %p (user data %p) to log functions", |
---|
593 | func, data); |
---|
594 | } |
---|
595 | |
---|
596 | static gint |
---|
597 | gst_debug_compare_log_function_by_func (gconstpointer entry, gconstpointer func) |
---|
598 | { |
---|
599 | gpointer entryfunc = ((LogFuncEntry *) entry)->func; |
---|
600 | |
---|
601 | return (entryfunc < func) ? -1 : (entryfunc > func) ? 1 : 0; |
---|
602 | } |
---|
603 | |
---|
604 | static gint |
---|
605 | gst_debug_compare_log_function_by_data (gconstpointer entry, gconstpointer data) |
---|
606 | { |
---|
607 | gpointer entrydata = ((LogFuncEntry *) entry)->user_data; |
---|
608 | |
---|
609 | return (entrydata < data) ? -1 : (entrydata > data) ? 1 : 0; |
---|
610 | } |
---|
611 | |
---|
612 | static guint |
---|
613 | gst_debug_remove_with_compare_func (GCompareFunc func, gpointer data) |
---|
614 | { |
---|
615 | GSList *found; |
---|
616 | GSList *new; |
---|
617 | guint removals = 0; |
---|
618 | |
---|
619 | g_static_mutex_lock (&__log_func_mutex); |
---|
620 | new = __log_functions; |
---|
621 | while ((found = g_slist_find_custom (new, data, func))) { |
---|
622 | if (new == __log_functions) { |
---|
623 | new = g_slist_copy (new); |
---|
624 | continue; |
---|
625 | } |
---|
626 | g_free (found->data); |
---|
627 | new = g_slist_delete_link (new, found); |
---|
628 | removals++; |
---|
629 | } |
---|
630 | /* FIXME: We leak the old list here. See _add_log_function for why. */ |
---|
631 | __log_functions = new; |
---|
632 | g_static_mutex_unlock (&__log_func_mutex); |
---|
633 | |
---|
634 | return removals; |
---|
635 | } |
---|
636 | |
---|
637 | /** |
---|
638 | * gst_debug_remove_log_function: |
---|
639 | * @func: the log function to remove |
---|
640 | * |
---|
641 | * Removes all registrered instances of the given logging functions. |
---|
642 | * |
---|
643 | * Returns: How many instances of the function were removed |
---|
644 | */ |
---|
645 | guint |
---|
646 | gst_debug_remove_log_function (GstLogFunction func) |
---|
647 | { |
---|
648 | guint removals; |
---|
649 | |
---|
650 | g_return_val_if_fail (func != NULL, 0); |
---|
651 | |
---|
652 | removals = |
---|
653 | gst_debug_remove_with_compare_func |
---|
654 | (gst_debug_compare_log_function_by_func, func); |
---|
655 | GST_DEBUG ("removed log function %p %d times from log function list", func, |
---|
656 | removals); |
---|
657 | |
---|
658 | return removals; |
---|
659 | } |
---|
660 | |
---|
661 | /** |
---|
662 | * gst_debug_remove_log_function_by_data: |
---|
663 | * @data: user data of the log function to remove |
---|
664 | * |
---|
665 | * Removes all registrered instances of log functions with the given user data. |
---|
666 | * |
---|
667 | * Returns: How many instances of the function were removed |
---|
668 | */ |
---|
669 | guint |
---|
670 | gst_debug_remove_log_function_by_data (gpointer data) |
---|
671 | { |
---|
672 | guint removals; |
---|
673 | |
---|
674 | removals = |
---|
675 | gst_debug_remove_with_compare_func |
---|
676 | (gst_debug_compare_log_function_by_data, data); |
---|
677 | GST_DEBUG |
---|
678 | ("removed %d log functions with user data %p from log function list", |
---|
679 | removals, data); |
---|
680 | |
---|
681 | return removals; |
---|
682 | } |
---|
683 | |
---|
684 | /** |
---|
685 | * gst_debug_set_colored: |
---|
686 | * @colored: Whether to use colored output or not |
---|
687 | * |
---|
688 | * Sets or unsets the use of coloured debugging output. |
---|
689 | */ |
---|
690 | void |
---|
691 | gst_debug_set_colored (gboolean colored) |
---|
692 | { |
---|
693 | gst_atomic_int_set (&__use_color, colored ? 1 : 0); |
---|
694 | } |
---|
695 | |
---|
696 | /** |
---|
697 | * gst_debug_is_colored: |
---|
698 | * |
---|
699 | * Checks if the debugging output should be colored. |
---|
700 | * |
---|
701 | * Returns: TRUE, if the debug output should be colored. |
---|
702 | */ |
---|
703 | gboolean |
---|
704 | gst_debug_is_colored (void) |
---|
705 | { |
---|
706 | return gst_atomic_int_read (&__use_color) == 0 ? FALSE : TRUE; |
---|
707 | } |
---|
708 | |
---|
709 | /** |
---|
710 | * gst_debug_set_active: |
---|
711 | * @active: Whether to use debugging output or not |
---|
712 | * |
---|
713 | * If activated, debugging messages are sent to the debugging |
---|
714 | * handlers. |
---|
715 | * It makes sense to deactivate it for speed issues. |
---|
716 | * <note><para>This function is not threadsafe. It makes sense to only call it |
---|
717 | * during initialization.</para></note> |
---|
718 | */ |
---|
719 | void |
---|
720 | gst_debug_set_active (gboolean active) |
---|
721 | { |
---|
722 | __gst_debug_enabled = active; |
---|
723 | } |
---|
724 | |
---|
725 | /** |
---|
726 | * gst_debug_is_active: |
---|
727 | * |
---|
728 | * Checks if debugging output is activated. |
---|
729 | * |
---|
730 | * Returns: TRUE, if debugging is activated |
---|
731 | */ |
---|
732 | gboolean |
---|
733 | gst_debug_is_active (void) |
---|
734 | { |
---|
735 | return __gst_debug_enabled; |
---|
736 | } |
---|
737 | |
---|
738 | /** |
---|
739 | * gst_debug_set_default_threshold: |
---|
740 | * @level: level to set |
---|
741 | * |
---|
742 | * Sets the default threshold to the given level and updates all categories to |
---|
743 | * use this threshold. |
---|
744 | */ |
---|
745 | void |
---|
746 | gst_debug_set_default_threshold (GstDebugLevel level) |
---|
747 | { |
---|
748 | gst_atomic_int_set (&__default_level, level); |
---|
749 | gst_debug_reset_all_thresholds (); |
---|
750 | } |
---|
751 | |
---|
752 | /** |
---|
753 | * gst_debug_get_default_threshold: |
---|
754 | * |
---|
755 | * Returns the default threshold that is used for new categories. |
---|
756 | * |
---|
757 | * Returns: the default threshold level |
---|
758 | */ |
---|
759 | GstDebugLevel |
---|
760 | gst_debug_get_default_threshold (void) |
---|
761 | { |
---|
762 | return (GstDebugLevel) gst_atomic_int_read (&__default_level); |
---|
763 | } |
---|
764 | static void |
---|
765 | gst_debug_reset_threshold (gpointer category, gpointer unused) |
---|
766 | { |
---|
767 | GstDebugCategory *cat = (GstDebugCategory *) category; |
---|
768 | GSList *walk; |
---|
769 | |
---|
770 | g_static_mutex_lock (&__level_name_mutex); |
---|
771 | walk = __level_name; |
---|
772 | while (walk) { |
---|
773 | LevelNameEntry *entry = walk->data; |
---|
774 | |
---|
775 | walk = g_slist_next (walk); |
---|
776 | if (g_pattern_match_string (entry->pat, cat->name)) { |
---|
777 | GST_LOG ("category %s matches pattern %p - gets set to level %d", |
---|
778 | cat->name, entry->pat, entry->level); |
---|
779 | gst_debug_category_set_threshold (cat, entry->level); |
---|
780 | goto exit; |
---|
781 | } |
---|
782 | } |
---|
783 | gst_debug_category_set_threshold (cat, gst_debug_get_default_threshold ()); |
---|
784 | |
---|
785 | exit: |
---|
786 | g_static_mutex_unlock (&__level_name_mutex); |
---|
787 | } |
---|
788 | static void |
---|
789 | gst_debug_reset_all_thresholds (void) |
---|
790 | { |
---|
791 | g_static_mutex_lock (&__cat_mutex); |
---|
792 | g_slist_foreach (__categories, gst_debug_reset_threshold, NULL); |
---|
793 | g_static_mutex_unlock (&__cat_mutex); |
---|
794 | } |
---|
795 | static void |
---|
796 | for_each_threshold_by_entry (gpointer data, gpointer user_data) |
---|
797 | { |
---|
798 | GstDebugCategory *cat = (GstDebugCategory *) data; |
---|
799 | LevelNameEntry *entry = (LevelNameEntry *) user_data; |
---|
800 | |
---|
801 | if (g_pattern_match_string (entry->pat, cat->name)) { |
---|
802 | GST_LOG ("category %s matches pattern %p - gets set to level %d", |
---|
803 | cat->name, entry->pat, entry->level); |
---|
804 | gst_debug_category_set_threshold (cat, entry->level); |
---|
805 | } |
---|
806 | } |
---|
807 | |
---|
808 | /** |
---|
809 | * gst_debug_set_threshold_for_name: |
---|
810 | * @name: name of the categories to set |
---|
811 | * @level: level to set them to |
---|
812 | * |
---|
813 | * Sets all categories which match the given glob style pattern to the given |
---|
814 | * level. |
---|
815 | */ |
---|
816 | void |
---|
817 | gst_debug_set_threshold_for_name (const gchar * name, GstDebugLevel level) |
---|
818 | { |
---|
819 | GPatternSpec *pat; |
---|
820 | LevelNameEntry *entry; |
---|
821 | |
---|
822 | g_return_if_fail (name != NULL); |
---|
823 | |
---|
824 | pat = g_pattern_spec_new (name); |
---|
825 | entry = g_new (LevelNameEntry, 1); |
---|
826 | entry->pat = pat; |
---|
827 | entry->level = level; |
---|
828 | g_static_mutex_lock (&__level_name_mutex); |
---|
829 | __level_name = g_slist_prepend (__level_name, entry); |
---|
830 | g_static_mutex_unlock (&__level_name_mutex); |
---|
831 | g_static_mutex_lock (&__cat_mutex); |
---|
832 | g_slist_foreach (__categories, for_each_threshold_by_entry, entry); |
---|
833 | g_static_mutex_unlock (&__cat_mutex); |
---|
834 | } |
---|
835 | |
---|
836 | /** |
---|
837 | * gst_debug_unset_threshold_for_name: |
---|
838 | * @name: name of the categories to set |
---|
839 | * |
---|
840 | * Resets all categories with the given name back to the default level. |
---|
841 | */ |
---|
842 | void |
---|
843 | gst_debug_unset_threshold_for_name (const gchar * name) |
---|
844 | { |
---|
845 | GSList *walk; |
---|
846 | GPatternSpec *pat; |
---|
847 | |
---|
848 | g_return_if_fail (name != NULL); |
---|
849 | |
---|
850 | pat = g_pattern_spec_new (name); |
---|
851 | g_static_mutex_lock (&__level_name_mutex); |
---|
852 | walk = __level_name; |
---|
853 | /* improve this if you want, it's mighty slow */ |
---|
854 | while (walk) { |
---|
855 | LevelNameEntry *entry = walk->data; |
---|
856 | |
---|
857 | if (g_pattern_spec_equal (entry->pat, pat)) { |
---|
858 | __level_name = g_slist_remove_link (__level_name, walk); |
---|
859 | g_pattern_spec_free (entry->pat); |
---|
860 | g_free (entry); |
---|
861 | g_slist_free_1 (walk); |
---|
862 | walk = __level_name; |
---|
863 | } |
---|
864 | } |
---|
865 | g_static_mutex_unlock (&__level_name_mutex); |
---|
866 | g_pattern_spec_free (pat); |
---|
867 | gst_debug_reset_all_thresholds (); |
---|
868 | } |
---|
869 | |
---|
870 | GstDebugCategory * |
---|
871 | _gst_debug_category_new (gchar * name, guint color, gchar * description) |
---|
872 | { |
---|
873 | GstDebugCategory *cat; |
---|
874 | |
---|
875 | g_return_val_if_fail (name != NULL, NULL); |
---|
876 | |
---|
877 | cat = g_new (GstDebugCategory, 1); |
---|
878 | cat->name = g_strdup (name); |
---|
879 | cat->color = color; |
---|
880 | if (description != NULL) { |
---|
881 | cat->description = g_strdup (description); |
---|
882 | } else { |
---|
883 | cat->description = g_strdup ("no description"); |
---|
884 | } |
---|
885 | cat->threshold = g_new (GstAtomicInt, 1); |
---|
886 | gst_atomic_int_init (cat->threshold, 0); |
---|
887 | gst_debug_reset_threshold (cat, NULL); |
---|
888 | |
---|
889 | /* add to category list */ |
---|
890 | g_static_mutex_lock (&__cat_mutex); |
---|
891 | __categories = g_slist_prepend (__categories, cat); |
---|
892 | g_static_mutex_unlock (&__cat_mutex); |
---|
893 | |
---|
894 | return cat; |
---|
895 | } |
---|
896 | |
---|
897 | /** |
---|
898 | * gst_debug_category_free: |
---|
899 | * @category: #GstDebugCategory to free. |
---|
900 | * |
---|
901 | * Removes and frees the category and all associated resources. |
---|
902 | */ |
---|
903 | void |
---|
904 | gst_debug_category_free (GstDebugCategory * category) |
---|
905 | { |
---|
906 | if (category == NULL) |
---|
907 | return; |
---|
908 | |
---|
909 | /* remove from category list */ |
---|
910 | g_static_mutex_lock (&__cat_mutex); |
---|
911 | __categories = g_slist_remove (__categories, category); |
---|
912 | g_static_mutex_unlock (&__cat_mutex); |
---|
913 | |
---|
914 | g_free ((gpointer) category->name); |
---|
915 | g_free ((gpointer) category->description); |
---|
916 | gst_atomic_int_destroy (category->threshold); |
---|
917 | g_free (category->threshold); |
---|
918 | g_free (category); |
---|
919 | } |
---|
920 | |
---|
921 | /** |
---|
922 | * gst_debug_category_set_threshold: |
---|
923 | * @category: a #GstDebugCategory to set threshold of. |
---|
924 | * @level: the #GstDebugLevel threshold to set. |
---|
925 | * |
---|
926 | * Sets the threshold of the category to the given level. Debug information will |
---|
927 | * only be output if the threshold is lower or equal to the level of the |
---|
928 | * debugging message. |
---|
929 | * <note><para> |
---|
930 | * Do not use this function in production code, because other functions may |
---|
931 | * change the threshold of categories as side effect. It is however a nice |
---|
932 | * function to use when debugging (even from gdb). |
---|
933 | * </para></note> |
---|
934 | */ |
---|
935 | void |
---|
936 | gst_debug_category_set_threshold (GstDebugCategory * category, |
---|
937 | GstDebugLevel level) |
---|
938 | { |
---|
939 | g_return_if_fail (category != NULL); |
---|
940 | |
---|
941 | gst_atomic_int_set (category->threshold, level); |
---|
942 | } |
---|
943 | |
---|
944 | /** |
---|
945 | * gst_debug_category_reset_threshold: |
---|
946 | * @category: a #GstDebugCategory to reset threshold of. |
---|
947 | * |
---|
948 | * Resets the threshold of the category to the default level. Debug information |
---|
949 | * will only be output if the threshold is lower or equal to the level of the |
---|
950 | * debugging message. |
---|
951 | * Use this function to set the threshold back to where it was after using |
---|
952 | * gst_debug_category_set_threshold(). |
---|
953 | */ |
---|
954 | void |
---|
955 | gst_debug_category_reset_threshold (GstDebugCategory * category) |
---|
956 | { |
---|
957 | gst_debug_reset_threshold (category, NULL); |
---|
958 | } |
---|
959 | |
---|
960 | /** |
---|
961 | * gst_debug_category_get_threshold: |
---|
962 | * @category: a #GstDebugCategory to get threshold of. |
---|
963 | * |
---|
964 | * Returns the threshold of a #GstCategory. |
---|
965 | * |
---|
966 | * Returns: the #GstDebugLevel that is used as threshold. |
---|
967 | */ |
---|
968 | GstDebugLevel |
---|
969 | gst_debug_category_get_threshold (GstDebugCategory * category) |
---|
970 | { |
---|
971 | return gst_atomic_int_read (category->threshold); |
---|
972 | } |
---|
973 | |
---|
974 | /** |
---|
975 | * gst_debug_category_get_name: |
---|
976 | * @category: a #GstDebugCategory to get name of. |
---|
977 | * |
---|
978 | * Returns the name of a debug category. |
---|
979 | * |
---|
980 | * Returns: the name of the category. |
---|
981 | */ |
---|
982 | const gchar * |
---|
983 | gst_debug_category_get_name (GstDebugCategory * category) |
---|
984 | { |
---|
985 | return category->name; |
---|
986 | } |
---|
987 | |
---|
988 | /** |
---|
989 | * gst_debug_category_get_color: |
---|
990 | * @category: a #GstDebugCategory to get the color of. |
---|
991 | * |
---|
992 | * Returns the color of a debug category used when printing output in this |
---|
993 | * category. |
---|
994 | * |
---|
995 | * Returns: the color of the category. |
---|
996 | */ |
---|
997 | guint |
---|
998 | gst_debug_category_get_color (GstDebugCategory * category) |
---|
999 | { |
---|
1000 | return category->color; |
---|
1001 | } |
---|
1002 | |
---|
1003 | /** |
---|
1004 | * gst_debug_category_get_description: |
---|
1005 | * @category: a #GstDebugCategory to get the description of. |
---|
1006 | * |
---|
1007 | * Returns the description of a debug category. |
---|
1008 | * |
---|
1009 | * Returns: the description of the category. |
---|
1010 | */ |
---|
1011 | const gchar * |
---|
1012 | gst_debug_category_get_description (GstDebugCategory * category) |
---|
1013 | { |
---|
1014 | return category->description; |
---|
1015 | } |
---|
1016 | |
---|
1017 | /** |
---|
1018 | * gst_debug_get_all_categories: |
---|
1019 | * |
---|
1020 | * Returns a snapshot of a all categories that are currently in use . This list |
---|
1021 | * may change anytime. |
---|
1022 | * The caller has to free the list after use. |
---|
1023 | * <emphasis>This function is not threadsafe, so only use it while only the |
---|
1024 | * main thread is running.</emphasis> |
---|
1025 | * |
---|
1026 | * Returns: the list of categories |
---|
1027 | */ |
---|
1028 | GSList * |
---|
1029 | gst_debug_get_all_categories (void) |
---|
1030 | { |
---|
1031 | GSList *ret; |
---|
1032 | |
---|
1033 | g_static_mutex_lock (&__cat_mutex); |
---|
1034 | ret = g_slist_copy (__categories); |
---|
1035 | g_static_mutex_unlock (&__cat_mutex); |
---|
1036 | |
---|
1037 | return ret; |
---|
1038 | } |
---|
1039 | |
---|
1040 | /*** FUNCTION POINTERS ********************************************************/ |
---|
1041 | |
---|
1042 | GHashTable *__gst_function_pointers = NULL; |
---|
1043 | const gchar * |
---|
1044 | _gst_debug_nameof_funcptr (void *ptr) |
---|
1045 | G_GNUC_NO_INSTRUMENT; |
---|
1046 | |
---|
1047 | /* This function MUST NOT return NULL */ |
---|
1048 | const gchar *_gst_debug_nameof_funcptr (void *ptr) |
---|
1049 | { |
---|
1050 | gchar *ptrname; |
---|
1051 | |
---|
1052 | #ifdef HAVE_DLADDR |
---|
1053 | Dl_info dlinfo; |
---|
1054 | #endif |
---|
1055 | |
---|
1056 | if (__gst_function_pointers |
---|
1057 | && (ptrname = g_hash_table_lookup (__gst_function_pointers, ptr))) { |
---|
1058 | return ptrname; |
---|
1059 | } |
---|
1060 | /* we need to create an entry in the hash table for this one so we don't leak |
---|
1061 | * the name */ |
---|
1062 | #ifdef HAVE_DLADDR |
---|
1063 | if (dladdr (ptr, &dlinfo) && dlinfo.dli_sname) { |
---|
1064 | gchar *name = g_strdup (dlinfo.dli_sname); |
---|
1065 | |
---|
1066 | _gst_debug_register_funcptr (ptr, name); |
---|
1067 | return name; |
---|
1068 | } else |
---|
1069 | #endif |
---|
1070 | { |
---|
1071 | gchar *name = g_strdup_printf ("%p", ptr); |
---|
1072 | |
---|
1073 | _gst_debug_register_funcptr (ptr, name); |
---|
1074 | return name; |
---|
1075 | } |
---|
1076 | } |
---|
1077 | |
---|
1078 | void * |
---|
1079 | _gst_debug_register_funcptr (void *ptr, gchar * ptrname) |
---|
1080 | { |
---|
1081 | if (!__gst_function_pointers) |
---|
1082 | __gst_function_pointers = g_hash_table_new (g_direct_hash, g_direct_equal); |
---|
1083 | if (!g_hash_table_lookup (__gst_function_pointers, ptr)) |
---|
1084 | g_hash_table_insert (__gst_function_pointers, ptr, ptrname); |
---|
1085 | |
---|
1086 | return ptr; |
---|
1087 | } |
---|
1088 | |
---|
1089 | #ifdef HAVE_PRINTF_EXTENSION |
---|
1090 | static int |
---|
1091 | _gst_info_printf_extension (FILE * stream, const struct printf_info *info, |
---|
1092 | const void *const *args) |
---|
1093 | { |
---|
1094 | char *buffer; |
---|
1095 | int len; |
---|
1096 | void *ptr; |
---|
1097 | |
---|
1098 | buffer = NULL; |
---|
1099 | ptr = *(void **) args[0]; |
---|
1100 | |
---|
1101 | buffer = gst_debug_print_object (ptr); |
---|
1102 | len = fprintf (stream, "%*s", (info->left ? -info->width : info->width), |
---|
1103 | buffer); |
---|
1104 | |
---|
1105 | free (buffer); |
---|
1106 | return len; |
---|
1107 | } |
---|
1108 | |
---|
1109 | static int |
---|
1110 | _gst_info_printf_extension_arginfo (const struct printf_info *info, size_t n, |
---|
1111 | int *argtypes) |
---|
1112 | { |
---|
1113 | if (n > 0) |
---|
1114 | argtypes[0] = PA_POINTER; |
---|
1115 | return 1; |
---|
1116 | } |
---|
1117 | #endif /* HAVE_PRINTF_EXTENSION */ |
---|
1118 | |
---|
1119 | #else /* !GST_DISABLE_GST_DEBUG */ |
---|
1120 | |
---|
1121 | gboolean |
---|
1122 | __gst_in_valgrind (void) |
---|
1123 | { |
---|
1124 | return FALSE; |
---|
1125 | } |
---|
1126 | |
---|
1127 | #endif /* GST_DISABLE_GST_DEBUG */ |
---|
1128 | |
---|
1129 | |
---|
1130 | #ifdef GST_ENABLE_FUNC_INSTRUMENTATION |
---|
1131 | /* FIXME make this thread specific */ |
---|
1132 | static GSList *stack_trace = NULL; |
---|
1133 | |
---|
1134 | void |
---|
1135 | __cyg_profile_func_enter (void *this_fn, void *call_site) |
---|
1136 | G_GNUC_NO_INSTRUMENT; |
---|
1137 | void __cyg_profile_func_enter (void *this_fn, void *call_site) |
---|
1138 | { |
---|
1139 | gchar *name = _gst_debug_nameof_funcptr (this_fn); |
---|
1140 | gchar *site = _gst_debug_nameof_funcptr (call_site); |
---|
1141 | |
---|
1142 | GST_CAT_DEBUG (GST_CAT_CALL_TRACE, "entering function %s from %s", name, |
---|
1143 | site); |
---|
1144 | stack_trace = |
---|
1145 | g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)", |
---|
1146 | this_fn, name, call_site, site)); |
---|
1147 | |
---|
1148 | g_free (name); |
---|
1149 | g_free (site); |
---|
1150 | } |
---|
1151 | |
---|
1152 | void |
---|
1153 | __cyg_profile_func_exit (void *this_fn, void *call_site) |
---|
1154 | G_GNUC_NO_INSTRUMENT; |
---|
1155 | void __cyg_profile_func_exit (void *this_fn, void *call_site) |
---|
1156 | { |
---|
1157 | gchar *name = _gst_debug_nameof_funcptr (this_fn); |
---|
1158 | |
---|
1159 | GST_CAT_DEBUG (GST_CAT_CALL_TRACE, "leaving function %s", name); |
---|
1160 | g_free (stack_trace->data); |
---|
1161 | stack_trace = g_slist_delete_link (stack_trace, stack_trace); |
---|
1162 | |
---|
1163 | g_free (name); |
---|
1164 | } |
---|
1165 | |
---|
1166 | void |
---|
1167 | gst_debug_print_stack_trace (void) |
---|
1168 | { |
---|
1169 | GSList *walk = stack_trace; |
---|
1170 | gint count = 0; |
---|
1171 | |
---|
1172 | if (walk) |
---|
1173 | walk = g_slist_next (walk); |
---|
1174 | |
---|
1175 | while (walk) { |
---|
1176 | gchar *name = (gchar *) walk->data; |
---|
1177 | |
---|
1178 | g_print ("#%-2d %s\n", count++, name); |
---|
1179 | |
---|
1180 | walk = g_slist_next (walk); |
---|
1181 | } |
---|
1182 | } |
---|
1183 | #else |
---|
1184 | void |
---|
1185 | gst_debug_print_stack_trace (void) |
---|
1186 | { |
---|
1187 | /* nothing because it's compiled out */ |
---|
1188 | } |
---|
1189 | |
---|
1190 | #endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */ |
---|