From 718dadcb900e5a206833f25b40cfbafb4d111c35 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Fri, 13 May 2011 11:35:03 +0100 Subject: [PATCH 5/7] DBusPendingCall: optionally trace refcount changes --- dbus/dbus-pending-call.c | 80 ++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 70 insertions(+), 10 deletions(-) diff --git a/dbus/dbus-pending-call.c b/dbus/dbus-pending-call.c index 1e5f0c6..3440ba2 100644 --- a/dbus/dbus-pending-call.c +++ b/dbus/dbus-pending-call.c @@ -30,6 +30,7 @@ #include "dbus-list.h" #include "dbus-threads.h" #include "dbus-test.h" +#include "dbus-valgrind-internal.h" /** * @defgroup DBusPendingCallInternals DBusPendingCall implementation details @@ -79,6 +80,47 @@ struct DBusPendingCall unsigned int timeout_added : 1; /**< Have added the timeout */ }; +#ifdef DBUS_ENABLE_VERBOSE_MODE +static void +_dbus_pending_call_trace_ref (DBusPendingCall *pending_call, + int old_refcount, + int new_refcount, + const char *why) +{ + static int enabled = -1; + + if (enabled < 0) + { + const char *s = _dbus_getenv ("DBUS_PENDING_CALL_TRACE"); + + enabled = FALSE; + + if (s && *s) + { + if (*s == '0') + enabled = FALSE; + else if (*s == '1') + enabled = TRUE; + else + _dbus_warn ("DBUS_PENDING_CALL_TRACE should be 0 or 1 if set, " + "not '%s'", s); + } + } + + if (enabled) + { + if (RUNNING_ON_VALGRIND) + VALGRIND_PRINTF_BACKTRACE ("DBusPendingCall %p %d -> %d refs (%s)", + pending_call, old_refcount, new_refcount, why); + else + _dbus_verbose ("DBusPendingCall %p %d -> %d refs (%s)", + pending_call, old_refcount, new_refcount, why); + } +} +#else +#define _dbus_pending_call_trace_ref(p,o,n,w) do {} while (0) +#endif + static dbus_int32_t notify_user_data_slot = -1; /** @@ -138,7 +180,9 @@ _dbus_pending_call_new_unlocked (DBusConnection *connection, _dbus_connection_ref_unlocked (pending->connection); _dbus_data_slot_list_init (&pending->slot_list); - + + _dbus_pending_call_trace_ref (pending, 0, 1, "new_unlocked"); + return pending; } @@ -373,6 +417,8 @@ _dbus_pending_call_set_timeout_error_unlocked (DBusPendingCall *pending, DBusPendingCall * _dbus_pending_call_ref_unlocked (DBusPendingCall *pending) { + _dbus_pending_call_trace_ref (pending, pending->refcount.value, + pending->refcount.value + 1, "ref_unlocked"); pending->refcount.value += 1; return pending; @@ -436,6 +482,9 @@ _dbus_pending_call_unref_and_unlock (DBusPendingCall *pending) _dbus_assert (pending->refcount.value > 0); + _dbus_pending_call_trace_ref (pending, pending->refcount.value, + pending->refcount.value - 1, "unref_and_unlock"); + pending->refcount.value -= 1; last_unref = pending->refcount.value == 0; @@ -531,21 +580,29 @@ _dbus_pending_call_set_data_unlocked (DBusPendingCall *pending, DBusPendingCall * dbus_pending_call_ref (DBusPendingCall *pending) { + dbus_int32_t old_refcount; + _dbus_return_val_if_fail (pending != NULL, NULL); /* The connection lock is better than the global * lock in the atomic increment fallback */ #ifdef DBUS_HAVE_ATOMIC_INT - _dbus_atomic_inc (&pending->refcount); + old_refcount = _dbus_atomic_inc (&pending->refcount); #else CONNECTION_LOCK (pending->connection); - _dbus_assert (pending->refcount.value > 0); + old_refcount = pending->refcount.value; + _dbus_assert (old_refcount > 0); pending->refcount.value += 1; CONNECTION_UNLOCK (pending->connection); #endif - + + _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount + 1, + "ref"); + /* unused if not verbose */ + (void) old_refcount; + return pending; } @@ -558,7 +615,7 @@ dbus_pending_call_ref (DBusPendingCall *pending) void dbus_pending_call_unref (DBusPendingCall *pending) { - dbus_bool_t last_unref; + dbus_int32_t old_refcount; _dbus_return_if_fail (pending != NULL); @@ -566,16 +623,19 @@ dbus_pending_call_unref (DBusPendingCall *pending) * int fallback if we lack atomic int decrement */ #ifdef DBUS_HAVE_ATOMIC_INT - last_unref = (_dbus_atomic_dec (&pending->refcount) == 1); + old_refcount = _dbus_atomic_dec (&pending->refcount); #else CONNECTION_LOCK (pending->connection); - _dbus_assert (pending->refcount.value > 0); + old_refcount = pending->refcount.value; + _dbus_assert (old_refcount > 0); pending->refcount.value -= 1; - last_unref = pending->refcount.value == 0; CONNECTION_UNLOCK (pending->connection); #endif - - if (last_unref) + + _dbus_pending_call_trace_ref (pending, old_refcount, old_refcount - 1, + "unref"); + + if (old_refcount == 1) _dbus_pending_call_last_unref(pending); } -- 1.7.5.1