gstfunnel: avoid access of freed pad
[platform/upstream/gstreamer.git] / gst / gsttrace.c
1 /* GStreamer
2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3  *                    2000 Wim Taymans <wtay@chello.be>
4  *
5  * gsttrace.c: Tracing functions (deprecated)
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 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <stdio.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #if defined (_MSC_VER) && _MSC_VER >= 1400
36 # include <io.h>
37 #endif
38
39 #include "gst_private.h"
40 #include "gstinfo.h"
41
42 #include "gsttrace.h"
43
44 GMutex _gst_trace_mutex;
45
46 /* global flags */
47 static GstAllocTraceFlags _gst_trace_flags = GST_ALLOC_TRACE_NONE;
48
49 /* list of registered tracers */
50 static GList *_gst_alloc_tracers = NULL;
51
52 static void
53 _at_exit (void)
54 {
55   if (_gst_trace_flags)
56     _priv_gst_alloc_trace_dump ();
57 }
58
59 void
60 _priv_gst_alloc_trace_initialize (void)
61 {
62   const gchar *trace;
63
64   trace = g_getenv ("GST_TRACE");
65   if (trace != NULL) {
66     const GDebugKey keys[] = {
67       {"live", GST_ALLOC_TRACE_LIVE},
68       {"mem-live", GST_ALLOC_TRACE_MEM_LIVE},
69     };
70     _gst_trace_flags = g_parse_debug_string (trace, keys, G_N_ELEMENTS (keys));
71     atexit (_at_exit);
72   }
73
74   g_mutex_init (&_gst_trace_mutex);
75 }
76
77 void
78 _priv_gst_alloc_trace_deinit (void)
79 {
80   g_mutex_clear (&_gst_trace_mutex);
81 }
82
83 /**
84  * _priv_gst_alloc_trace_register:
85  * @name: the name of the new alloc trace object.
86  * @offset: the offset in the object where a GType an be found. -1 when the
87  * object has no gtype.
88  *
89  * Register an get a handle to a GstAllocTrace object that
90  * can be used to trace memory allocations.
91  *
92  * Returns: A handle to a GstAllocTrace.
93  */
94 GstAllocTrace *
95 _priv_gst_alloc_trace_register (const gchar * name, goffset offset)
96 {
97   GstAllocTrace *trace;
98
99   g_return_val_if_fail (name, NULL);
100
101   trace = g_slice_new (GstAllocTrace);
102   trace->name = g_strdup (name);
103   trace->live = 0;
104   trace->mem_live = NULL;
105   trace->flags = _gst_trace_flags;
106   trace->offset = offset;
107
108   _gst_alloc_tracers = g_list_prepend (_gst_alloc_tracers, trace);
109
110   return trace;
111 }
112
113 static gint
114 compare_func (GstAllocTrace * a, GstAllocTrace * b)
115 {
116   return strcmp (a->name, b->name);
117 }
118
119 static GList *
120 gst_alloc_trace_list_sorted (void)
121 {
122   GList *ret;
123
124   ret = g_list_sort (g_list_copy (_gst_alloc_tracers),
125       (GCompareFunc) compare_func);
126
127   return ret;
128 }
129
130 static void
131 gst_alloc_trace_print (const GstAllocTrace * trace)
132 {
133   GSList *mem_live;
134
135   g_return_if_fail (trace != NULL);
136
137   if (trace->flags & GST_ALLOC_TRACE_LIVE) {
138     g_print ("%-22.22s : %d\n", trace->name, trace->live);
139   } else {
140     g_print ("%-22.22s : (no live count)\n", trace->name);
141   }
142
143   if (trace->flags & GST_ALLOC_TRACE_MEM_LIVE) {
144     mem_live = trace->mem_live;
145
146     while (mem_live) {
147       gpointer data = mem_live->data;
148       const gchar *type_name;
149       gchar *extra = NULL;
150       gint refcount = -1;
151
152       if (trace->offset == -2) {
153         if (G_IS_OBJECT (data)) {
154           type_name = G_OBJECT_TYPE_NAME (data);
155           refcount = G_OBJECT (data)->ref_count;
156         } else
157           type_name = "<invalid>";
158       } else if (trace->offset == -1) {
159         type_name = "<unknown>";
160       } else {
161         GType type;
162
163         type = G_STRUCT_MEMBER (GType, data, trace->offset);
164         type_name = g_type_name (type);
165
166         if (type == GST_TYPE_CAPS) {
167           extra = gst_caps_to_string (data);
168           refcount = GST_MINI_OBJECT_REFCOUNT_VALUE (data);
169         }
170       }
171
172       if (extra) {
173         g_print ("  %-20.20s : (%d) %p (\"%s\")\n", type_name, refcount, data,
174             extra);
175         g_free (extra);
176       } else
177         g_print ("  %-20.20s : (%d) %p\n", type_name, refcount, data);
178
179       mem_live = mem_live->next;
180     }
181   }
182 }
183
184 /**
185  * _priv_gst_alloc_trace_dump:
186  *
187  * Print the status of all registered alloc trace objects.
188  */
189 void
190 _priv_gst_alloc_trace_dump (void)
191 {
192   GList *orig, *walk;
193
194   orig = walk = gst_alloc_trace_list_sorted ();
195
196   while (walk) {
197     GstAllocTrace *trace = (GstAllocTrace *) walk->data;
198
199     gst_alloc_trace_print (trace);
200
201     walk = g_list_next (walk);
202   }
203
204   g_list_free (orig);
205 }