commit to make gstreamer follow the gtk function/macro naming conventions:
[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  *
5  * gstinfo.c: INFO, ERROR, and DEBUG systems
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include <dlfcn.h>
24 #include "gst_private.h"
25 #include "gstelement.h"
26 #include "gstpad.h"
27 #include "gstscheduler.h"
28
29 #if defined __sgi__
30 #include <rld_interface.h>
31 typedef struct DL_INFO {
32   const char * dli_fname;
33   void       * dli_fbase;
34   const char * dli_sname;
35   void       * dli_saddr;
36   int          dli_version;
37   int          dli_reserved1;
38   long         dli_reserved[4];
39 } Dl_info;
40 #define _RLD_DLADDR             14
41 int dladdr(void *address, Dl_info *dl);
42
43 int dladdr(void *address, Dl_info *dl)
44 {
45   void *v;
46   v = _rld_new_interface(_RLD_DLADDR,address,dl);
47   return (int)v;
48 }
49 #endif
50
51 extern gchar *_gst_progname;
52
53
54 /***** Categories and colorization *****/
55 static gchar *_gst_info_category_strings[] = {
56   "GST_INIT",
57   "COTHREADS",
58   "COTHREAD_SWITCH",
59   "AUTOPLUG",
60   "AUTOPLUG_ATTEMPT",
61   "PARENTAGE",
62   "STATES",
63   "PLANNING",
64   "SCHEDULING",
65   "DATAFLOW",
66   "BUFFER",
67   "CAPS",
68   "CLOCK",
69   "ELEMENT_PADS",
70   "ELEMENTFACTORY",
71   "PADS",
72   "PIPELINE",
73   "PLUGIN_LOADING",
74   "PLUGIN_ERRORS",
75   "PLUGIN_INFO",
76   "PROPERTIES",
77   "THREAD",
78   "TYPES",
79   "XML",
80   "NEGOTIATION",
81   "REFCOUNTING",
82   "EVENT",
83   "PARAMS",
84
85   [30] = "CALL_TRACE",
86 };
87
88 /**
89  * gst_get_category_name:
90  * @category: the category to return the name of
91  *
92  * Return a string containing the name of the category
93  *
94  * Returns: string containing the name of the category
95  */
96 const gchar *
97 gst_get_category_name (gint category) {
98   if ((category >= 0) && (category < GST_CAT_MAX_CATEGORY))
99     return _gst_info_category_strings[category];
100   else
101     return NULL;
102 }
103
104
105 /*
106  * Attribute codes:
107  * 00=none 01=bold 04=underscore 05=blink 07=reverse 08=concealed
108  * Text color codes:
109  * 30=black 31=red 32=green 33=yellow 34=blue 35=magenta 36=cyan 37=white
110  * Background color codes:
111  * 40=black 41=red 42=green 43=yellow 44=blue 45=magenta 46=cyan 47=white
112  */
113 const gchar *_gst_category_colors[32] = {
114   [GST_CAT_GST_INIT]            = "07;37",
115   [GST_CAT_COTHREADS]           = "00;32",
116   [GST_CAT_COTHREAD_SWITCH]     = "00;37;42",
117   [GST_CAT_AUTOPLUG]            = "00;34",
118   [GST_CAT_AUTOPLUG_ATTEMPT]    = "00;36;44",
119   [GST_CAT_PARENTAGE]           = "01;37;41",           /* !! */
120   [GST_CAT_STATES]              = "00;31",
121   [GST_CAT_PLANNING]            = "07;35",
122   [GST_CAT_SCHEDULING]          = "00;35",
123   [GST_CAT_DATAFLOW]            = "00;32",
124   [GST_CAT_BUFFER]              = "00;32",
125   [GST_CAT_CAPS]                = "04;34",
126   [GST_CAT_CLOCK]               = "00;33",              /* !! */
127   [GST_CAT_ELEMENT_PADS]        = "01;37;41",           /* !! */
128   [GST_CAT_ELEMENT_FACTORY]     = "01;37;41",           /* !! */
129   [GST_CAT_PADS]                = "01;37;41",           /* !! */
130   [GST_CAT_PIPELINE]            = "01;37;41",           /* !! */
131   [GST_CAT_PLUGIN_LOADING]      = "00;36",
132   [GST_CAT_PLUGIN_ERRORS]       = "05;31",
133   [GST_CAT_PLUGIN_INFO]         = "00;36",
134   [GST_CAT_PROPERTIES]          = "00;37;44",           /* !! */
135   [GST_CAT_THREAD]              = "00;31",
136   [GST_CAT_TYPES]               = "01;37;41",           /* !! */
137   [GST_CAT_XML]                 = "01;37;41",           /* !! */
138   [GST_CAT_NEGOTIATION]         = "07;34",
139   [GST_CAT_REFCOUNTING]         = "00;34:42",
140   [GST_CAT_EVENT]               = "01;37;41",           /* !! */
141   [GST_CAT_PARAMS]              = "00;30;43",           /* !! */
142
143   [GST_CAT_CALL_TRACE]          = "",
144   [31]                          = "05;31",
145 };
146
147 /* colorization hash - DEPRACATED in favor of above */
148 inline gint _gst_debug_stringhash_color(gchar *file) {
149   int filecolor = 0;
150   while (file[0]) filecolor += *(char *)(file++);
151   filecolor = (filecolor % 6) + 31;
152   return filecolor;
153 }
154
155
156
157 /***** DEBUG system *****/
158 GstDebugHandler _gst_debug_handler = gst_default_debug_handler;
159 guint32 _gst_debug_categories = 0x00000000;
160
161 /**
162  * gst_default_debug_handler:
163  * @category: category of the DEBUG message
164  * @incore: if the debug handler is for core code.
165  * @file: the file the DEBUG occurs in
166  * @function: the function the DEBUG occurs in
167  * @line: the line number in the file
168  * @debug_string: the current debug_string in the function, if any
169  * @element: pointer to the #GstElement in question
170  * @string: the actual DEBUG string
171  *
172  * Prints out the DEBUG mesage in a variant of the following form:
173  *
174  *   DEBUG(pid:cid):gst_function:542(args): [elementname] something neat happened
175  */
176 void
177 gst_default_debug_handler (gint category, gboolean incore,
178                            const gchar *file, const gchar *function,
179                            gint line, const gchar *debug_string,
180                            void *element, gchar *string)
181   __attribute__ ((no_instrument_function));
182
183 void
184 gst_default_debug_handler (gint category, gboolean incore,
185                            const gchar *file, const gchar *function,
186                            gint line, const gchar *debug_string,
187                            void *element, gchar *string)
188 {
189   gchar *empty = "";
190   gchar *elementname = empty,*location = empty;
191   int pthread_id = getpid();
192   int cothread_id = 0; /*FIXME*/
193 #ifdef GST_DEBUG_COLOR
194   int pthread_color = pthread_id%6 + 31;
195   int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
196 #endif
197
198   if (debug_string == NULL) debug_string = "";
199 /*  if (category != GST_CAT_GST_INIT) */
200     location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
201   if (element && GST_IS_ELEMENT (element))
202 #ifdef GST_DEBUG_COLOR
203     elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
204 #else
205     elementname = g_strdup_printf (" [%s]", GST_OBJECT_NAME (element));
206 #endif
207
208 #ifdef GST_DEBUG_COLOR
209   fprintf(stderr,"DEBUG(\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
210           "%s;%sm%s%s\033[00m %s\n",
211           pthread_color,pthread_id,cothread_color,cothread_id,incore?"00":"01",
212           _gst_category_colors[category],location,elementname,string);
213 #else
214   fprintf(stderr,"DEBUG(%5d:%2d)%s%s %s\n",
215           pthread_id,cothread_id,location,elementname,string);
216 #endif /* GST_DEBUG_COLOR */
217
218   if (location != empty) g_free(location);
219   if (elementname != empty) g_free(elementname);
220
221   g_free(string);
222 }
223
224
225 /**
226  * gst_debug_set_categories:
227  * @categories: bitmask of DEBUG categories to enable
228  *
229  * Enable the output of DEBUG categories based on the given bitmask.
230  * The bit for any given category is (1 << GST_CAT_...).
231  */
232 void
233 gst_debug_set_categories (guint32 categories) {
234   _gst_debug_categories = categories;
235 }
236
237 /**
238  * gst_debug_get_categories:
239  *
240  * Return the current bitmask of enabled DEBUG categories
241  *
242  * Returns: the current bitmask of enabled DEBUG categories
243  * The bit for any given category is (1 << GST_CAT_...).
244  */
245 guint32
246 gst_debug_get_categories () {
247   return _gst_debug_categories;
248 }
249
250 /**
251  * gst_debug_enable_category:
252  * @category: the category to enable
253  *
254  * Enables the given GST_CAT_... DEBUG category.
255  */
256 void
257 gst_debug_enable_category (gint category) {
258   _gst_debug_categories |= (1 << category);
259 }
260
261 /**
262  * gst_debug_disable_category:
263  * @category: the category to disable
264  *
265  * Disables the given GST_CAT_... DEBUG category.
266  */
267 void
268 gst_debug_disable_category (gint category) {
269   _gst_debug_categories &= ~ (1 << category);
270 }
271
272
273
274
275 /***** INFO system *****/
276 GstInfoHandler _gst_info_handler = gst_default_info_handler;
277 guint32 _gst_info_categories = 0x00000001;
278
279
280 /**
281  * gst_default_info_handler:
282  * @category: category of the INFO message
283  * @incore: if the info handler is for core code.
284  * @file: the file the INFO occurs in
285  * @function: the function the INFO occurs in
286  * @line: the line number in the file
287  * @debug_string: the current debug_string in the function, if any
288  * @element: pointer to the #GstElement in question
289  * @string: the actual INFO string
290  *
291  * Prints out the INFO mesage in a variant of the following form:
292  *
293  *   INFO:gst_function:542(args): [elementname] something neat happened
294  */
295 void
296 gst_default_info_handler (gint category, gboolean incore,
297                           const gchar *file, const gchar *function,
298                           gint line, const gchar *debug_string,
299                           void *element, gchar *string)
300 {
301   gchar *empty = "";
302   gchar *elementname = empty,*location = empty;
303   int pthread_id = getpid();
304   int cothread_id = 0; /*FIXME*/
305 #ifdef GST_DEBUG_COLOR
306   int pthread_color = pthread_id%6 + 31;
307   int cothread_color = (cothread_id < 0) ? 37 : (cothread_id%6 + 31);
308 #endif
309
310   if (debug_string == NULL) debug_string = "";
311   if (category != GST_CAT_GST_INIT)
312     location = g_strdup_printf("%s:%d%s:",function,line,debug_string);
313   if (element && GST_IS_ELEMENT (element))
314     elementname = g_strdup_printf (" \033[04m[%s]\033[00m", GST_OBJECT_NAME (element));
315
316 /*
317 #ifdef GST_DEBUG_ENABLED
318 */
319   #ifdef GST_DEBUG_COLOR
320     fprintf(stderr,"\033[01mINFO\033[00m (\033[00;%dm%5d\033[00m:\033[00;%dm%2d\033[00m)\033["
321             GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
322             pthread_color,pthread_id,cothread_color,cothread_id,
323             _gst_category_colors[category],location,elementname,string);
324   #else
325     fprintf(stderr,"INFO (%5d:%2d)%s%s %s\n",
326             pthread_id,cothread_id,location,elementname,string);
327 #endif /* GST_DEBUG_COLOR */
328 /*
329 #else
330   #ifdef GST_DEBUG_COLOR
331     fprintf(stderr,"\033[01mINFO\033[00m:\033[" GST_DEBUG_CHAR_MODE ";%sm%s%s\033[00m %s\n",
332             location,elementname,_gst_category_colors[category],string);
333   #else
334     fprintf(stderr,"INFO:%s%s %s\n",
335             location,elementname,string);
336   #endif * GST_DEBUG_COLOR *
337
338 #endif
339 */
340
341   if (location != empty) g_free(location);
342   if (elementname != empty) g_free(elementname);
343
344   g_free(string);
345 }
346
347 /**
348  * gst_info_set_categories:
349  * @categories: bitmask of INFO categories to enable
350  *
351  * Enable the output of INFO categories based on the given bitmask.
352  * The bit for any given category is (1 << GST_CAT_...).
353  */
354 void
355 gst_info_set_categories (guint32 categories) {
356   _gst_info_categories = categories;
357 }
358
359 /**
360  * gst_info_get_categories:
361  *
362  * Return the current bitmask of enabled INFO categories
363  * The bit for any given category is (1 << GST_CAT_...).
364  *
365  * Returns: the current bitmask of enabled INFO categories
366  * The bit for any given category is (1 << GST_CAT_...).
367  */
368 guint32
369 gst_info_get_categories () {
370   return _gst_info_categories;
371 }
372
373 /**
374  * gst_info_enable_category:
375  * @category: the category to enable
376  *
377  * Enables the given GST_CAT_... INFO category.
378  */
379 void
380 gst_info_enable_category (gint category) {
381   _gst_info_categories |= (1 << category);
382 }
383
384 /**
385  * gst_info_disable_category:
386  * @category: the category to disable
387  *
388  * Disables the given GST_CAT_... INFO category.
389  */
390 void
391 gst_info_disable_category (gint category) {
392   _gst_info_categories &= ~ (1 << category);
393 }
394
395
396
397 /***** ERROR system *****/
398 GstErrorHandler _gst_error_handler = gst_default_error_handler;
399
400 /**
401  * gst_default_error_handler:
402  * @file: the file the ERROR occurs in
403  * @function: the function the INFO occurs in
404  * @line: the line number in the file
405  * @debug_string: the current debug_string in the function, if any
406  * @element: pointer to the #GstElement in question
407  * @object: pointer to a related object
408  * @string: the actual ERROR string
409  *
410  * Prints out the given ERROR string in a variant of the following format:
411  *
412  * ***** GStreamer ERROR ***** in file gstsomething.c at gst_function:399(arg)
413  * Element: /pipeline/thread/element.src
414  * Error: peer is null!
415  * ***** attempting to stack trace.... *****
416  *
417  * At the end, it attempts to print the stack trace via GDB.
418  */
419 void
420 gst_default_error_handler (gchar *file, gchar *function,
421                            gint line, gchar *debug_string,
422                            void *element, void *object, gchar *string)
423 {
424   int chars = 0;
425   gchar *path;
426   int i;
427
428   /* if there are NULL pointers, point them to null strings to clean up output */
429   if (!debug_string) debug_string = "";
430   if (!string) string = "";
431
432   /* print out a preamble */
433   fprintf(stderr,"***** GStreamer ERROR ***** in file %s at %s:%d%s\n",
434           file,function,line,debug_string);
435
436   /* if there's an element, print out the pertinent information */
437   if (element) {
438     if (GST_IS_OBJECT(element)) {
439       path = gst_object_get_path_string(element);
440       fprintf(stderr,"Element: %s",path);
441       chars = 9 + strlen(path);
442       g_free(path);
443     } else {
444       fprintf(stderr,"Element ptr: %p",element);
445       chars = 15 + sizeof(void*)*2;
446     }
447   }
448
449   /* if there's an object, print it out as well */
450   if (object) {
451     /* attempt to pad the line, or create a new one */
452     if (chars < 40)
453       for (i=0;i<(40-chars)/8+1;i++) fprintf(stderr,"\t");
454     else
455       fprintf(stderr,"\n");
456
457     if (GST_IS_OBJECT(object)) {
458       path = gst_object_get_path_string(object);
459       fprintf(stderr,"Object: %s",path);
460       g_free(path);
461     } else {
462       fprintf(stderr,"Object ptr: %p",object);
463     }
464   }
465
466   fprintf(stderr,"\n");
467   fprintf(stderr,"Error: %s\n",string);
468
469   g_free(string);
470
471   fprintf(stderr,"***** attempting to stack trace.... *****\n");
472
473   g_on_error_stack_trace (_gst_progname);
474
475   exit(1);
476 }
477
478
479
480 /***** DEBUG system *****/
481 GHashTable *__gst_function_pointers = NULL;
482 /* FIXME make this thread specific */
483 /* static GSList *stack_trace = NULL; */
484
485 gchar *_gst_debug_nameof_funcptr (void *ptr) __attribute__ ((no_instrument_function));
486
487 gchar *
488 _gst_debug_nameof_funcptr (void *ptr)
489 {
490   gchar *ptrname;
491   Dl_info dlinfo;
492   if (__gst_function_pointers && (ptrname = g_hash_table_lookup(__gst_function_pointers,ptr))) {
493     return g_strdup(ptrname);
494   } else if (dladdr(ptr,&dlinfo) && dlinfo.dli_sname) {
495     return g_strdup(dlinfo.dli_sname);
496   } else {
497     return g_strdup_printf("%p",ptr);
498   }
499   return NULL;
500 }
501
502
503 #ifdef GST_ENABLE_FUNC_INSTRUMENTATION
504 void __cyg_profile_func_enter(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
505 void __cyg_profile_func_enter(void *this_fn,void *call_site) 
506 {
507   gchar *name = _gst_debug_nameof_funcptr (this_fn);
508   gchar *site = _gst_debug_nameof_funcptr (call_site);
509         
510   GST_DEBUG(GST_CAT_CALL_TRACE, "entering function %s from %s", name, site);
511   stack_trace = g_slist_prepend (stack_trace, g_strdup_printf ("%8p in %s from %p (%s)", this_fn, name, call_site, site));
512
513   g_free (name);
514   g_free (site);
515 }
516
517 void __cyg_profile_func_exit(void *this_fn,void *call_site) __attribute__ ((no_instrument_function));
518 void __cyg_profile_func_exit(void *this_fn,void *call_site) 
519 {
520   gchar *name = _gst_debug_nameof_funcptr (this_fn);
521
522   GST_DEBUG(GST_CAT_CALL_TRACE, "leaving function %s", name);
523   g_free (stack_trace->data);
524   stack_trace = g_slist_delete_link (stack_trace, stack_trace);
525
526   g_free (name);
527 }
528
529 void 
530 gst_debug_print_stack_trace (void)
531 {
532   GSList *walk = stack_trace;
533   gint count = 0;
534
535   if (walk)
536     walk = g_slist_next (walk);
537
538   while (walk) {
539     gchar *name = (gchar *) walk->data;
540
541     g_print ("#%-2d %s\n", count++, name);
542
543     walk = g_slist_next (walk);
544   }
545 }
546 #else
547 void 
548 gst_debug_print_stack_trace (void)
549 {
550   /* nothing because it's compiled out */
551 }
552
553 #endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */