]> git.sesse.net Git - vlc/blobdiff - src/input/resource.c
aout: fix mutex leak
[vlc] / src / input / resource.c
index fcf32ef2a8f7e146f9c96fed77426b10c075bf08..25f979befbbc11f182d322260f40ba27aeabacb0 100644 (file)
@@ -6,19 +6,19 @@
  *
  * Authors: Laurent Aimar < fenrir _AT_ videolan _DOT_ org >
  *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
  * (at your option) any later version.
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
 /*****************************************************************************
@@ -31,6 +31,7 @@
 #include <assert.h>
 
 #include <vlc_common.h>
+#include <vlc_atomic.h>
 #include <vlc_vout.h>
 #include <vlc_spu.h>
 #include <vlc_aout.h>
@@ -44,7 +45,7 @@
 
 struct input_resource_t
 {
-    VLC_GC_MEMBERS
+    atomic_uint    refs;
 
     vlc_object_t   *p_parent;
 
@@ -67,10 +68,11 @@ struct input_resource_t
     /* You need lock+lock_hold to write to the following variables and
      * only lock or lock_hold to read them */
 
-    int             i_vout;
     vout_thread_t   **pp_vout;
+    int             i_vout;
 
-    aout_instance_t *p_aout;
+    bool            b_aout_busy;
+    audio_output_t *p_aout;
 };
 
 /* */
@@ -322,92 +324,100 @@ exit:
     vlc_mutex_unlock( &p_resource->lock_hold );
 }
 
-/* */
-static void DestroyAout( input_resource_t *p_resource )
-{
-    if( p_resource->p_aout )
-        vlc_object_release( p_resource->p_aout );
-    p_resource->p_aout = NULL;
-}
-static aout_instance_t *RequestAout( input_resource_t *p_resource, aout_instance_t *p_aout )
+/* Audio output */
+audio_output_t *input_resource_GetAout( input_resource_t *p_resource )
 {
-    vlc_assert_locked( &p_resource->lock );
+    audio_output_t *p_aout;
 
-    if( p_aout )
+    vlc_mutex_lock( &p_resource->lock );
+    if( p_resource->b_aout_busy )
     {
-        msg_Dbg( p_resource->p_parent, "releasing aout" );
-        vlc_object_release( p_aout );
-        return NULL;
+        vlc_mutex_unlock( &p_resource->lock );
+        msg_Dbg( p_resource->p_parent, "creating extra audio output" );
+        return aout_New( p_resource->p_parent );
     }
-    else
+
+    p_aout = p_resource->p_aout;
+    if( p_aout == NULL )
     {
-        p_aout = p_resource->p_aout;
-        if( !p_aout )
-        {
-            msg_Dbg( p_resource->p_parent, "creating aout" );
-            p_aout = aout_New( p_resource->p_parent );
+        msg_Dbg( p_resource->p_parent, "creating audio output" );
+        p_aout = aout_New( p_resource->p_parent );
+    }
+    else
+        msg_Dbg( p_resource->p_parent, "reusing audio output" );
 
-            vlc_mutex_lock( &p_resource->lock_hold );
-            p_resource->p_aout = p_aout;
-            vlc_mutex_unlock( &p_resource->lock_hold );
-        }
-        else
-        {
-            msg_Dbg( p_resource->p_parent, "reusing aout" );
-        }
+    if( p_aout != NULL )
+    {
+        vlc_mutex_lock( &p_resource->lock_hold );
+        p_resource->p_aout = p_aout;
+        vlc_mutex_unlock( &p_resource->lock_hold );
 
-        if( !p_aout )
-            return NULL;
+        p_resource->b_aout_busy = true;
         vlc_object_hold( p_aout );
-        return p_aout;
     }
+    vlc_mutex_unlock( &p_resource->lock );
+    return p_aout;
 }
