[vlc-devel] commit: The totally dumb reference checker ( Rémi Denis-Courmont )
git version control
git at videolan.org
Wed May 28 21:30:54 CEST 2008
vlc | branch: master | Rémi Denis-Courmont <rem at videolan.org> | Wed May 28 22:32:25 2008 +0300| [523ef308d2bff928d1246e968003a3ff429890db]
The totally dumb reference checker
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=523ef308d2bff928d1246e968003a3ff429890db
---
src/libvlc.h | 5 ++++
src/misc/objects.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/misc/variables.c | 8 +++++++
3 files changed, 68 insertions(+), 0 deletions(-)
diff --git a/src/libvlc.h b/src/libvlc.h
index 9597df6..9160eb7 100644
--- a/src/libvlc.h
+++ b/src/libvlc.h
@@ -46,6 +46,11 @@ void system_End ( libvlc_int_t * );
int vlc_threads_init( void );
void vlc_threads_end( void );
vlc_object_t *vlc_threadobj (void);
+#ifndef NDEBUG
+void vlc_refcheck (vlc_object_t *obj);
+#else
+# define vlc_refcheck( obj ) (void)0
+#endif
/*
* CPU capabilities
diff --git a/src/misc/objects.c b/src/misc/objects.c
index 1b84e31..629036e 100644
--- a/src/misc/objects.c
+++ b/src/misc/objects.c
@@ -1469,3 +1469,58 @@ static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
ListChildren( p_list, p_tmp, i_type );
}
}
+
+#ifndef NDEBUG
+void vlc_refcheck (vlc_object_t *obj)
+{
+ static unsigned errors = 0;
+ vlc_object_t *caller = vlc_threadobj ();
+ vlc_object_internals_t *priv = vlc_internals (obj);
+ int refs;
+
+ if (errors > 100)
+ return;
+
+ if (!caller)
+ return; /* main thread, not sure how to handle it */
+
+ /* An object can always access itself without reference! */
+ if (caller == obj)
+ return;
+
+ /* The calling thread is younger than the object.
+ * Access could be valid, we would need more accounting. */
+ if (caller->i_object_id > obj->i_object_id)
+ return;
+
+ vlc_spin_lock (&priv->ref_spin);
+ refs = priv->i_refcount;
+ vlc_spin_unlock (&priv->ref_spin);
+
+ /* Object has more than one reference.
+ * The current thread could be holding a valid reference. */
+ if (refs > 1)
+ return;
+
+ /* The parent of an object normally holds the unique reference.
+ * As not all objects are threads, it could also be an ancestor. */
+ vlc_mutex_lock (&structure_lock);
+ for (vlc_object_t *cur = obj; cur != NULL; cur = cur->p_parent)
+ if (cur == caller)
+ {
+ vlc_mutex_unlock (&structure_lock);
+ return;
+ }
+ vlc_mutex_unlock (&structure_lock);
+
+#if 1
+ if (caller->i_object_type == VLC_OBJECT_PLAYLIST)
+ return; /* Playlist is too clever, or hopelessly broken. */
+#endif
+ msg_Err (caller, "This thread is accessing...");
+ msg_Err (obj, "...this object in a suspicious manner.");
+
+ if (++errors == 100)
+ msg_Err (caller, "Too many reference errors");
+}
+#endif
diff --git a/src/misc/variables.c b/src/misc/variables.c
index 2c2a789..6d5923a 100644
--- a/src/misc/variables.c
+++ b/src/misc/variables.c
@@ -168,6 +168,7 @@ int __var_Create( vlc_object_t *p_this, const char *psz_name, int i_type )
static vlc_list_t dummy_null_list = {0, NULL, NULL};
vlc_object_internals_t *p_priv = vlc_internals( p_this );
+ vlc_refcheck( p_this );
vlc_mutex_lock( &p_priv->var_lock );
/* FIXME: if the variable already exists, we don't duplicate it. But we
@@ -331,6 +332,7 @@ int __var_Destroy( vlc_object_t *p_this, const char *psz_name )
variable_t *p_var;
vlc_object_internals_t *p_priv = vlc_internals( p_this );
+ vlc_refcheck( p_this );
vlc_mutex_lock( &p_priv->var_lock );
i_var = GetUnused( p_this, psz_name );
@@ -407,6 +409,7 @@ int __var_Change( vlc_object_t *p_this, const char *psz_name,
vlc_value_t oldval;
vlc_object_internals_t *p_priv = vlc_internals( p_this );
+ vlc_refcheck( p_this );
vlc_mutex_lock( &p_priv->var_lock );
i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
@@ -759,6 +762,7 @@ int __var_Set( vlc_object_t *p_this, const char *psz_name, vlc_value_t val )
vlc_value_t oldval;
vlc_object_internals_t *p_priv = vlc_internals( p_this );
+ vlc_refcheck( p_this );
vlc_mutex_lock( &p_priv->var_lock );
i_var = GetUnused( p_this, psz_name );
@@ -836,6 +840,7 @@ int __var_Get( vlc_object_t *p_this, const char *psz_name, vlc_value_t *p_val )
variable_t *p_var;
vlc_object_internals_t *p_priv = vlc_internals( p_this );
+ vlc_refcheck( p_this );
vlc_mutex_lock( &p_priv->var_lock );
i_var = Lookup( p_priv->p_vars, p_priv->i_vars, psz_name );
@@ -902,6 +907,7 @@ int __var_AddCallback( vlc_object_t *p_this, const char *psz_name,
callback_entry_t entry;
vlc_object_internals_t *p_priv = vlc_internals( p_this );
+ vlc_refcheck( p_this );
entry.pf_callback = pf_callback;
entry.p_data = p_data;
@@ -939,6 +945,7 @@ int __var_DelCallback( vlc_object_t *p_this, const char *psz_name,
variable_t *p_var;
vlc_object_internals_t *p_priv = vlc_internals( p_this );
+ vlc_refcheck( p_this );
vlc_mutex_lock( &p_priv->var_lock );
i_var = GetUnused( p_this, psz_name );
@@ -1575,6 +1582,7 @@ int __var_Command( vlc_object_t *p_this, const char *psz_name,
return VLC_ENOOBJ;
}
+ vlc_refcheck( p_this );
i_type = var_Type( p_obj, psz_cmd );
if( !( i_type&VLC_VAR_ISCOMMAND ) )
{
More information about the vlc-devel
mailing list