[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