some formatting and doc fixes, and make gstdebug output line up
[platform/upstream/gstreamer.git] / gst / gstinfo.c
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
26 #include "gstinfo.h"
27
28 #ifndef GST_DISABLE_GST_DEBUG
29
30 #include <dlfcn.h>
31 #include <unistd.h>
32 #include "gstinfo.h"
33 #include "gstlog.h"
34 #include "gst_private.h"
35 #include "gstelement.h"
36 #include "gstpad.h"
37 #include "gstscheduler.h"
38 #include "gst_private.h"
39
40 GST_DEBUG_CATEGORY_STATIC(GST_CAT_DEBUG);
41
42 #if defined __sgi__
43 #include <rld_interface.h>
44 typedef struct DL_INFO {
45   const char * dli_fname;
46   void       * dli_fbase;
47   const char * dli_sname;
48   void       * dli_saddr;
49   int          dli_version;
50   int          dli_reserved1;
51   long         dli_reserved[4];
52 } Dl_info;
53 #define _RLD_DLADDR             14
54 int dladdr(void *address, Dl_info *dl);
55
56 int dladdr(void *address, Dl_info *dl)
57 {
58   void *v;
59   v = _rld_new_interface(_RLD_DLADDR,address,dl);
60   return (int)v;
61 }
62 #endif /* __sgi__ */
63
64 extern gchar *_gst_progname;
65
66 static void     gst_debug_reset_threshold       (gpointer category,
67                                                  gpointer unused);
68 static void     gst_debug_reset_all_thresholds  (void);
69
70 /* list of all name/level pairs from --gst-debug and GST_DEBUG */
71 static GStaticMutex __level_name_mutex = G_STATIC_MUTEX_INIT;
72 static GSList *__level_name = NULL;
73 typedef struct {
74   GPatternSpec *        pat;
75   GstDebugLevel         level;
76 } LevelNameEntry;
77
78 /* list of all categories */
79 static GStaticMutex __cat_mutex = G_STATIC_MUTEX_INIT;
80 static GSList *__categories = NULL;
81
82 /* all registered debug handlers */
83 typedef struct {
84   GstLogFunction        func;
85   gpointer              user_data;
86 } LogFuncEntry;
87 static GStaticMutex __log_func_mutex = G_STATIC_MUTEX_INIT;
88 static GSList *__log_functions = NULL;
89
90 static GstAtomicInt __default_level;
91 static GstAtomicInt __use_color;
92 static GstAtomicInt __enabled;
93
94
95 GstDebugCategory *GST_CAT_DEFAULT = NULL;
96
97 GstDebugCategory *GST_CAT_GST_INIT = NULL;
98 GstDebugCategory *GST_CAT_COTHREADS = NULL;
99 GstDebugCategory *GST_CAT_COTHREAD_SWITCH = NULL;
100 GstDebugCategory *GST_CAT_AUTOPLUG = NULL;
101 GstDebugCategory *GST_CAT_AUTOPLUG_ATTEMPT = NULL;
102 GstDebugCategory *GST_CAT_PARENTAGE = NULL;
103 GstDebugCategory *GST_CAT_STATES = NULL;
104 GstDebugCategory *GST_CAT_PLANNING = NULL;
105 GstDebugCategory *GST_CAT_SCHEDULING = NULL;
106 GstDebugCategory *GST_CAT_DATAFLOW = NULL;
107 GstDebugCategory *GST_CAT_BUFFER = NULL;
108 GstDebugCategory *GST_CAT_CAPS = NULL;
109 GstDebugCategory *GST_CAT_CLOCK = NULL;
110 GstDebugCategory *GST_CAT_ELEMENT_PADS = NULL;
111 GstDebugCategory *GST_CAT_ELEMENT_FACTORY = NULL;
112 GstDebugCategory *GST_CAT_PADS = NULL;
113 GstDebugCategory *GST_CAT_PIPELINE = NULL;
114 GstDebugCategory *GST_CAT_PLUGIN_LOADING = NULL;
115 GstDebugCategory *GST_CAT_PLUGIN_INFO = NULL;
116 GstDebugCategory *GST_CAT_PROPERTIES = NULL;
117 GstDebugCategory *GST_CAT_THREAD = NULL;
118 GstDebugCategory *GST_CAT_TYPES = NULL;
119 GstDebugCategory *GST_CAT_XML = NULL;
120 GstDebugCategory *GST_CAT_NEGOTIATION = NULL;
121 GstDebugCategory *GST_CAT_REFCOUNTING = NULL;
122 GstDebugCategory *GST_CAT_EVENT = NULL;
123 GstDebugCategory *GST_CAT_PARAMS = NULL;
124 GstDebugCategory *GST_CAT_CALL_TRACE = NULL;
125
126 /**
127  * _gst_debug_init:
128  * 
129  * Initializes the debugging system.
130  * Normally you don't want to call this, because gst_init does it for you.
131  */
132 void _gst_debug_init (void)
133 {
134   gst_atomic_int_init (&__default_level, GST_LEVEL_DEFAULT);
135   gst_atomic_int_init (&__use_color, 1);
136   gst_atomic_int_init (&__enabled, 1);
137
138   /* do NOT use a single debug function before this line has been run */
139   GST_CAT_DEFAULT       = _gst_debug_category_new ("default", 
140                                 GST_DEBUG_UNDERLINE,
141                                 NULL);
142   GST_CAT_DEBUG         = _gst_debug_category_new ("GST_DEBUG",
143                                 GST_DEBUG_BOLD | GST_DEBUG_FG_YELLOW,
144                                 "debugging subsystem");
145
146   gst_debug_add_log_function (gst_debug_log_default, NULL);
147
148   /* FIXME: add descriptions here */
149   GST_CAT_GST_INIT      = _gst_debug_category_new ("GST_INIT",
150                                 GST_DEBUG_BOLD | GST_DEBUG_FG_RED,
151                                 NULL);
152   GST_CAT_COTHREADS     = _gst_debug_category_new ("GST_COTHREADS",
153                                 GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN,
154                                 NULL);
155   GST_CAT_COTHREAD_SWITCH = _gst_debug_category_new ("GST_COTHREAD_SWITCH",
156                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_GREEN,
157                                 NULL);
158   GST_CAT_AUTOPLUG      = _gst_debug_category_new ("GST_AUTOPLUG",
159                                 GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE,
160                                 NULL);
161   GST_CAT_AUTOPLUG_ATTEMPT = _gst_debug_category_new ("GST_AUTOPLUG_ATTEMPT",
162                                 GST_DEBUG_BOLD | GST_DEBUG_FG_CYAN | GST_DEBUG_BG_BLUE,
163                                 NULL);
164   GST_CAT_PARENTAGE     = _gst_debug_category_new ("GST_PARENTAGE",
165                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED,
166                                 NULL);
167   GST_CAT_STATES        = _gst_debug_category_new ("GST_STATES",
168                                 GST_DEBUG_BOLD | GST_DEBUG_FG_RED,
169                                 NULL);
170   GST_CAT_PLANNING      = _gst_debug_category_new ("GST_PLANNING",
171                                 GST_DEBUG_BOLD | GST_DEBUG_FG_MAGENTA,
172                                 NULL);
173   GST_CAT_SCHEDULING    = _gst_debug_category_new ("GST_SCHEDULING",
174                                 GST_DEBUG_BOLD | GST_DEBUG_FG_MAGENTA,
175                                 NULL);
176   GST_CAT_DATAFLOW      = _gst_debug_category_new ("GST_DATAFLOW",
177                                 GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN,
178                                 NULL);
179   GST_CAT_BUFFER        = _gst_debug_category_new ("GST_BUFFER",
180                                 GST_DEBUG_BOLD | GST_DEBUG_FG_GREEN,
181                                 NULL);
182   GST_CAT_CAPS          = _gst_debug_category_new ("GST_CAPS",
183                                 GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE,
184                                 NULL);
185   GST_CAT_CLOCK         = _gst_debug_category_new ("GST_CLOCK",
186                                 GST_DEBUG_BOLD | GST_DEBUG_FG_YELLOW,
187                                 NULL);
188   GST_CAT_ELEMENT_PADS  = _gst_debug_category_new ("GST_ELEMENT_PADS",
189                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED,
190                                 NULL);
191   GST_CAT_ELEMENT_FACTORY = _gst_debug_category_new ("GST_ELEMENT_FACTORY",
192                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED,
193                                 NULL);
194   GST_CAT_PADS          = _gst_debug_category_new ("GST_PADS",
195                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED,
196                                 NULL);
197   GST_CAT_PIPELINE      = _gst_debug_category_new ("GST_PIPELINE",
198                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED,
199                                 NULL);
200   GST_CAT_PLUGIN_LOADING = _gst_debug_category_new ("GST_PLUGIN_LOADING",
201                                 GST_DEBUG_BOLD | GST_DEBUG_FG_CYAN,
202                                 NULL);
203   GST_CAT_PLUGIN_INFO   = _gst_debug_category_new ("GST_PLUGIN_INFO",
204                                 GST_DEBUG_BOLD | GST_DEBUG_FG_CYAN,
205                                 NULL);
206   GST_CAT_PROPERTIES    = _gst_debug_category_new ("GST_PROPERTIES",
207                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_BLUE,
208                                 NULL);
209   GST_CAT_THREAD        = _gst_debug_category_new ("GST_THREAD",
210                                 GST_DEBUG_BOLD | GST_DEBUG_FG_RED,
211                                 NULL);
212   GST_CAT_TYPES         = _gst_debug_category_new ("GST_TYPES",
213                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED,
214                                 NULL);
215   GST_CAT_XML           = _gst_debug_category_new ("GST_XML",
216                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED,
217                                 NULL);
218   GST_CAT_NEGOTIATION   = _gst_debug_category_new ("GST_NEGOTIATION",
219                                 GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE,
220                                 NULL);
221   GST_CAT_REFCOUNTING   = _gst_debug_category_new ("GST_REFCOUNTING",
222                                 GST_DEBUG_BOLD | GST_DEBUG_FG_BLUE | GST_DEBUG_BG_GREEN,
223                                 NULL);
224   GST_CAT_EVENT         = _gst_debug_category_new ("GST_EVENT",
225                                 GST_DEBUG_BOLD | GST_DEBUG_FG_WHITE | GST_DEBUG_BG_RED,
226                                 NULL);
227   GST_CAT_PARAMS        = _gst_debug_category_new ("GST_PARAMS",
228                                 GST_DEBUG_BOLD | GST_DEBUG_FG_BLACK | GST_DEBUG_BG_YELLOW,
229                                 NULL);
230   GST_CAT_CALL_TRACE    = _gst_debug_category_new ("GST_CALL_TRACE",
231                                 GST_DEBUG_BOLD,
232                                 NULL);
233 }
234
235 /* we can't do this further above, because we initialize the GST_CAT_DEFAULT struct */
236 #define GST_CAT_DEFAULT GST_CAT_DEBUG
237
238 /**
239  * gst_debug_log:
240  * @category: category to log
241  * @level: level of the message is in
242  * @file: the file that emitted the message, usually the __FILE__ identifier
243  * @function: the function that emitted the message
244  * @line: the line from that the message was emitted, usually __LINE__
245  * @object: the object this message relates to or NULL if none
246  * @format: a printf style format string
247  * @...: optional arguments for the format
248  * 
249  * Logs the given message using the currently registered debugging handlers.
250  */
251 void gst_debug_log (GstDebugCategory *category, GstDebugLevel level,
252                     const gchar *file, const gchar *function, gint line,
253                     GObject *object, gchar *format, ...)
254 {
255   va_list var_args;
256   
257   va_start (var_args, format);
258   gst_debug_logv (category, level, file, function, line, object, format, var_args);
259   va_end (var_args);
260 }
261 /**
262  * gst_debug_logv:
263  * @category: category to log
264  * @level: level of the message is in
265  * @file: the file that emitted the message, usually the __FILE__ identifier
266  * @function: the function that emitted the message
267  * @line: the line from that the message was emitted, usually __LINE__
268  * @object: the object this message relates to or NULL if none
269  * @format: a printf style format string
270  * @args: optional arguments for the format
271  * 
272  * Logs the given message using the currently registered debugging handlers.
273  */
274 void gst_debug_logv (GstDebugCategory *category, GstDebugLevel level,
275                      const gchar *file, const gchar *function, gint line,
276                      GObject *object, gchar *format, va_list args)
277 {
278   gchar *message;
279   LogFuncEntry *entry;
280   GSList *handler;
281
282   g_return_if_fail (category != NULL);
283   g_return_if_fail (file != NULL);
284   g_return_if_fail (function != NULL);
285   g_return_if_fail (format != NULL);
286
287   message = g_strdup_vprintf (format, args);
288   g_static_mutex_lock (&__log_func_mutex);
289   handler = __log_functions;
290   while (handler) {
291     entry = handler->data;
292     handler = g_slist_next (handler);
293     entry->func (category, level, file, function, line, object, message, entry->user_data);
294   }
295   g_static_mutex_unlock (&__log_func_mutex);
296   g_free (message);
297 }
298 /**
299  * gst_debug_construct_term_color:
300  * @colorinfo: the color info
301  * 
302  * Constructs a string that can be used for getting the desired color in color
303  * terminals.
304  * You need to free the string after use.
305  * 
306  * Returns: a string containing the color definition
307  */
308 gchar *
309 gst_debug_construct_term_color (guint colorinfo)
310 {
311   GString *color;
312   gchar *ret;
313
314   color = g_string_new ("\033[00");
315
316   if (colorinfo & GST_DEBUG_BOLD) {
317     g_string_append (color, ";01");
318   }
319   if (colorinfo & GST_DEBUG_UNDERLINE) {
320     g_string_append (color, ";04");
321   }
322   if (colorinfo & GST_DEBUG_FG_MASK) {
323     g_string_append_printf (color, ";3%1d", colorinfo & GST_DEBUG_FG_MASK);
324   }
325   if (colorinfo & GST_DEBUG_BG_MASK) {
326     g_string_append_printf (color, ";4%1d", (colorinfo & GST_DEBUG_BG_MASK) >> 4);
327   }
328   g_string_append (color, "m");
329
330   ret = color->str;
331   g_string_free (color, FALSE);
332   return ret;
333 }
334 /**
335  * gst_debug_log_default:
336  * @category: category to log
337  * @level: level of the message
338  * @file: the file that emitted the message, usually the __FILE__ identifier
339  * @function: the function that emitted the message
340  * @line: the line from that the message was emitted, usually __LINE__
341  * @message: the actual message
342  * @object: the object this message relates to or NULL if none
343  * @unused: an unused variable, reserved for some user_data.
344  * 
345  * The default logging handler used by GStreamer. Logging functions get called
346  * whenever a macro like GST_DEBUG or similar is used. This function outputs the
347  * message and additional info using the glib error handler.
348  * You can add other handlers by using #gst_debug_add_log_function. 
349  * And you can remove this handler by calling
350  * gst_debug_remove_log_function (gst_debug_log_default);
351  */
352 void
353 gst_debug_log_default (GstDebugCategory *category, GstDebugLevel level,
354                        const gchar *file, const gchar *function, gint line,
355                        GObject *object, gchar *message, gpointer unused)
356 {
357   gchar *color;
358   gchar *clear;
359   gchar *obj;
360   gchar *pidcolor;
361   gint pid;
362   
363   if (level > gst_debug_category_get_threshold (category))
364     return;
365   
366   pid = getpid();
367
368   /* color info */
369   if (gst_debug_is_colored ()) {
370     color = gst_debug_construct_term_color (gst_debug_category_get_color (category));
371     clear = "\033[00m";
372     pidcolor = g_strdup_printf ("\033[3%1dm", pid % 6 + 31);
373   } else {
374     color = g_strdup ("");
375     clear = "";
376     pidcolor = g_strdup ("");
377   }
378   /* nicely printed object */
379   if (object == NULL) {
380     obj = g_strdup ("");
381   } else if (GST_IS_PAD (object) && GST_OBJECT_NAME (object)) {
382     obj = g_strdup_printf (" [%s:%s]", GST_DEBUG_PAD_NAME (object));
383   } else if (GST_IS_OBJECT (object) && GST_OBJECT_NAME (object)) {
384     obj = g_strdup_printf (" [%s]", GST_OBJECT_NAME (object));
385   } else {
386     obj = g_strdup_printf (" [%s@%p]", G_OBJECT_TYPE_NAME(object), object);  
387   }
388
389   g_printerr ("%s %s%15s%s(%s%5d%s) %s%s(%d):%s:%s%s %s\n", 
390               gst_debug_level_get_name (level),
391               color, gst_debug_category_get_name (category), clear,
392               pidcolor, pid, clear,
393               color, file, line, function, obj, clear,
394               message);
395
396   g_free (color);
397   g_free (pidcolor);
398   g_free (obj);
399 }
400 /**
401  * gst_debug_level_get_name:
402  * @level: the level to get the name for
403  * 
404  * Get the string trepresentation of a debugging level
405  * 
406  * Returns: the name
407  */
408 const gchar *
409 gst_debug_level_get_name (GstDebugLevel level)
410 {
411   switch (level) {
412     case GST_LEVEL_NONE:        return "";
413     case GST_LEVEL_ERROR:       return "ERROR";
414     case GST_LEVEL_WARNING:     return "WARN ";
415     case GST_LEVEL_INFO:        return "INFO ";
416     case GST_LEVEL_DEBUG:       return "DEBUG";
417     case GST_LEVEL_LOG:         return "LOG  ";
418     default:
419       g_warning ("invalid level specified for gst_debug_level_get_name");
420       return "";
421   }
422 }
423 /**
424  * gst_debug_add_log_function:
425  * @func: the function to use
426  * @data: user data
427  * 
428  * Adds the logging function to the list of logging functions.
429  * Be sure to use G_GNUC_NO_INSTRUMENT on that function, it is needed.
430  */
431 void
432 gst_debug_add_log_function (GstLogFunction func, gpointer data)
433 {
434   LogFuncEntry *entry;
435
436   g_return_if_fail (func != NULL);
437
438   entry = g_new (LogFuncEntry, 1);
439   entry->func = func;
440   entry->user_data = data;
441   g_static_mutex_lock (&__log_func_mutex);
442   __log_functions = g_slist_prepend (__log_functions, entry);
443   g_static_mutex_unlock (&__log_func_mutex);
444
445   GST_DEBUG ("prepended log function %p (user data %p) to log functions",
446              func, data);
447 }
448 static gint
449 gst_debug_compare_log_function_by_func (gconstpointer entry, gconstpointer func)
450 {
451   gpointer entryfunc = ((LogFuncEntry *) entry)->func;
452   
453   return (entryfunc < func) ? -1 : (entryfunc > func) ? 1 : 0;
454 }
455 static gint
456 gst_debug_compare_log_function_by_data (gconstpointer entry, gconstpointer data)
457 {
458   gpointer entrydata = ((LogFuncEntry *) entry)->user_data;
459   
460   return (entrydata < data) ? -1 : (entrydata > data) ? 1 : 0;
461 }
462 /**
463  * gst_debug_remove_log_function:
464  * @func: the log function to remove
465  * 
466  * Removes all registrered instances of the given logging functions.
467  * 
468  * Returns: How many instances of the function were removed
469  */
470 guint
471 gst_debug_remove_log_function (GstLogFunction func)
472 {
473   GSList *found;
474   guint removals = 0;
475
476   g_return_val_if_fail (func != NULL, 0);
477
478   g_static_mutex_lock (&__log_func_mutex);
479   while ((found = g_slist_find_custom (__log_functions, func, 
480                                        gst_debug_compare_log_function_by_func))) {
481     g_free (found->data);
482     __log_functions = g_slist_delete_link (__log_functions, found);
483     removals++;
484   }
485   g_static_mutex_unlock (&__log_func_mutex);
486   GST_DEBUG ("removed log function %p %d times from log function list",
487              func, removals);
488
489   return removals;
490 }
491 /**
492  * gst_debug_remove_log_function_by_data:
493  * @data: user data of the log function to remove
494  * 
495  * Removes all registrered instances of log functions with the given user data.
496  * 
497  * Returns: How many instances of the function were removed
498  */
499 guint
500 gst_debug_remove_log_function_by_data (gpointer data)
501 {
502   GSList *found;
503   guint removals = 0;
504
505   g_static_mutex_lock (&__log_func_mutex);
506   while ((found = g_slist_find_custom (__log_functions, data, 
507                                        gst_debug_compare_log_function_by_data))) {
508     g_free (found->data);
509     __log_functions = g_slist_delete_link (__log_functions, found);
510     removals++;
511   }
512   g_static_mutex_unlock (&__log_func_mutex);
513   GST_DEBUG ("removed %d log functions with user data %p from log function list",
514              removals, data);
515
516   return removals;
517 }
518 /**
519  * gst_debug_set_colored:
520  * @colored: Whether to use colored output or not
521  * 
522  * Sets or unsets the use of coloured debugging output.
523  */
524 void
525 gst_debug_set_colored (gboolean colored)
526 {
527   gst_atomic_int_set (&__use_color, colored ? 1 : 0);
528 }
529 /**
530  * gst_debug_is_colored:
531  * 
532  * Checks if the debugging output should be colored.
533  * 
534  * Returns: TRUE, if the debug output should be colored.
535  */
536 gboolean
537 gst_debug_is_colored (void)
538 {
539   return gst_atomic_int_read (&__use_color) == 0 ? FALSE : TRUE;
540 }
541 /**
542  * gst_debug_set_active:
543  * @active: Whether to use debugging output or not
544  * 
545  * If activated, debugging messages are sent to the debugging
546  * handlers.
547  * It makes sense to deactivate it for speed issues.
548  */
549 void
550 gst_debug_set_active (gboolean active)
551 {
552   gst_atomic_int_set (&__enabled, active ? 1 : 0);
553 }
554 /**
555  * gst_debug_is_active:
556  * 
557  * Checks if debugging output is activated.
558  * 
559  * Returns: TRUE, if debugging is activated
560  */
561 gboolean
562 gst_debug_is_active (void)
563 {
564   return gst_atomic_int_read (&__enabled) == 0 ? FALSE : TRUE;
565 }
566 /**
567  * gst_debug_set_default_threshold:
568  * @level: level to set
569  * 
570  * Sets the default threshold to the given level and updates all categories to
571  * use this threshold.
572  */
573 void
574 gst_debug_set_default_threshold (GstDebugLevel level)
575 {
576   gst_atomic_int_set (&__default_level, level);
577   gst_debug_reset_all_thresholds ();
578 }
579 /**
580  * gst_debug_get_default_threshold:
581  * 
582  * Returns the default threshold that is used for new categories.
583  * 
584  * Returns: the default threshold level
585  */
586 GstDebugLevel
587 gst_debug_get_default_threshold (void)
588 {       
589   return (GstDebugLevel) gst_atomic_int_read (&__default_level);
590 }
591 static void
592 gst_debug_reset_threshold (gpointer category, gpointer unused)
593 {
594   GstDebugCategory *cat = (GstDebugCategory *) category;
595   GSList *walk;
596   
597   g_static_mutex_lock (&__level_name_mutex);
598   walk = __level_name;
599   while (walk) {
600     LevelNameEntry *entry = walk->data;
601     walk = g_slist_next (walk);
602     if (g_pattern_match_string (entry->pat, cat->name)) {
603       GST_LOG ("category %s matches pattern %p - gets set to level %d",
604                cat->name, entry->pat, entry->level);
605       gst_debug_category_set_threshold (cat, entry->level);
606       goto exit;
607     }
608   }
609   gst_debug_category_set_threshold (cat, gst_debug_get_default_threshold ());
610
611 exit:
612   g_static_mutex_unlock (&__level_name_mutex);
613 }
614 static void
615 gst_debug_reset_all_thresholds (void)
616 {
617   g_static_mutex_lock (&__cat_mutex);
618   g_slist_foreach (__categories, gst_debug_reset_threshold, NULL);
619   g_static_mutex_unlock (&__cat_mutex);
620 }
621 static void
622 for_each_threshold_by_entry (gpointer data, gpointer user_data)
623 {
624   GstDebugCategory *cat = (GstDebugCategory *) data;
625   LevelNameEntry *entry = (LevelNameEntry *) user_data;
626
627   if (g_pattern_match_string (entry->pat, cat->name)) {
628     GST_LOG ("category %s matches pattern %p - gets set to level %d",
629              cat->name, entry->pat, entry->level);
630     gst_debug_category_set_threshold (cat, entry->level);
631   }
632 }
633 /**
634  * gst_debug_set_threshold_for_name:
635  * @name: name of the categories to set
636  * @level: level to set them to
637  * 
638  * Sets all categories which match the gven glob style pattern to the given 
639  * level.
640  */
641 void
642 gst_debug_set_threshold_for_name (const gchar *name, GstDebugLevel level)
643 {
644   GPatternSpec *pat;
645   LevelNameEntry *entry;
646         
647   g_return_if_fail (name != NULL);
648
649   pat = g_pattern_spec_new (name);
650   entry = g_new (LevelNameEntry, 1);
651   entry->pat = pat;
652   entry->level = level;
653   g_static_mutex_lock (&__level_name_mutex);
654   __level_name = g_slist_prepend (__level_name, entry);
655   g_static_mutex_unlock (&__level_name_mutex);
656   g_static_mutex_lock (&__cat_mutex);
657   g_slist_foreach (__categories, for_each_threshold_by_entry, entry);
658   g_static_mutex_unlock (&__cat_mutex);
659 }
660 /**
661  * gst_debug_unset_threshold_for_name:
662  * @name: name of the categories to set
663  * 
664  * Resets all categories with the given name back to the default level.
665  */
666 void
667 gst_debug_unset_threshold_for_name (const gchar *name)
668 {
669   GSList *walk;
670   GPatternSpec *pat;
671         
672   g_return_if_fail (name != NULL);
673
674   pat = g_pattern_spec_new (name);
675   g_static_mutex_lock (&__level_name_mutex);
676   walk = __level_name;
677   /* improve this if you want, it's mighty slow */
678   while (walk) {
679     LevelNameEntry *entry = walk->data;
680     if (g_pattern_spec_equal (entry->pat, pat)) {
681       __level_name = g_slist_remove_link (__level_name, walk);
682       g_pattern_spec_free (entry->pat);
683       g_free (entry);
684       g_slist_free_1 (walk);
685       walk = __level_name;
686     }
687   }
688   g_static_mutex_unlock (&__level_name_mutex);
689   g_pattern_spec_free (pat);
690   gst_debug_reset_all_thresholds ();
691 }
692 GstDebugCategory *
693 _gst_debug_category_new (gchar *name, guint color, gchar *description)
694 {
695   GstDebugCategory *cat;
696   
697   g_return_val_if_fail (name != NULL, NULL);
698
699   cat = g_new (GstDebugCategory, 1);
700   cat->name = g_strdup (name);
701   cat->color = color;
702   if (description != NULL) {
703     cat->description = g_strdup (description);
704   } else {
705     cat->description = g_strdup ("no description");
706   }
707   cat->threshold = g_new (GstAtomicInt, 1);
708   gst_atomic_int_init (cat->threshold, 0);
709   gst_debug_reset_threshold (cat, NULL);
710
711   /* add to category list */
712   g_static_mutex_lock (&__cat_mutex);
713   __categories = g_slist_prepend (__categories, cat);
714   g_static_mutex_unlock (&__cat_mutex);
715
716   return cat;
717 }
718 /**
719  * gst_debug_category_free:
720  * @category: category to remove
721  * 
722  * Removes and frees the category and all associated ressources.
723  */
724 void
725 gst_debug_category_free (GstDebugCategory *category)
726 {
727   if (category == NULL) return;
728
729   /* remove from category list */
730   g_static_mutex_lock (&__cat_mutex);
731   __categories = g_slist_remove (__categories, category);
732   g_static_mutex_unlock (&__cat_mutex);
733
734   g_free ((gpointer) category->name); 
735   g_free ((gpointer) category->description); 
736   gst_atomic_int_destroy (category->threshold);
737   g_free (category->threshold);
738   g_free (category);
739 }
740 /**
741  * gst_debug_category_set_threshold:
742  * @category: category to set threshold for
743  * @level: the threshold to set
744  * 
745  * Sets the threshold of the category to the given level. Debug information will
746  * only be output if the threshold is lower or equal to the level of the 
747  * debugging message.
748  * <note><para>
749  * Do not use this function in production code, because other functions may 
750  * change the threshold of categories as side effect. It is however a nice 
751  * function to use when debugging (even from gdb).
752  * </para></note>
753  */
754 void
755 gst_debug_category_set_threshold (GstDebugCategory *category, GstDebugLevel level)
756 {
757   g_return_if_fail (category != NULL);
758
759   gst_atomic_int_set (category->threshold, level);
760 }
761 /**
762  * gst_debug_category_reset_threshold:
763  * @category: category to set threshold for
764  * 
765  * Resets the threshold of the category to the default level. Debug information 
766  * will only be output if the threshold is lower or equal to the level of the 
767  * debugging message.
768  * Use this function to set the threshold back to where it was after using 
769  * gst_debug_category_set_threshold().
770  */
771 void
772 gst_debug_category_reset_threshold (GstDebugCategory *category)
773 {
774   gst_debug_reset_threshold (category, NULL);
775 }
776 /**
777  * gst_debug_category_get_threshold:
778  * @category: category to get threshold for
779  * 
780  * Returns the threshold of a #GstCategory.
781  * 
782  * Returns: the level that is used as threshold
783  */
784 GstDebugLevel
785 gst_debug_category_get_threshold (GstDebugCategory *category)
786 {
787   return gst_atomic_int_read (category->threshold);
788 }
789 /**
790  * gst_debug_category_get_name:
791  * @category: category to get name for
792  * 
793  * Returns the name of a #GstCategory.
794  * 
795  * Returns: the name of the category
796  */
797 const gchar *
798 gst_debug_category_get_name (GstDebugCategory *category)
799 {
800   return category->name;
801 }
802 /**
803  * gst_debug_category_get_color:
804  * @category: category to get color for
805  * 
806  * Returns the color of a #GstCategory to use when outputting this.
807  * 
808  * Returns: the color of the category
809  */
810 guint
811 gst_debug_category_get_color (GstDebugCategory *category)
812 {
813   return category->color;
814 }
815 /**
816  * gst_debug_category_get_description:
817  * @category: category to get description for
818  * 
819  * Returns the description of a #GstCategory
820  * 
821  * Returns: the description of the category
822  */
823 const gchar *
824 gst_debug_category_get_description (GstDebugCategory *category)
825 {
826   return category->description;
827 }
828 /**
829  * gst_debug_get_all_categories:
830  *
831  * Returns a snapshot of a all categories that are currently in use . This list
832  * may change anytime.
833  * The caller has to free the list after use.
834  * <emphasis>This function is not threadsafe, so only use it while only the 
835  * main thread is running.</emphasis>
836  * 
837  * Returns: the list of categories
838  */
839 GSList *
840 gst_debug_get_all_categories (void)
841 {
842   GSList *ret;
843
844   g_static_mutex_lock (&__cat_mutex);
845   ret = g_slist_copy (__categories);
846   g_static_mutex_unlock (&__cat_mutex);
847
848   return ret; 
849 }
850
851 /*** FUNCTION POINTERS ********************************************************/
852
853 GHashTable *__gst_function_pointers = NULL;
854 gchar *_gst_debug_nameof_funcptr (void *ptr) G_GNUC_NO_INSTRUMENT;
855
856 /* This function MUST NOT return NULL */
857 gchar *
858 _gst_debug_nameof_funcptr (void *ptr)
859 {
860   gchar *ptrname;
861   Dl_info dlinfo;
862   if (__gst_function_pointers && (ptrname = g_hash_table_lookup(__gst_function_pointers,ptr))) {
863     return g_strdup(ptrname);
864   } else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
865     return g_strdup(dlinfo.dli_sname);
866   } else {
867     return g_strdup_printf("%p",ptr);
868   }
869 }
870 void *
871 _gst_debug_register_funcptr (void *ptr, gchar *ptrname)
872 {
873   if (!__gst_function_pointers)
874     __gst_function_pointers = g_hash_table_new (g_direct_hash, g_direct_equal);
875   if (!g_hash_table_lookup (__gst_function_pointers, ptr))
876     g_hash_table_insert (__gst_function_pointers, ptr, ptrname);
877
878   return ptr;
879 }
880
881 #endif /* GST_DISABLE_GST_DEBUG */
882
883 #ifdef GST_ENABLE_FUNC_INSTRUMENTATION
884 /* FIXME make this thread specific */
885 static GSList *stack_trace = NULL;
886
887 void __cyg_profile_func_enter(void *this_fn,void *call_site) G_GNUC_NO_INSTRUMENT;
888 void __cyg_profile_func_enter(void *this_fn,void *call_site) 
889 {
890   gchar *name = _gst_debug_nameof_funcptr (this_fn);
891   gchar *site = _gst_debug_nameof_funcptr (call_site);
892         
893   GST_CAT_DEBUG(GST_CAT_CALL_TRACE, "entering function %s from %s", name, site);
894   stack_trace = g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)", this_fn, name, call_site, site));
895
896   g_free (name);
897   g_free (site);
898 }
899
900 void __cyg_profile_func_exit(void *this_fn,void *call_site) G_GNUC_NO_INSTRUMENT;
901 void __cyg_profile_func_exit(void *this_fn,void *call_site) 
902 {
903   gchar *name = _gst_debug_nameof_funcptr (this_fn);
904
905   GST_CAT_DEBUG(GST_CAT_CALL_TRACE, "leaving function %s", name);
906   g_free (stack_trace->data);
907   stack_trace = g_slist_delete_link (stack_trace, stack_trace);
908
909   g_free (name);
910 }
911
912 void 
913 gst_debug_print_stack_trace (void)
914 {
915   GSList *walk = stack_trace;
916   gint count = 0;
917
918   if (walk)
919     walk = g_slist_next (walk);
920
921   while (walk) {
922     gchar *name = (gchar *) walk->data;
923
924     g_print ("#%-2d %s\n", count++, name);
925
926     walk = g_slist_next (walk);
927   }
928 }
929 #else
930 void 
931 gst_debug_print_stack_trace (void)
932 {
933   /* nothing because it's compiled out */
934 }
935
936 #endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */