2 * Copyright (C) 2016 Collabora Ltd. <guillaume.desmottes@collabora.co.uk>
3 * Copyright (C) 2019 Nirbheek Chauhan <nirbheek@centricular.com>
5 * gstleaks.c: tracing module detecting object leaks
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.
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.
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., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
23 * SECTION:tracer-leaks
24 * @short_description: detect GstObject and GstMiniObject leaks
26 * This tracing module tracks the lifetimes of #GstObject and #GstMiniObject
27 * objects and prints a list of leaks to the debug log under `GST_TRACER:7` when
28 * gst_deinit() is called, and also prints a g_warning().
30 * Starting with GStreamer 1.18, you can also use action signals on the tracer
31 * object to fetch leak information. Use gst_tracing_get_active_tracers() to
32 * get a list of all active tracers and find the right one by name.
34 * You can activate this tracer in the usual way by adding the string 'leaks'
35 * to the environment variable `GST_TRACERS`. Such as: `GST_TRACERS=leaks`
37 * Note that the values are separated by semicolon (`;`), such as:
38 * `GST_TRACERS=leaks;latency`, and multiple instances of the same tracer can be
39 * active at the same time.
41 * Parameters can also be passed to each tracer. The leaks tracer currently
42 * accepts five params:
43 * 1. filters: (string) to filter which objects to record
44 * 2. check-refs: (boolean) whether to record every location where a leaked
45 * object was reffed and unreffed
46 * 3. stack-traces-flags: (string) full or none; see: #GstStackTraceFlags
47 * 4. name: (string) set a name for the tracer object itself
48 * 5. log-leaks-on-deinit: (boolean) whether to report all leaks on
49 * gst_deinit() by printing them in the debug log; "true" by default
53 * GST_TRACERS='leaks(filters="GstEvent,GstMessage",stack-traces-flags=none)'
56 * GST_TRACERS='leaks(filters="GstBuffer",stack-traces-flags=full,check-refs=true);leaks(name=all-leaks)'
67 #include <glib-unix.h>
69 #endif /* G_OS_UNIX */
71 GST_DEBUG_CATEGORY_STATIC (gst_leaks_debug);
72 #define GST_CAT_DEFAULT gst_leaks_debug
77 SIGNAL_GET_LIVE_OBJECTS,
78 SIGNAL_LOG_LIVE_OBJECTS,
79 SIGNAL_ACTIVITY_START_TRACKING,
80 SIGNAL_ACTIVITY_GET_CHECKPOINT,
81 SIGNAL_ACTIVITY_LOG_CHECKPOINT,
82 SIGNAL_ACTIVITY_STOP_TRACKING,
87 #define DEFAULT_LOG_LEAKS TRUE /* for backwards-compat */
90 GST_DEBUG_CATEGORY_INIT (gst_leaks_debug, "leaks", 0, "leaks tracer");
91 #define gst_leaks_tracer_parent_class parent_class
92 G_DEFINE_TYPE_WITH_CODE (GstLeaksTracer, gst_leaks_tracer,
93 GST_TYPE_TRACER, _do_init);
95 static GstStructure *gst_leaks_tracer_get_live_objects (GstLeaksTracer * self);
96 static void gst_leaks_tracer_log_live_objects (GstLeaksTracer * self);
97 static void gst_leaks_tracer_activity_start_tracking (GstLeaksTracer * self);
98 static GstStructure *gst_leaks_tracer_activity_get_checkpoint (GstLeaksTracer *
100 static void gst_leaks_tracer_activity_log_checkpoint (GstLeaksTracer * self);
101 static void gst_leaks_tracer_activity_stop_tracking (GstLeaksTracer * self);
104 static void gst_leaks_tracer_setup_signals (GstLeaksTracer * leaks);
105 static void gst_leaks_tracer_cleanup_signals (GstLeaksTracer * leaks);
108 static GstTracerRecord *tr_alive;
109 static GstTracerRecord *tr_refings;
110 static GstTracerRecord *tr_added = NULL;
111 static GstTracerRecord *tr_removed = NULL;
112 static GQueue instances = G_QUEUE_INIT;
113 static guint gst_leaks_tracer_signals[LAST_SIGNAL] = { 0 };
115 G_LOCK_DEFINE_STATIC (instances);
133 gchar *creation_trace;
139 object_refing_info_free (ObjectRefingInfo * refinfo)
141 g_free (refinfo->trace);
146 object_refing_infos_free (ObjectRefingInfos * infos)
148 g_list_free_full (infos->refing_infos,
149 (GDestroyNotify) object_refing_info_free);
151 g_free (infos->creation_trace);
156 set_print_stack_trace_from_string (GstLeaksTracer * self, const gchar * str)
160 /* Test if we can retrieve backtrace */
161 trace = gst_debug_get_stack_trace (FALSE);
167 if (g_strcmp0 (str, "full") == 0)
168 self->trace_flags = GST_STACK_TRACE_SHOW_FULL;
170 self->trace_flags = GST_STACK_TRACE_SHOW_NONE;
174 set_print_stack_trace (GstLeaksTracer * self, GstStructure * params)
176 const gchar *trace_flags = g_getenv ("GST_LEAKS_TRACER_STACK_TRACE");
178 self->trace_flags = -1;
179 if (!trace_flags && params)
180 trace_flags = gst_structure_get_string (params, "stack-traces-flags");
185 set_print_stack_trace_from_string (self, trace_flags);
189 set_filters (GstLeaksTracer * self, const gchar * filters)
192 GStrv tmp = g_strsplit (filters, ",", -1);
194 self->filter = g_array_sized_new (FALSE, FALSE, sizeof (GType),
195 g_strv_length (tmp));
196 for (i = 0; tmp[i]; i++) {
199 type = g_type_from_name (tmp[i]);
201 /* The type may not yet be known by the type system, typically because
202 * the plugin implementing it as not yet be loaded. Save it for now as
203 * it will have another chance to be added to the filter later in
204 * should_handle_object_type() when/if the object type is actually
206 if (!self->unhandled_filter)
207 self->unhandled_filter = g_hash_table_new_full (g_str_hash, g_str_equal,
210 g_hash_table_add (self->unhandled_filter, g_strdup (tmp[i]));
211 g_atomic_int_inc (&self->unhandled_filter_count);
215 GST_DEBUG_OBJECT (self, "add filter on %s", tmp[i]);
217 g_array_append_val (self->filter, type);
224 set_params_from_structure (GstLeaksTracer * self, GstStructure * params)
226 const gchar *filters, *name;
228 filters = gst_structure_get_string (params, "filters");
230 set_filters (self, filters);
232 name = gst_structure_get_string (params, "name");
234 gst_object_set_name (GST_OBJECT (self), name);
236 gst_structure_get_boolean (params, "check-refs", &self->check_refs);
237 gst_structure_get_boolean (params, "log-leaks-on-deinit", &self->log_leaks);
241 set_params (GstLeaksTracer * self)
244 GstStructure *params_struct = NULL;
246 g_object_get (self, "params", ¶ms, NULL);
250 tmp = g_strdup_printf ("leaks,%s", params);
251 params_struct = gst_structure_from_string (tmp, NULL);
255 set_params_from_structure (self, params_struct);
257 set_filters (self, params);
262 set_print_stack_trace (self, params_struct);
265 gst_structure_free (params_struct);
269 _expand_unhandled_filters (gchar * typename, gpointer unused_value,
270 GstLeaksTracer * self)
274 type = g_type_from_name (typename);
279 g_atomic_int_dec_and_test (&self->unhandled_filter_count);
280 g_array_append_val (self->filter, type);
286 should_handle_object_type (GstLeaksTracer * self, GType object_type)
291 /* No filtering, handle all types */
294 if (object_type == 0)
298 if (g_atomic_int_get (&self->unhandled_filter_count)) {
299 GST_OBJECT_LOCK (self);
300 g_hash_table_foreach_remove (self->unhandled_filter,
301 (GHRFunc) _expand_unhandled_filters, self);
302 GST_OBJECT_UNLOCK (self);
305 len = self->filter->len;
306 for (i = 0; i < len; i++) {
307 GType type = g_array_index (self->filter, GType, i);
309 if (g_type_is_a (object_type, type))
316 /* The object may be destroyed when we log it using the checkpointing system so
317 * we have to save its type name */
321 const gchar *type_name;
324 static inline gboolean
325 object_is_gst_mini_object (gpointer obj)
327 return (G_TYPE_IS_DERIVED (GST_MINI_OBJECT_TYPE (obj)) &&
328 G_TYPE_FUNDAMENTAL (GST_MINI_OBJECT_TYPE (obj)) == G_TYPE_BOXED);
332 object_log_new (gpointer obj, ObjectKind kind)
334 ObjectLog *o = g_new (ObjectLog, 1);
340 o->type_name = G_OBJECT_TYPE_NAME (obj);
343 o->type_name = g_type_name (GST_MINI_OBJECT_TYPE (obj));
346 g_assert_not_reached ();
354 object_log_free (ObjectLog * obj)
360 handle_object_destroyed (GstLeaksTracer * self, gpointer object,
363 GST_OBJECT_LOCK (self);
366 ("object %p destroyed while the leaks tracer was finalizing. Some threads are still running?",
371 g_hash_table_remove (self->objects, object);
373 g_hash_table_add (self->removed, object_log_new (object, kind));
375 GST_OBJECT_UNLOCK (self);
379 object_weak_cb (gpointer data, GObject * object)
381 GstLeaksTracer *self = data;
383 handle_object_destroyed (self, object, GOBJECT);
387 mini_object_weak_cb (gpointer data, GstMiniObject * object)
389 GstLeaksTracer *self = data;
391 handle_object_destroyed (self, object, MINI_OBJECT);
395 handle_object_created (GstLeaksTracer * self, gpointer object, GType type,
398 ObjectKind kind = gobject ? GOBJECT : MINI_OBJECT; // FIXME: change arg to pass directly
399 ObjectRefingInfos *infos;
401 if (!should_handle_object_type (self, type))
404 infos = g_malloc0 (sizeof (ObjectRefingInfos));
406 g_object_weak_ref ((GObject *) object, object_weak_cb, self);
408 gst_mini_object_weak_ref (GST_MINI_OBJECT_CAST (object),
409 mini_object_weak_cb, self);
411 GST_OBJECT_LOCK (self);
412 if ((gint) self->trace_flags != -1)
413 infos->creation_trace = gst_debug_get_stack_trace (self->trace_flags);
415 g_hash_table_insert (self->objects, object, infos);
418 g_hash_table_add (self->added, object_log_new (object, kind));
419 GST_OBJECT_UNLOCK (self);
423 mini_object_created_cb (GstTracer * tracer, GstClockTime ts,
424 GstMiniObject * object)
426 GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer);
428 handle_object_created (self, object, GST_MINI_OBJECT_TYPE (object), FALSE);
432 object_created_cb (GstTracer * tracer, GstClockTime ts, GstObject * object)
434 GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer);
435 GType object_type = G_OBJECT_TYPE (object);
437 /* Can't track tracers as they may be disposed after the leak tracer itself */
438 if (g_type_is_a (object_type, GST_TYPE_TRACER))
441 handle_object_created (self, object, object_type, TRUE);
445 handle_object_reffed (GstLeaksTracer * self, gpointer object, GType type,
446 gint new_refcount, gboolean reffed, GstClockTime ts)
448 ObjectRefingInfos *infos;
449 ObjectRefingInfo *refinfo;
451 if (!self->check_refs)
454 if (!should_handle_object_type (self, type))
457 GST_OBJECT_LOCK (self);
458 infos = g_hash_table_lookup (self->objects, object);
462 refinfo = g_malloc0 (sizeof (ObjectRefingInfo));
464 refinfo->new_refcount = new_refcount;
465 refinfo->reffed = reffed;
466 if ((gint) self->trace_flags != -1)
467 refinfo->trace = gst_debug_get_stack_trace (self->trace_flags);
469 infos->refing_infos = g_list_prepend (infos->refing_infos, refinfo);
472 GST_OBJECT_UNLOCK (self);
476 object_reffed_cb (GstTracer * tracer, GstClockTime ts, GstObject * object,
479 GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer);
481 handle_object_reffed (self, object, G_OBJECT_TYPE (object), new_refcount,
486 object_unreffed_cb (GstTracer * tracer, GstClockTime ts, GstObject * object,
489 GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer);
491 handle_object_reffed (self, object, G_OBJECT_TYPE (object), new_refcount,
496 mini_object_reffed_cb (GstTracer * tracer, GstClockTime ts,
497 GstMiniObject * object, gint new_refcount)
499 GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer);
501 handle_object_reffed (self, object, GST_MINI_OBJECT_TYPE (object),
502 new_refcount, TRUE, ts);
506 mini_object_unreffed_cb (GstTracer * tracer, GstClockTime ts,
507 GstMiniObject * object, gint new_refcount)
509 GstLeaksTracer *self = GST_LEAKS_TRACER_CAST (tracer);
511 handle_object_reffed (self, object, GST_MINI_OBJECT_TYPE (object),
512 new_refcount, FALSE, ts);
516 gst_leaks_tracer_init (GstLeaksTracer * self)
518 self->log_leaks = DEFAULT_LOG_LEAKS;
519 self->objects = g_hash_table_new_full (NULL, NULL, NULL,
520 (GDestroyNotify) object_refing_infos_free);
522 if (g_getenv ("GST_LEAKS_TRACER_SIG")) {
524 gst_leaks_tracer_setup_signals (self);
526 g_warning ("System doesn't support POSIX signals");
527 #endif /* G_OS_UNIX */
531 g_queue_push_tail (&instances, self);
532 G_UNLOCK (instances);
536 gst_leaks_tracer_constructed (GObject * object)
538 GstLeaksTracer *self = GST_LEAKS_TRACER (object);
539 GstTracer *tracer = GST_TRACER (object);
543 gst_tracing_register_hook (tracer, "mini-object-created",
544 G_CALLBACK (mini_object_created_cb));
545 gst_tracing_register_hook (tracer, "object-created",
546 G_CALLBACK (object_created_cb));
548 if (self->check_refs) {
549 gst_tracing_register_hook (tracer, "object-reffed",
550 G_CALLBACK (object_reffed_cb));
551 gst_tracing_register_hook (tracer, "mini-object-reffed",
552 G_CALLBACK (mini_object_reffed_cb));
553 gst_tracing_register_hook (tracer, "mini-object-unreffed",
554 G_CALLBACK (mini_object_unreffed_cb));
555 gst_tracing_register_hook (tracer, "object-unreffed",
556 G_CALLBACK (object_unreffed_cb));
559 /* We rely on weak pointers rather than (mini-)object-destroyed hooks so we
560 * are notified of objects being destroyed even during the shuting down of
561 * the tracing system. */
563 ((GObjectClass *) gst_leaks_tracer_parent_class)->constructed (object);
572 ObjectRefingInfos *infos;
575 /* The content of the returned Leak struct is valid until the self->objects
576 * hash table has been modified. */
578 leak_new (gpointer obj, GType type, guint ref_count, ObjectRefingInfos * infos)
580 Leak *leak = g_new (Leak, 1);
584 leak->ref_count = ref_count;
585 leak->desc = gst_info_strdup_printf ("%" GST_PTR_FORMAT, obj);
592 leak_free (Leak * leak)
599 sort_leaks (gconstpointer _a, gconstpointer _b)
601 const Leak *a = _a, *b = _b;
603 return g_strcmp0 (g_type_name (a->type), g_type_name (b->type));
607 create_leaks_list (GstLeaksTracer * self)
613 g_hash_table_iter_init (&iter, self->objects);
614 while (g_hash_table_iter_next (&iter, &obj, &infos)) {
618 if (object_is_gst_mini_object (obj)) {
619 if (GST_MINI_OBJECT_FLAG_IS_SET (obj, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED))
622 type = GST_MINI_OBJECT_TYPE (obj);
623 ref_count = ((GstMiniObject *) obj)->refcount;
625 if (GST_OBJECT_FLAG_IS_SET (obj, GST_OBJECT_FLAG_MAY_BE_LEAKED))
628 type = G_OBJECT_TYPE (obj);
629 ref_count = ((GObject *) obj)->ref_count;
632 l = g_list_prepend (l, leak_new (obj, type, ref_count, infos));
635 /* Sort leaks by type name so they are grouped together making the output
637 l = g_list_sort (l, sort_leaks);
639 /* Reverse list to sort objects by creation time; this is needed because we
640 * prepended objects into this list earlier, and because g_list_sort() above
641 * is stable so the creation order is preserved when sorting by type name. */
642 return g_list_reverse (l);
646 process_leak (Leak * leak, GValue * ret_leaks)
648 GstStructure *r, *s = NULL;
650 GValue refings = G_VALUE_INIT;
653 /* log to the debug log */
654 gst_tracer_record_log (tr_alive, g_type_name (leak->type), leak->obj,
655 leak->desc, leak->ref_count,
656 leak->infos->creation_trace ? leak->infos->creation_trace : "");
658 GValue s_value = G_VALUE_INIT;
659 GValue obj_value = G_VALUE_INIT;
660 /* for leaked objects, we take ownership of the object instead of
661 * reffing ("collecting") it to avoid deadlocks */
662 g_value_init (&obj_value, leak->type);
663 if (object_is_gst_mini_object (leak->obj))
664 g_value_take_boxed (&obj_value, leak->obj);
666 g_value_take_object (&obj_value, leak->obj);
667 s = gst_structure_new_empty ("object-alive");
668 gst_structure_take_value (s, "object", &obj_value);
669 gst_structure_set (s, "ref-count", G_TYPE_UINT, leak->ref_count,
670 "trace", G_TYPE_STRING, leak->infos->creation_trace, NULL);
671 /* avoid copy of structure */
672 g_value_init (&s_value, GST_TYPE_STRUCTURE);
673 g_value_take_boxed (&s_value, s);
674 gst_value_list_append_and_take_value (ret_leaks, &s_value);
677 /* store refinfo if available */
678 if (leak->infos->refing_infos)
679 g_value_init (&refings, GST_TYPE_LIST);
681 /* iterate the list from last to first to correct the order */
682 for (ref = g_list_last (leak->infos->refing_infos); ref; ref = ref->prev) {
683 ObjectRefingInfo *refinfo = (ObjectRefingInfo *) ref->data;
686 /* log to the debug log */
687 gst_tracer_record_log (tr_refings, refinfo->ts, g_type_name (leak->type),
688 leak->obj, refinfo->reffed ? "reffed" : "unreffed",
689 refinfo->new_refcount, refinfo->trace ? refinfo->trace : "");
691 GValue r_value = G_VALUE_INIT;
692 r = gst_structure_new_empty ("object-refings");
693 gst_structure_set (r, "ts", GST_TYPE_CLOCK_TIME, refinfo->ts,
694 "desc", G_TYPE_STRING, refinfo->reffed ? "reffed" : "unreffed",
695 "ref-count", G_TYPE_UINT, refinfo->new_refcount,
696 "trace", G_TYPE_STRING, refinfo->trace, NULL);
697 /* avoid copy of structure */
698 g_value_init (&r_value, GST_TYPE_STRUCTURE);
699 g_value_take_boxed (&r_value, r);
700 gst_value_list_append_and_take_value (&refings, &r_value);
704 if (ret_leaks && leak->infos->refing_infos)
705 gst_structure_take_value (s, "ref-infos", &refings);
708 /* Return TRUE if at least one leaked object was found */
710 process_leaks (GstLeaksTracer * self, GValue * ret_leaks)
713 gboolean ret = FALSE;
717 GST_TRACE_OBJECT (self, "start listing currently alive objects");
719 leaks = create_leaks_list (self);
722 GST_TRACE_OBJECT (self, "No objects alive currently");
726 for (l = leaks; l; l = l->next) {
727 process_leak (l->data, ret_leaks);
731 g_list_free_full (leaks, (GDestroyNotify) leak_free);
737 GST_TRACE_OBJECT (self, "listed %u alive objects", n);
743 gst_leaks_tracer_finalize (GObject * object)
745 GstLeaksTracer *self = GST_LEAKS_TRACER (object);
746 gboolean leaks = FALSE;
750 GST_DEBUG_OBJECT (self, "destroying tracer, checking for leaks");
754 /* Tracers are destroyed as part of gst_deinit() so now is a good time to
755 * report all the objects which are still alive. */
757 leaks = process_leaks (self, NULL);
759 /* Remove weak references */
760 g_hash_table_iter_init (&iter, self->objects);
761 while (g_hash_table_iter_next (&iter, &obj, NULL)) {
762 if (object_is_gst_mini_object (obj))
763 gst_mini_object_weak_unref (GST_MINI_OBJECT_CAST (obj),
764 mini_object_weak_cb, self);
766 g_object_weak_unref (obj, object_weak_cb, self);
769 g_clear_pointer (&self->objects, g_hash_table_unref);
771 g_array_free (self->filter, TRUE);
772 g_clear_pointer (&self->added, g_hash_table_unref);
773 g_clear_pointer (&self->removed, g_hash_table_unref);
774 g_clear_pointer (&self->unhandled_filter, g_hash_table_unref);
777 g_queue_remove (&instances, self);
778 G_UNLOCK (instances);
781 gst_leaks_tracer_cleanup_signals (self);
785 g_warning ("Leaks detected and logged under GST_DEBUG=GST_TRACER:7");
787 ((GObjectClass *) gst_leaks_tracer_parent_class)->finalize (object);
790 #define RECORD_FIELD_TYPE_TS \
791 "ts", GST_TYPE_STRUCTURE, gst_structure_new ("value", \
792 "type", G_TYPE_GTYPE, GST_TYPE_CLOCK_TIME, \
794 #define RECORD_FIELD_TYPE_NAME \
795 "type-name", GST_TYPE_STRUCTURE, gst_structure_new ("value", \
796 "type", G_TYPE_GTYPE, G_TYPE_STRING, \
798 #define RECORD_FIELD_ADDRESS \
799 "address", GST_TYPE_STRUCTURE, gst_structure_new ("value", \
800 "type", G_TYPE_GTYPE, G_TYPE_POINTER, \
802 #define RECORD_FIELD_DESC \
803 "description", GST_TYPE_STRUCTURE, gst_structure_new ("value", \
804 "type", G_TYPE_GTYPE, G_TYPE_STRING, \
806 #define RECORD_FIELD_REF_COUNT \
807 "ref-count", GST_TYPE_STRUCTURE, gst_structure_new ("value", \
808 "type", G_TYPE_GTYPE, G_TYPE_UINT, \
810 #define RECORD_FIELD_TRACE \
811 "trace", GST_TYPE_STRUCTURE, gst_structure_new ("value", \
812 "type", G_TYPE_GTYPE, G_TYPE_STRING, \
817 sig_usr1_handler (gpointer data)
820 g_queue_foreach (&instances, (GFunc) gst_leaks_tracer_log_live_objects, NULL);
821 G_UNLOCK (instances);
823 return G_SOURCE_CONTINUE;
827 sig_usr2_handler_foreach (gpointer data, gpointer user_data)
829 GstLeaksTracer *tracer = data;
831 if (!tracer->added) {
832 GST_TRACE_OBJECT (tracer, "First checkpoint, start tracking objects");
833 gst_leaks_tracer_activity_start_tracking (tracer);
835 gst_leaks_tracer_activity_log_checkpoint (tracer);
840 sig_usr2_handler (gpointer data)
843 g_queue_foreach (&instances, sig_usr2_handler_foreach, NULL);
844 G_UNLOCK (instances);
846 return G_SOURCE_CONTINUE;
849 struct signal_thread_data
856 static GMainLoop *signal_loop; /* NULL */
857 static GThread *signal_thread; /* NULL */
858 static gint signal_thread_users; /* 0 */
859 G_LOCK_DEFINE_STATIC (signal_thread);
862 unlock_mutex (gpointer data)
864 g_mutex_unlock ((GMutex *) data);
866 return G_SOURCE_REMOVE;
870 gst_leaks_tracer_signal_thread (struct signal_thread_data *data)
872 static GMainContext *signal_ctx;
873 GSource *source1, *source2, *unlock_source;
875 signal_ctx = g_main_context_new ();
876 signal_loop = g_main_loop_new (signal_ctx, FALSE);
878 unlock_source = g_idle_source_new ();
879 g_source_set_callback (unlock_source, unlock_mutex, &data->lock, NULL);
880 g_source_attach (unlock_source, signal_ctx);
882 source1 = g_unix_signal_source_new (SIGUSR1);
883 g_source_set_callback (source1, sig_usr1_handler, NULL, NULL);
884 g_source_attach (source1, signal_ctx);
886 source2 = g_unix_signal_source_new (SIGUSR2);
887 g_source_set_callback (source2, sig_usr2_handler, NULL, NULL);
888 g_source_attach (source2, signal_ctx);
890 g_mutex_lock (&data->lock);
892 g_cond_broadcast (&data->cond);
894 g_main_loop_run (signal_loop);
896 g_source_destroy (source1);
897 g_source_destroy (source2);
898 g_main_loop_unref (signal_loop);
900 g_main_context_unref (signal_ctx);
907 atfork_prepare (void)
909 G_LOCK (signal_thread);
915 G_UNLOCK (signal_thread);
921 signal_thread_users = 0;
922 signal_thread = NULL;
923 G_UNLOCK (signal_thread);
927 gst_leaks_tracer_setup_signals (GstLeaksTracer * leaks)
929 struct signal_thread_data data;
931 G_LOCK (signal_thread);
932 signal_thread_users++;
933 if (signal_thread_users == 1) {
936 GST_INFO_OBJECT (leaks, "Setting up signal handling");
938 /* If application is forked, the child process won't inherit the extra thread.
939 * As a result we need to reset the child process thread state accordingly.
940 * This is typically needed when running tests as libcheck fork the tests.
942 * See https://pubs.opengroup.org/onlinepubs/007904975/functions/pthread_atfork.html
944 res = pthread_atfork (atfork_prepare, atfork_parent, atfork_child);
946 GST_WARNING_OBJECT (leaks, "pthread_atfork() failed (%d)", res);
950 g_mutex_init (&data.lock);
951 g_cond_init (&data.cond);
952 signal_thread = g_thread_new ("gstleak-signal",
953 (GThreadFunc) gst_leaks_tracer_signal_thread, &data);
955 g_mutex_lock (&data.lock);
957 g_cond_wait (&data.cond, &data.lock);
958 g_mutex_unlock (&data.lock);
960 g_mutex_clear (&data.lock);
961 g_cond_clear (&data.cond);
963 G_UNLOCK (signal_thread);
967 gst_leaks_tracer_cleanup_signals (GstLeaksTracer * leaks)
969 G_LOCK (signal_thread);
970 signal_thread_users--;
971 if (signal_thread_users == 0) {
972 GST_INFO_OBJECT (leaks, "Cleaning up signal handling");
973 g_main_loop_quit (signal_loop);
974 g_thread_join (signal_thread);
975 signal_thread = NULL;
976 gst_object_unref (tr_added);
978 gst_object_unref (tr_removed);
981 G_UNLOCK (signal_thread);
985 #define setup_signals() g_warning ("System doesn't support POSIX signals");
986 #endif /* G_OS_UNIX */
988 static GstStructure *
989 gst_leaks_tracer_get_live_objects (GstLeaksTracer * self)
992 GValue live_objects = G_VALUE_INIT;
994 g_value_init (&live_objects, GST_TYPE_LIST);
996 GST_OBJECT_LOCK (self);
997 process_leaks (self, &live_objects);
998 GST_OBJECT_UNLOCK (self);
1000 info = gst_structure_new_empty ("live-objects-info");
1001 gst_structure_take_value (info, "live-objects-list", &live_objects);
1007 gst_leaks_tracer_log_live_objects (GstLeaksTracer * self)
1009 GST_OBJECT_LOCK (self);
1010 process_leaks (self, NULL);
1011 GST_OBJECT_UNLOCK (self);
1015 gst_leaks_tracer_activity_start_tracking (GstLeaksTracer * self)
1017 GST_OBJECT_LOCK (self);
1019 GST_ERROR_OBJECT (self, "tracking is already in progress");
1023 self->added = g_hash_table_new_full (NULL, NULL,
1024 (GDestroyNotify) object_log_free, NULL);
1025 self->removed = g_hash_table_new_full (NULL, NULL,
1026 (GDestroyNotify) object_log_free, NULL);
1027 GST_OBJECT_UNLOCK (self);
1030 /* When @ret is %NULL, this simply logs the activities */
1032 process_checkpoint (GstTracerRecord * record, const gchar * record_type,
1033 GHashTable * hash, GValue * ret)
1035 GHashTableIter iter;
1038 g_hash_table_iter_init (&iter, hash);
1039 while (g_hash_table_iter_next (&iter, &o, NULL)) {
1043 /* log to the debug log */
1044 gst_tracer_record_log (record, obj->type_name, obj->object);
1046 GValue s_value = G_VALUE_INIT;
1047 GValue addr_value = G_VALUE_INIT;
1048 gchar *address = g_strdup_printf ("%p", obj->object);
1049 GstStructure *s = gst_structure_new_empty (record_type);
1050 /* copy type_name because it's owned by @obj */
1051 gst_structure_set (s, "type-name", G_TYPE_STRING, obj->type_name, NULL);
1052 /* avoid copy of @address */
1053 g_value_init (&addr_value, G_TYPE_STRING);
1054 g_value_take_string (&addr_value, address);
1055 gst_structure_take_value (s, "address", &addr_value);
1056 /* avoid copy of the structure */
1057 g_value_init (&s_value, GST_TYPE_STRUCTURE);
1058 g_value_take_boxed (&s_value, s);
1059 gst_value_list_append_and_take_value (ret, &s_value);
1064 static GstStructure *
1065 gst_leaks_tracer_activity_get_checkpoint (GstLeaksTracer * self)
1067 GValue added = G_VALUE_INIT;
1068 GValue removed = G_VALUE_INIT;
1069 GstStructure *s = gst_structure_new_empty ("activity-checkpoint");
1071 g_value_init (&added, GST_TYPE_LIST);
1072 g_value_init (&removed, GST_TYPE_LIST);
1074 GST_OBJECT_LOCK (self);
1075 process_checkpoint (tr_added, "objects-created", self->added, &added);
1076 process_checkpoint (tr_removed, "objects-removed", self->removed, &removed);
1078 g_hash_table_remove_all (self->added);
1079 g_hash_table_remove_all (self->removed);
1080 GST_OBJECT_UNLOCK (self);
1082 gst_structure_take_value (s, "objects-created-list", &added);
1083 gst_structure_take_value (s, "objects-removed-list", &removed);
1089 gst_leaks_tracer_activity_log_checkpoint (GstLeaksTracer * self)
1091 GST_OBJECT_LOCK (self);
1092 GST_TRACE_OBJECT (self, "listing objects created since last checkpoint");
1093 process_checkpoint (tr_added, NULL, self->added, NULL);
1094 GST_TRACE_OBJECT (self, "listing objects removed since last checkpoint");
1095 process_checkpoint (tr_removed, NULL, self->removed, NULL);
1096 g_hash_table_remove_all (self->added);
1097 g_hash_table_remove_all (self->removed);
1098 GST_OBJECT_UNLOCK (self);
1102 gst_leaks_tracer_activity_stop_tracking (GstLeaksTracer * self)
1104 GST_OBJECT_LOCK (self);
1105 g_clear_pointer (&self->added, g_hash_table_destroy);
1106 g_clear_pointer (&self->removed, g_hash_table_destroy);
1107 GST_OBJECT_UNLOCK (self);
1111 gst_leaks_tracer_class_init (GstLeaksTracerClass * klass)
1113 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1115 gobject_class->constructed = gst_leaks_tracer_constructed;
1116 gobject_class->finalize = gst_leaks_tracer_finalize;
1118 tr_alive = gst_tracer_record_new ("object-alive.class",
1119 RECORD_FIELD_TYPE_NAME, RECORD_FIELD_ADDRESS, RECORD_FIELD_DESC,
1120 RECORD_FIELD_REF_COUNT, RECORD_FIELD_TRACE, NULL);
1121 GST_OBJECT_FLAG_SET (tr_alive, GST_OBJECT_FLAG_MAY_BE_LEAKED);
1123 tr_refings = gst_tracer_record_new ("object-refings.class",
1124 RECORD_FIELD_TYPE_TS, RECORD_FIELD_TYPE_NAME, RECORD_FIELD_ADDRESS,
1125 RECORD_FIELD_DESC, RECORD_FIELD_REF_COUNT, RECORD_FIELD_TRACE, NULL);
1126 GST_OBJECT_FLAG_SET (tr_refings, GST_OBJECT_FLAG_MAY_BE_LEAKED);
1128 tr_added = gst_tracer_record_new ("object-added.class",
1129 RECORD_FIELD_TYPE_NAME, RECORD_FIELD_ADDRESS, NULL);
1130 GST_OBJECT_FLAG_SET (tr_added, GST_OBJECT_FLAG_MAY_BE_LEAKED);
1132 tr_removed = gst_tracer_record_new ("object-removed.class",
1133 RECORD_FIELD_TYPE_NAME, RECORD_FIELD_ADDRESS, NULL);
1134 GST_OBJECT_FLAG_SET (tr_removed, GST_OBJECT_FLAG_MAY_BE_LEAKED);
1137 * GstLeaksTracer::get-live-objects:
1138 * @leakstracer: the leaks tracer object to emit this signal on
1140 * Returns a #GstStructure containing a #GValue of type #GST_TYPE_LIST which
1141 * is a list of #GstStructure objects containing information about the
1142 * objects that are still alive, which is useful for detecting leaks. Each
1143 * #GstStructure object has the following fields:
1145 * `object`: containing the leaked object itself
1146 * `ref-count`: the current reference count of the object
1147 * `trace`: the allocation stack trace for the object, only available if the
1148 * `stack-traces-flags` param is set to `full`
1149 * `ref-infos`: a #GValue of type #GST_TYPE_LIST which is a list of
1150 * #GstStructure objects containing information about the
1151 * ref/unref history of the object; only available if the
1152 * `check-refs` param is set to `true`
1154 * Each `ref-infos` #GstStructure has the following fields:
1156 * `ts`: the timestamp for the ref/unref
1157 * `desc`: either "reffed" or "unreffed"
1158 * `ref-count`: the reference count after the ref/unref
1159 * `trace`: the stack trace for the ref/unref
1161 * **Notes on usage**: This action signal is supposed to be called at the
1162 * end of an application before it exits, or at the end of an execution run
1163 * when all streaming has stopped and all pipelines have been freed. It is
1164 * assumed that at this point any GStreamer object that is still alive is
1165 * leaked, and there are no legitimate owners any more. As such, ownership
1166 * of the leaked objects is transferred to you then, assuming no other code
1167 * still retrains references to them.
1169 * If that's not the case, and there is code somewhere still holding
1170 * a reference, then the application behaviour is undefined after this
1171 * function is called, since we will have stolen some other code's valid
1172 * reference and when the returned #GstStructure is freed that code will be
1173 * holding a reference to an invalid object, which will most likely crash
1176 * If you don't want to just check for leaks at the end of a program, the
1177 * activity checkpoint action signals might be a better fit for your use
1180 * Returns: (transfer full): a newly-allocated #GstStructure
1184 gst_leaks_tracer_signals[SIGNAL_GET_LIVE_OBJECTS] =
1185 g_signal_new ("get-live-objects", G_TYPE_FROM_CLASS (klass),
1186 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstLeaksTracerClass,
1187 get_live_objects), NULL, NULL, NULL, GST_TYPE_STRUCTURE, 0,
1191 * GstLeaksTracer::log-live-objects:
1192 * @leakstracer: the leaks tracer object to emit this signal on
1194 * Logs all objects that are still alive to the debug log in the same format
1195 * as the logging during gst_deinit().
1199 gst_leaks_tracer_signals[SIGNAL_LOG_LIVE_OBJECTS] =
1200 g_signal_new ("log-live-objects", G_TYPE_FROM_CLASS (klass),
1201 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstLeaksTracerClass,
1202 log_live_objects), NULL, NULL, NULL, G_TYPE_NONE, 0, G_TYPE_NONE);
1205 * GstLeaksTracer:::activity-start-tracking
1206 * @leakstracer: the leaks tracer object to emit this signal on
1208 * Start storing information about all objects that are being created or
1209 * removed. Call `stop-tracking` to stop.
1211 * NOTE: You do not need to call this to use the *-live-objects action
1212 * signals listed above.
1216 gst_leaks_tracer_signals[SIGNAL_ACTIVITY_START_TRACKING] =
1217 g_signal_new ("activity-start-tracking", G_TYPE_FROM_CLASS (klass),
1218 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstLeaksTracerClass,
1219 activity_start_tracking), NULL, NULL, NULL, G_TYPE_NONE, 0,
1223 * GstLeaksTracer:::activity-get-checkpoint
1224 * @leakstracer: the leaks tracer object to emit this signal on
1226 * You must call this after calling `activity-start-tracking` and you should
1227 * call `activity-stop-tracking` when you are done tracking.
1229 * Returns a #GstStructure with two fields: `"objects-created-list"` and
1230 * `"objects-removed-list"`, each of which is a #GValue of type #GST_TYPE_LIST
1231 * containing all objects that were created/removed since the last
1232 * checkpoint, or since tracking started if this is the first checkpoint.
1234 * The list elements are in order of creation/removal. Each list element is
1235 * a #GValue containing a #GstStructure with the following fields:
1237 * `type-name`: a string representing the type of the object
1238 * `address`: a string representing the address of the object; the object
1239 * itself cannot be returned since we don't own it and it may be
1240 * freed at any moment, or it may already have been freed
1242 * Returns: (transfer full): a newly-allocated #GstStructure
1246 gst_leaks_tracer_signals[SIGNAL_ACTIVITY_GET_CHECKPOINT] =
1247 g_signal_new ("activity-get-checkpoint", G_TYPE_FROM_CLASS (klass),
1248 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstLeaksTracerClass,
1249 activity_get_checkpoint), NULL, NULL, NULL, GST_TYPE_STRUCTURE, 0,
1253 * GstLeaksTracer:::activity-log-checkpoint
1254 * @leakstracer: the leaks tracer object to emit this signal on
1256 * You must call this after calling `activity-start-tracking` and you should
1257 * call `activity-stop-tracking` when you are done tracking.
1259 * List all objects that were created or removed since the last checkpoint,
1260 * or since tracking started if this is the first checkpoint.
1262 * This action signal is equivalent to `activity-get-checkpoint` except that
1263 * the checkpoint data will be printed to the debug log under `GST_TRACER:7`.
1267 gst_leaks_tracer_signals[SIGNAL_ACTIVITY_LOG_CHECKPOINT] =
1268 g_signal_new ("activity-log-checkpoint", G_TYPE_FROM_CLASS (klass),
1269 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstLeaksTracerClass,
1270 activity_log_checkpoint), NULL, NULL, NULL, G_TYPE_NONE, 0,
1274 * GstLeaksTracer:::activity-stop-tracking
1275 * @leakstracer: the leaks tracer object to emit this signal on
1277 * Stop tracking all objects that are being created or removed, undoes the
1278 * effects of the `start-tracking` signal.
1282 gst_leaks_tracer_signals[SIGNAL_ACTIVITY_STOP_TRACKING] =
1283 g_signal_new ("activity-stop-tracking", G_TYPE_FROM_CLASS (klass),
1284 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstLeaksTracerClass,
1285 activity_stop_tracking), NULL, NULL, NULL, G_TYPE_NONE, 0,
1288 klass->get_live_objects = gst_leaks_tracer_get_live_objects;
1289 klass->log_live_objects = gst_leaks_tracer_log_live_objects;
1290 klass->activity_start_tracking = gst_leaks_tracer_activity_start_tracking;
1291 klass->activity_get_checkpoint = gst_leaks_tracer_activity_get_checkpoint;
1292 klass->activity_log_checkpoint = gst_leaks_tracer_activity_log_checkpoint;
1293 klass->activity_stop_tracking = gst_leaks_tracer_activity_stop_tracking;