-static aout_instance_t *HoldAout( input_resource_t *p_resource )
-{
-    vlc_mutex_lock( &p_resource->lock_hold );
 
-    aout_instance_t *p_aout = p_resource->p_aout;
-    if( p_aout )
-        vlc_object_hold( p_aout );
+void input_resource_PutAout( input_resource_t *p_resource,
+                             audio_output_t *p_aout )
+{
+    assert( p_aout != NULL );
 
-    vlc_mutex_unlock( &p_resource->lock_hold );
+    vlc_mutex_lock( &p_resource->lock );
+    if( p_aout == p_resource->p_aout )
+    {
+        assert( p_resource->b_aout_busy );
+        p_resource->b_aout_busy = false;
+        msg_Dbg( p_resource->p_parent, "keeping audio output" );
+        vlc_object_release( p_aout );
+        p_aout = NULL;
+    }
+    else
+        msg_Dbg( p_resource->p_parent, "destroying extra audio output" );
+    vlc_mutex_unlock( &p_resource->lock );
 
-    return p_aout;
+    if( p_aout != NULL )
+        aout_Destroy( p_aout );
 }
-static void TerminateAout( input_resource_t *p_resource )
-{
-    vlc_mutex_lock( &p_resource->lock_hold );
 
-    aout_instance_t *p_aout = p_resource->p_aout;
-    p_resource->p_aout = NULL;
+audio_output_t *input_resource_HoldAout( input_resource_t *p_resource )
+{
+    audio_output_t *p_aout;
 
+    vlc_mutex_lock( &p_resource->lock_hold );
+    p_aout = p_resource->p_aout;
+    if( p_aout )
+        vlc_object_hold( p_aout );
     vlc_mutex_unlock( &p_resource->lock_hold );
 
-    if( p_aout )
-        vlc_object_release( p_aout );
+    return p_aout;
 }
 
-static void Destructor( gc_object_t *p_gc )
+static void input_resource_TerminateAout( input_resource_t *p_resource )
 {
-    input_resource_t *p_resource = vlc_priv( p_gc, input_resource_t );
+    audio_output_t *p_aout;
 
-    DestroySout( p_resource );
-    DestroyVout( p_resource );
-    DestroyAout( p_resource );
+    vlc_mutex_lock( &p_resource->lock );
+    vlc_mutex_lock( &p_resource->lock_hold );
+    p_aout = p_resource->p_aout;
+    p_resource->p_aout = NULL;
+    vlc_mutex_unlock( &p_resource->lock_hold );
+    p_resource->b_aout_busy = false;
+    vlc_mutex_unlock( &p_resource->lock );
 
-    vlc_mutex_destroy( &p_resource->lock_hold );
-    vlc_mutex_destroy( &p_resource->lock );
-    free( p_resource );
+    if( p_aout != NULL )
+        aout_Destroy( p_aout );
 }
 
-/* */
+/* Common */
 input_resource_t *input_resource_New( vlc_object_t *p_parent )
 {
     input_resource_t *p_resource = calloc( 1, sizeof(*p_resource) );
     if( !p_resource )
         return NULL;
 
-    vlc_gc_init( p_resource, Destructor );
+    atomic_init( &p_resource->refs, 1 );
     p_resource->p_parent = p_parent;
     vlc_mutex_init( &p_resource->lock );
     vlc_mutex_init( &p_resource->lock_hold );
@@ -416,12 +426,22 @@ input_resource_t *input_resource_New( vlc_object_t *p_parent )
 
 void input_resource_Release( input_resource_t *p_resource )
 {
-    vlc_gc_decref( p_resource );
+    if( atomic_fetch_sub( &p_resource->refs, 1 ) != 1 )
+        return;
+
+    DestroySout( p_resource );
+    DestroyVout( p_resource );
+    if( p_resource->p_aout != NULL )
+        aout_Destroy( p_resource->p_aout );
+
+    vlc_mutex_destroy( &p_resource->lock_hold );
+    vlc_mutex_destroy( &p_resource->lock );
+    free( p_resource );
 }
 
 input_resource_t *input_resource_Hold( input_resource_t *p_resource )
 {
-    vlc_gc_incref( p_resource );
+    atomic_fetch_add( &p_resource->refs, 1 );
     return p_resource;
 }
 
@@ -474,20 +494,6 @@ bool input_resource_HasVout( input_resource_t *p_resource )
     return b_vout;
 }
 
-/* */
-aout_instance_t *input_resource_RequestAout( input_resource_t *p_resource, aout_instance_t *p_aout )
-{
-    vlc_mutex_lock( &p_resource->lock );
-    aout_instance_t *p_ret = RequestAout( p_resource, p_aout );
-    vlc_mutex_unlock( &p_resource->lock );
-
-    return p_ret;
-}
-aout_instance_t *input_resource_HoldAout( input_resource_t *p_resource )
-{
-    return HoldAout( p_resource );
-}
-
 /* */
 sout_instance_t *input_resource_RequestSout( input_resource_t *p_resource, sout_instance_t *p_sout, const char *psz_sout )
 {
@@ -505,11 +511,7 @@ void input_resource_TerminateSout( input_resource_t *p_resource )
 void input_resource_Terminate( input_resource_t *p_resource )
 {
     input_resource_TerminateSout( p_resource );
-
-    vlc_mutex_lock( &p_resource->lock );
-    TerminateAout( p_resource );
-    vlc_mutex_unlock( &p_resource->lock );
-
+    input_resource_TerminateAout( p_resource );
     input_resource_TerminateVout( p_resource );
 }