]> git.sesse.net Git - vlc/blobdiff - src/misc/objects.c
The last but not least of this serie of memleaks.
[vlc] / src / misc / objects.c
index 6791737610ceb0f71f124ff6a5de4cf35bf7ed2b..96214c14d0710889a451e8df0252bc433da03894 100644 (file)
@@ -81,7 +81,7 @@ static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
 static void vlc_object_destroy( vlc_object_t *p_this );
 static void vlc_object_detach_unlocked (vlc_object_t *p_this);
 
-#ifndef NDEBUG
+#ifdef LIBVLC_REFCHECK
 static vlc_threadvar_t held_objects;
 typedef struct held_list_t
 {
@@ -96,8 +96,8 @@ static void held_objects_destroy (void *);
  *****************************************************************************/
 static vlc_mutex_t     structure_lock;
 
-void *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
-                         int i_type, const char *psz_type )
+void *__vlc_custom_create( vlc_object_t *p_this, size_t i_size,
+                           int i_type, const char *psz_type )
 {
     vlc_object_t *p_new;
     vlc_object_internals_t *p_priv;
@@ -151,7 +151,7 @@ void *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
         p_libvlc_global->i_counter = 0;
         p_priv->next = p_priv->prev = p_new;
         vlc_mutex_init( &structure_lock );
-#ifndef NDEBUG
+#ifdef LIBVLC_REFCHECK
         /* TODO: use the destruction callback to track ref leaks */
         vlc_threadvar_create( &held_objects, held_objects_destroy );
 #endif
@@ -176,14 +176,14 @@ void *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
     p_new->p_private = NULL;
 
     /* Initialize mutexes and condvars */
-    vlc_mutex_init( &p_new->object_lock );
-    vlc_cond_init( p_new, &p_new->object_wait );
+    vlc_mutex_init( &p_priv->lock );
+    vlc_cond_init( p_new, &p_priv->wait );
     vlc_mutex_init( &p_priv->var_lock );
     vlc_spin_init( &p_priv->spin );
     p_priv->pipes[0] = p_priv->pipes[1] = -1;
 
     p_priv->next = VLC_OBJECT (p_libvlc_global);
-#if defined (NDEBUG)
+#if !defined (LIBVLC_REFCHECK)
     /* ... */
 #elif defined (LIBVLC_USE_PTHREAD)
     p_priv->creator_id = pthread_self ();
@@ -226,26 +226,10 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type )
 
     switch( i_type )
     {
-        case VLC_OBJECT_LIBVLC:
-            i_size = sizeof(libvlc_int_t);
-            psz_type = "libvlc";
-            break;
         case VLC_OBJECT_INTF:
             i_size = sizeof(intf_thread_t);
             psz_type = "interface";
             break;
-        case VLC_OBJECT_DIALOGS:
-            i_size = sizeof(intf_thread_t);
-            psz_type = "dialogs";
-            break;
-        case VLC_OBJECT_DEMUX:
-            i_size = sizeof(demux_t);
-            psz_type = "demux";
-            break;
-        case VLC_OBJECT_ACCESS:
-            i_size = sizeof(access_t);
-            psz_type = "access";
-            break;
         case VLC_OBJECT_DECODER:
             i_size = sizeof(decoder_t);
             psz_type = "decoder";
@@ -258,22 +242,10 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type )
             i_size = sizeof(encoder_t);
             psz_type = "encoder";
             break;
-        case VLC_OBJECT_FILTER:
-            i_size = sizeof(filter_t);
-            psz_type = "filter";
-            break;
-        case VLC_OBJECT_VOUT:
-            i_size = sizeof(vout_thread_t);
-            psz_type = "video output";
-            break;
         case VLC_OBJECT_AOUT:
             i_size = sizeof(aout_instance_t);
             psz_type = "audio output";
             break;
-        case VLC_OBJECT_SOUT:
-            i_size = sizeof(sout_instance_t);
-            psz_type = "stream output";
-            break;
         case VLC_OBJECT_OPENGL:
             i_size = sizeof( vout_thread_t );
             psz_type = "opengl";
@@ -282,13 +254,9 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type )
             i_size = sizeof( announce_handler_t );
             psz_type = "announce";
             break;
-        case VLC_OBJECT_INTERACTION:
-            i_size = sizeof( interaction_t );
-            psz_type = "interaction";
-            break;
         default:
-            i_size = i_type > (int)sizeof(vlc_object_t)
-                         ? i_type : (int)sizeof(vlc_object_t);
+            assert( i_type > 0 ); /* unknown type?! */
+            i_size = i_type;
             i_type = VLC_OBJECT_GENERIC;
             psz_type = "generic";
             break;
@@ -333,7 +301,12 @@ static void vlc_object_destroy( vlc_object_t *p_this )
 
     /* If we are running on a thread, wait until it ends */
     if( p_priv->b_thread )
