source: trunk/third/gstreamer/gst/gstinfo.c @ 21448

Revision 21448, 33.1 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21447, which included commits to RCS files with non-trunk default branches.
Line 
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 */
49GST_DEBUG_CATEGORY_STATIC (_GST_CAT_DEBUG);
50
51#if 0
52#if defined __sgi__
53#include <rld_interface.h>
54typedef 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}
64Dl_info;
65
66#define _RLD_DLADDR             14
67int dladdr (void *address, Dl_info * dl);
68
69int
70dladdr (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
80static void gst_debug_reset_threshold (gpointer category, gpointer unused);
81static void gst_debug_reset_all_thresholds (void);
82
83#ifdef HAVE_PRINTF_EXTENSION
84static int _gst_info_printf_extension (FILE * stream,
85    const struct printf_info *info, const void *const *args);
86static int _gst_info_printf_extension_arginfo (const struct printf_info *info,
87    size_t n, int *argtypes);
88#endif
89
90struct _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 */
98static GStaticMutex __level_name_mutex = G_STATIC_MUTEX_INIT;
99static GSList *__level_name = NULL;
100typedef struct
101{
102  GPatternSpec *pat;
103  GstDebugLevel level;
104}
105LevelNameEntry;
106
107/* list of all categories */
108static GStaticMutex __cat_mutex = G_STATIC_MUTEX_INIT;
109static GSList *__categories = NULL;
110
111/* all registered debug handlers */
112typedef struct
113{
114  GstLogFunction func;
115  gpointer user_data;
116}
117LogFuncEntry;
118static GStaticMutex __log_func_mutex = G_STATIC_MUTEX_INIT;
119static GSList *__log_functions = NULL;
120
121static GstAtomicInt __default_level;
122static GstAtomicInt __use_color;
123gboolean __gst_debug_enabled = TRUE;
124
125
126GstDebugCategory *GST_CAT_DEFAULT = NULL;
127
128GstDebugCategory *GST_CAT_GST_INIT = NULL;
129GstDebugCategory *GST_CAT_COTHREADS = NULL;
130GstDebugCategory *GST_CAT_COTHREAD_SWITCH = NULL;
131GstDebugCategory *GST_CAT_AUTOPLUG = NULL;
132GstDebugCategory *GST_CAT_AUTOPLUG_ATTEMPT = NULL;
133GstDebugCategory *GST_CAT_PARENTAGE = NULL;
134GstDebugCategory *GST_CAT_STATES = NULL;
135GstDebugCategory *GST_CAT_PLANNING = NULL;
136GstDebugCategory *GST_CAT_SCHEDULING = NULL;
137
138/* FIXME: remove GST_CAT_DATAFLOW in 0.9 */
139GstDebugCategory *GST_CAT_DATAFLOW = NULL;
140GstDebugCategory *GST_CAT_BUFFER = NULL;
141GstDebugCategory *GST_CAT_CAPS = NULL;
142GstDebugCategory *GST_CAT_CLOCK = NULL;
143GstDebugCategory *GST_CAT_ELEMENT_PADS = NULL;
144GstDebugCategory *GST_CAT_PADS = NULL;
145GstDebugCategory *GST_CAT_PIPELINE = NULL;
146GstDebugCategory *GST_CAT_PLUGIN_LOADING = NULL;
147GstDebugCategory *GST_CAT_PLUGIN_INFO = NULL;
148GstDebugCategory *GST_CAT_PROPERTIES = NULL;
149GstDebugCategory *GST_CAT_THREAD = NULL;
150GstDebugCategory *GST_CAT_TYPES = NULL;
151GstDebugCategory *GST_CAT_XML = NULL;
152GstDebugCategory *GST_CAT_NEGOTIATION = NULL;
153GstDebugCategory *GST_CAT_REFCOUNTING = NULL;
154GstDebugCategory *GST_CAT_ERROR_SYSTEM = NULL;
155GstDebugCategory *GST_CAT_EVENT = NULL;
156GstDebugCategory *GST_CAT_PARAMS = NULL;
157GstDebugCategory *GST_CAT_CALL_TRACE = NULL;
158GstDebugCategory *GST_CAT_SEEK = NULL;
159GstDebugCategory *GST_CAT_SIGNAL = NULL;
160GstDebugCategory *GST_CAT_PROBE = NULL;
161
162/* FIXME: export this? */
163gboolean
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 */
203void
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 */
311void
312gst_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 */
337void
338gst_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 */
375const gchar *
376gst_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
385static gchar *
386gst_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 */
441gchar *
442gst_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 */
487void
488gst_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 */
540const gchar *
541gst_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 */
570void
571gst_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
596static gint
597gst_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
604static gint
605gst_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
612static guint
613gst_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 */
645guint
646gst_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 */
669guint
670gst_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 */
690void
691gst_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 */
703gboolean
704gst_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 */
719void
720gst_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 */
732gboolean
733gst_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 */
745void
746gst_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 */
759GstDebugLevel
760gst_debug_get_default_threshold (void)
761{
762  return (GstDebugLevel) gst_atomic_int_read (&__default_level);
763}
764static void
765gst_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
785exit:
786  g_static_mutex_unlock (&__level_name_mutex);
787}
788static void
789gst_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}
795static void
796for_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 */
816void
817gst_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 */
842void
843gst_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
870GstDebugCategory *
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 */
903void
904gst_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 */
935void
936gst_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 */
954void
955gst_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 */
968GstDebugLevel
969gst_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 */
982const gchar *
983gst_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 */
997guint
998gst_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 */
1011const gchar *
1012gst_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 */
1028GSList *
1029gst_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
1042GHashTable *__gst_function_pointers = NULL;
1043const 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
1078void *
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
1090static 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
1109static 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
1121gboolean
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 */
1132static GSList *stack_trace = NULL;
1133
1134void
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
1152void
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
1166void
1167gst_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
1184void
1185gst_debug_print_stack_trace (void)
1186{
1187  /* nothing because it's compiled out */
1188}
1189
1190#endif /* GST_ENABLE_FUNC_INTSTRUMENTATION */
Note: See TracBrowser for help on using the repository browser.