]> git.sesse.net Git - vlc/commitdiff
The totally dumb reference checker
authorRémi Denis-Courmont <rem@videolan.org>
Wed, 28 May 2008 19:32:25 +0000 (22:32 +0300)
committerRémi Denis-Courmont <rem@videolan.org>
Wed, 28 May 2008 19:32:25 +0000 (22:32 +0300)
src/libvlc.h
src/misc/objects.c
src/misc/variables.c

index 9597df67820add1e01730e6ae6d103a789b151a6..9160eb7f6f340b2131f458305337dcd8a59ea2ee 100644 (file)
@@ -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
index 1b84e311cbfbba27fb2a6d140020e676c31b8e93..629036e6a02298bd8a8080b1ac4622dd21278612 100644 (file)
@@ -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
index 2c2a789aa9868ecd961f0a2cf2c08b7b97deaa1c..6d5923a2f78e2b7eeea40f4a6e218bd6dfa47bd6 100644 (file)
@@ -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 ) )
     {