+    {
+        msg_Warn (p_this->p_libvlc, /* do NOT use a dead object for logging! */
+                  "%s %d destroyed while thread alive (VLC might crash)",
+                  p_this->psz_object_type, p_this->i_object_id);
         vlc_thread_join( p_this );
+    }
 
     /* Call the custom "subclass" destructor */
     if( p_priv->pf_destructor )
@@ -353,9 +326,9 @@ static void vlc_object_destroy( vlc_object_t *p_this )
 
     if( p_this->p_libvlc == NULL )
     {
+#ifndef NDEBUG
         libvlc_global_data_t *p_global = (libvlc_global_data_t *)p_this;
 
-#ifndef NDEBUG
         assert( p_global == vlc_global() );
         /* Test for leaks */
         if (p_priv->next != p_this)
@@ -384,7 +357,7 @@ static void vlc_object_destroy( vlc_object_t *p_this )
 
         /* We are the global object ... no need to lock. */
         vlc_mutex_destroy( &structure_lock );
-#ifndef NDEBUG
+#ifdef LIBVLC_REFCHECK
         held_objects_destroy( vlc_threadvar_get( &held_objects ) );
         vlc_threadvar_delete( &held_objects );
 #endif
@@ -399,8 +372,8 @@ static void vlc_object_destroy( vlc_object_t *p_this )
 #endif
 
     vlc_spin_destroy( &p_priv->ref_spin );
-    vlc_mutex_destroy( &p_this->object_lock );
-    vlc_cond_destroy( &p_this->object_wait );
+    vlc_mutex_destroy( &p_priv->lock );
+    vlc_cond_destroy( &p_priv->wait );
     vlc_spin_destroy( &p_priv->spin );
     if( p_priv->pipes[1] != -1 )
         close( p_priv->pipes[1] );
@@ -415,13 +388,13 @@ static void vlc_object_destroy( vlc_object_t *p_this )
 
 void __vlc_object_lock( vlc_object_t *obj )
 {
-    vlc_mutex_lock( &obj->object_lock );
+    vlc_mutex_lock( &(vlc_internals(obj)->lock) );
 }
 
 void __vlc_object_unlock( vlc_object_t *obj )
 {
-    vlc_assert_locked( &obj->object_lock );
-    vlc_mutex_unlock( &obj->object_lock );
+    vlc_assert_locked( &(vlc_internals(obj)->lock) );
+    vlc_mutex_unlock( &(vlc_internals(obj)->lock) );
 }
 
 #ifdef WIN32
@@ -552,8 +525,9 @@ int __vlc_object_waitpipe( vlc_object_t *obj )
  */
 void __vlc_object_wait( vlc_object_t *obj )
 {
-    vlc_assert_locked( &obj->object_lock );
-    vlc_cond_wait( &obj->object_wait, &obj->object_lock );
+    vlc_object_internals_t *priv = vlc_internals( obj );
+    vlc_assert_locked( &priv->lock);
+    vlc_cond_wait( &priv->wait, &priv->lock );
 }
 
 
@@ -566,37 +540,9 @@ void __vlc_object_wait( vlc_object_t *obj )
  */
 int __vlc_object_timedwait( vlc_object_t *obj, mtime_t deadline )
 {
-    vlc_assert_locked( &obj->object_lock );
-    return vlc_cond_timedwait( &obj->object_wait, &obj->object_lock, deadline );
-}
-
-
-/**
- * Checks whether an object has been "killed".
- * The object lock must be held.
- *
- * Typical code for an object thread could be:
- *
-   vlc_object_lock (self);
-   ...initialization...
-   while (vlc_object_alive (self))
-   {
-       ...preprocessing...
-
-       vlc_object_wait (self);
-
-       ...postprocessing...
-   }
-   ...deinitialization...
-   vlc_object_unlock (self);
- *
- *
- * @return true iff the object has not been killed yet
- */
-bool __vlc_object_alive( vlc_object_t *obj )
-{
-    vlc_assert_locked( &obj->object_lock );
-    return !obj->b_die;
+    vlc_object_internals_t *priv = vlc_internals( obj );
+    vlc_assert_locked( &priv->lock);
+    return vlc_cond_timedwait( &priv->wait, &priv->lock, deadline );
 }
 
 
@@ -609,8 +555,8 @@ bool __vlc_object_alive( vlc_object_t *obj )
  */
 void __vlc_object_signal_unlocked( vlc_object_t *obj )
 {
-    vlc_assert_locked (&obj->object_lock);
-    vlc_cond_signal( &obj->object_wait );
+    vlc_assert_locked (&(vlc_internals(obj)->lock));
+    vlc_cond_signal( &(vlc_internals(obj)->wait) );
 }
 
 
@@ -620,16 +566,16 @@ void __vlc_object_signal_unlocked( vlc_object_t *obj )
  */
 void __vlc_object_kill( vlc_object_t *p_this )
 {
-    vlc_object_internals_t *internals = vlc_internals( p_this );
+    vlc_object_internals_t *priv = vlc_internals( p_this );
     int fd;
 
-    vlc_mutex_lock( &p_this->object_lock );
+    vlc_object_lock( p_this );
     p_this->b_die = true;
 
-    vlc_spin_lock (&internals->spin);
-    fd = internals->pipes[1];
-    internals->pipes[1] = -1;
-    vlc_spin_unlock (&internals->spin);
+    vlc_spin_lock (&priv->spin);
+    fd = priv->pipes[1];
+    priv->pipes[1] = -1;
+    vlc_spin_unlock (&priv->spin);
 
     if( fd != -1 )
     {
@@ -638,15 +584,8 @@ void __vlc_object_kill( vlc_object_t *p_this )
     }
 
     vlc_object_signal_unlocked( p_this );
-    vlc_mutex_unlock( &p_this->object_lock );
-
-    if (p_this->i_object_type == VLC_OBJECT_LIBVLC)
-    {
-        vlc_list_t *children = vlc_list_children (p_this);
-        for (int i = 0; i < children->i_count; i++)
-            vlc_object_kill (children->p_values[i].p_object);
-        vlc_list_release (children);
-    }
+    /* This also serves as a memory barrier toward vlc_object_alive(): */
+    vlc_object_unlock( p_this );
 }
 
 
@@ -663,6 +602,7 @@ void * vlc_object_get( int i_id )
 {
     libvlc_global_data_t *p_libvlc_global = vlc_global();
     vlc_object_t *obj = NULL;
+#ifndef NDEBUG
     vlc_object_t *caller = vlc_threadobj ();
 
     if (caller)
@@ -670,7 +610,7 @@ void * vlc_object_get( int i_id )
     else
         fprintf (stderr, "main thread uses deprecated vlc_object_get(%d)\n",
                  i_id);
-
+#endif
     vlc_mutex_lock( &structure_lock );
 
     for( obj = vlc_internals (p_libvlc_global)->next;
@@ -684,10 +624,12 @@ void * vlc_object_get( int i_id )
         }
     }
     obj = NULL;
+#ifndef NDEBUG
     if (caller)
         msg_Warn (caller, "wants non-existing object %d", i_id);
     else
         fprintf (stderr, "main thread wants non-existing object %d\n", i_id);
+#endif
 out:
     vlc_mutex_unlock( &structure_lock );
     return obj;
@@ -716,8 +658,8 @@ void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
     {
 #ifndef NDEBUG
         if (i_type == VLC_OBJECT_PLAYLIST)
-           msg_Warn (p_this, "using vlc_object_find(VLC_OBJECT_PLAYLIST) "
-                      "instead of pl_Yield()");
+           msg_Err (p_this, "using vlc_object_find(VLC_OBJECT_PLAYLIST) "
+                     "instead of pl_Yield()");
 #endif
         return vlc_object_find (p_this->p_libvlc, i_type,
                                 (i_mode & ~0x000f)|FIND_CHILD);
@@ -795,7 +737,7 @@ void __vlc_object_yield( vlc_object_t *p_this )
     /* Increment the counter */
     internals->i_refcount++;
     vlc_spin_unlock( &internals->ref_spin );
-#ifndef NDEBUG
+#ifdef LIBVLC_REFCHECK
     /* Update the list of referenced objects */
     /* Using TLS, so no need to lock */
     /* The following line may leak memory if a thread leaks objects. */
@@ -816,7 +758,7 @@ void __vlc_object_release( vlc_object_t *p_this )
     vlc_object_internals_t *internals = vlc_internals( p_this );
     bool b_should_destroy;
 
-#ifndef NDEBUG
+#ifdef LIBVLC_REFCHECK
     /* Update the list of referenced objects */
     /* Using TLS, so no need to lock */
     for (held_list_t *hlcur = vlc_threadvar_get (&held_objects),
@@ -906,15 +848,6 @@ void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
     INSERT_ELEM( priv->pp_children, priv->i_children, priv->i_children,
                  p_this );
 
-    /* Kill the object if parent is already dead.
-     * Note: We should surely lock parent here, but that would
-     * create quite a few dead lock case. Hopefully, it
-     * is perfectly safe to do it that way. We only risk
-     * receiving kill event twice. But given current API
-     * it is ok. */
-    if( p_this->p_parent->b_die )
-        vlc_object_kill( p_this );
-
     vlc_mutex_unlock( &structure_lock );
 }
 
@@ -1528,7 +1461,7 @@ static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
     }
 }
 
-#ifndef NDEBUG
+#ifdef LIBVLC_REFCHECK
 # if defined(HAVE_EXECINFO_H) && defined(HAVE_BACKTRACE)
 #  include <execinfo.h>
 # endif