From 523ef308d2bff928d1246e968003a3ff429890db Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Denis-Courmont?= Date: Wed, 28 May 2008 22:32:25 +0300 Subject: [PATCH] The totally dumb reference checker --- src/libvlc.h | 5 ++++ src/misc/objects.c | 55 ++++++++++++++++++++++++++++++++++++++++++++ src/misc/variables.c | 8 +++++++ 3 files changed, 68 insertions(+) diff --git a/src/libvlc.h b/src/libvlc.h index 9597df6782..9160eb7f6f 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 1b84e311cb..629036e6a0 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 2c2a789aa9..6d5923a2f7 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 ) ) { -- 2.39.2