]> git.sesse.net Git - vlc/blobdiff - src/misc/objects.c
Fix screensaver deadlock if terminating as soon the interface is created - closes...
[vlc] / src / misc / objects.c
index b1d27d0b3bd2bea32d5ae4d861bb52d8931fb994..695b8e7086986f36d67f4f1b37c81c315e454fac 100644 (file)
 #include "vlc_meta.h"
 
 #include "variables.h"
+#ifndef WIN32
+# include <unistd.h>
+#else
+# include <io.h>
+# include <fcntl.h>
+#endif
 
 /*****************************************************************************
  * Local prototypes
@@ -177,7 +183,7 @@ vlc_object_t *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
         vlc_mutex_unlock( &structure_lock );
     }
 
-    p_new->i_refcount = 0;
+    p_priv->i_refcount = 0;
     p_new->p_parent = NULL;
     p_new->pp_children = NULL;
     p_new->i_children = 0;
@@ -188,6 +194,7 @@ vlc_object_t *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
     vlc_mutex_init( p_new, &p_new->object_lock );
     vlc_cond_init( p_new, &p_new->object_wait );
     vlc_mutex_init( p_new, &p_priv->var_lock );
+    p_priv->pipes[0] = p_priv->pipes[1] = -1;
 
     if( i_type == VLC_OBJECT_GLOBAL )
     {
@@ -299,10 +306,6 @@ void * __vlc_object_create( vlc_object_t *p_this, int i_type )
             i_size = sizeof( vod_t );
             psz_type = "vod server";
             break;
-        case VLC_OBJECT_TLS:
-            i_size = sizeof( tls_t );
-            psz_type = "tls";
-            break;
         case VLC_OBJECT_XML:
             i_size = sizeof( xml_t );
             psz_type = "xml";
@@ -362,7 +365,7 @@ void __vlc_object_destroy( vlc_object_t *p_this )
         return;
     }
 
-    while( p_this->i_refcount )
+    while( p_priv->i_refcount > 0 )
     {
         i_delay++;
 
@@ -370,15 +373,15 @@ void __vlc_object_destroy( vlc_object_t *p_this )
         if( i_delay == 2 )
         {
             msg_Warn( p_this,
-                  "refcount is %i, delaying before deletion (id=%d,type=%d)",
-                  p_this->i_refcount, p_this->i_object_id,
+                  "refcount is %u, delaying before deletion (id=%d,type=%d)",
+                  p_priv->i_refcount, p_this->i_object_id,
                   p_this->i_object_type );
         }
         else if( i_delay == 10 )
         {
             msg_Err( p_this,
-                  "refcount is %i, delaying again (id=%d,type=%d)",
-                  p_this->i_refcount, p_this->i_object_id,
+                  "refcount is %u, delaying again (id=%d,type=%d)",
+                  p_priv->i_refcount, p_this->i_object_id,
                   p_this->i_object_type );
         }
         else if( i_delay == 20 )
@@ -439,6 +442,10 @@ void __vlc_object_destroy( vlc_object_t *p_this )
 
     vlc_mutex_destroy( &p_this->object_lock );
     vlc_cond_destroy( &p_this->object_wait );
+    if( p_priv->pipes[0] != -1 )
+        close( p_priv->pipes[0] );
+    if( p_priv->pipes[1] != -1 )
+        close( p_priv->pipes[1] );
 
     /* global is not dynamically allocated by vlc_object_create */
     if( p_this->i_object_type != VLC_OBJECT_GLOBAL )
@@ -455,10 +462,47 @@ void __vlc_object_lock( vlc_object_t *obj )
 
 void __vlc_object_unlock( vlc_object_t *obj )
 {
-    vlc_assert_locked( &p_this->object_lock );
+    vlc_assert_locked( &obj->object_lock );
     vlc_mutex_unlock( &obj->object_lock );
 }
 
+/**
+ * Returns the readable end of a pipe that becomes readable whenever
+ * an object is signaled. This can be used to wait for VLC object events
+ * inside select(), poll() loops or frameworks providing an event loop.
+ *
+ * Note that the pipe will remain the same for the lifetime of the object.
+ * DO NOT close it yourself. Ever.
+ *
+ * DO NOT try to read from the pipe either: call vlc_object_wait() instead.
+ * Assuming the pipe is readable, vlc_object_wait() will not block.
+ * Also note that, as with vlc_object_wait(), there may be spurious wakeups.
+ *
+ * @param obj object that would be signaled (object lock MUST hold)
+ * @return a readable pipe descriptor, or -1 on error.
+ */
+int vlc_object_waitpipe( vlc_object_t *obj )
+{
+    int *pipes = obj->p_internals->pipes;
+    vlc_assert_locked( &obj->object_lock );
+
+    if( pipes[1] == -1 )
+    {
+        /* This can only ever happen if someone killed us without locking */
+        assert( pipes[0] == -1 );
+
+#ifndef WIN32
+        if( pipe( pipes ) )
+#else
+        if( _pipe( pipes, 1, _O_BINARY ) )
+#endif
+            return -1;
+    }
+
+    return pipes[0];
+}
+
+
 /**
  * Waits for the object to be signaled (using vlc_object_signal()).
  * If the object already has a signal pending, this function will return
@@ -469,6 +513,18 @@ void __vlc_object_unlock( vlc_object_t *obj )
 vlc_bool_t __vlc_object_wait( vlc_object_t *obj )
 {
     vlc_assert_locked( &obj->object_lock );
+
+    int fd = obj->p_internals->pipes[0];
+    if( fd != -1 )
+    {
+        if( read( fd, &(char){ 0 }, 1 ) == 0 )
+        {
+            close( fd );
+            obj->p_internals->pipes[1] = -1;
+        }
+        return obj->b_die;
+    }
+
     vlc_cond_wait( &obj->object_wait, &obj->object_lock );
     return obj->b_die;
 }
@@ -497,23 +553,47 @@ int __vlc_object_timedwait( vlc_object_t *obj, mtime_t deadline )
 
 
 /**
- * Signals an object for which the lock is held.
+ * 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...
+
+       if (vlc_object_wait (self))
+           continue;
+
+       ...postprocessing...
+   }
+   ...deinitialization...
+   vlc_object_unlock (self);
+ *
+ *
+ * @return true iff the object has not been killed yet
  */
-void __vlc_object_signal_unlocked( vlc_object_t *obj )
+vlc_bool_t __vlc_object_alive( vlc_object_t *obj )
 {
     vlc_assert_locked( &obj->object_lock );
-    vlc_cond_signal( &obj->object_wait );
+    return !obj->b_die;
 }
 
 
 /**
- * Signals an object for which the lock is NOT held.
+ * Signals an object for which the lock is held.
  */
-void __vlc_object_signal( vlc_object_t *obj )
+void __vlc_object_signal_unlocked( vlc_object_t *obj )
 {
-    vlc_mutex_lock( &obj->object_lock );
-    vlc_object_signal_unlocked( obj );
-    vlc_mutex_unlock( &obj->object_lock );
+    vlc_assert_locked( &obj->object_lock );
+
+    int fd = obj->p_internals->pipes[1];
+    if( fd != -1 )
+        while( write( fd, &(char){ 0 }, 1 ) < 0 );
+
+    vlc_cond_signal( &obj->object_wait );
 }
 
 
@@ -524,12 +604,19 @@ void __vlc_object_signal( vlc_object_t *obj )
 void __vlc_object_kill( vlc_object_t *p_this )
 {
     vlc_mutex_lock( &p_this->object_lock );
+    p_this->b_die = VLC_TRUE;
 
     if( p_this->i_object_type == VLC_OBJECT_LIBVLC )
         for( int i = 0; i < p_this->i_children ; i++ )
             vlc_object_kill( p_this->pp_children[i] );
 
-    p_this->b_die = VLC_TRUE;
+    int fd = p_this->p_internals->pipes[1];
+    if( fd != -1 )
+    {
+        close( fd ); /* closing a pipe makes it readable too */
+        p_this->p_internals->pipes[1] = -1;
+    }
+
     vlc_object_signal_unlocked( p_this );
     vlc_mutex_unlock( &p_this->object_lock );
 }
@@ -573,7 +660,7 @@ void * __vlc_object_get( vlc_object_t *p_this, int i_id )
                 if( pp_objects[i_middle+1]->i_object_id == i_id )
                 {
                     vlc_mutex_unlock( &structure_lock );
-                    pp_objects[i_middle+1]->i_refcount++;
+                    pp_objects[i_middle+1]->p_internals->i_refcount++;
                     return pp_objects[i_middle+1];
                 }
                 break;
@@ -582,7 +669,7 @@ void * __vlc_object_get( vlc_object_t *p_this, int i_id )
         else
         {
             vlc_mutex_unlock( &structure_lock );
-            pp_objects[i_middle]->i_refcount++;
+            pp_objects[i_middle]->p_internals->i_refcount++;
             return pp_objects[i_middle];
         }
 
@@ -614,7 +701,7 @@ void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
     /* If we are of the requested type ourselves, don't look further */
     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
     {
-        p_this->i_refcount++;
+        p_this->p_internals->i_refcount++;
         vlc_mutex_unlock( &structure_lock );
         return p_this;
     }
@@ -667,7 +754,7 @@ void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
         && p_this->psz_object_name
         && !strcmp( p_this->psz_object_name, psz_name ) )
     {
-        p_this->i_refcount++;
+        p_this->p_internals->i_refcount++;
         vlc_mutex_unlock( &structure_lock );
         return p_this;
     }
@@ -709,18 +796,23 @@ void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
 void __vlc_object_yield( vlc_object_t *p_this )
 {
     vlc_mutex_lock( &structure_lock );
-    p_this->i_refcount++;
+    p_this->p_internals->i_refcount++;
     vlc_mutex_unlock( &structure_lock );
 }
 
-/**
- ****************************************************************************
+static inline void Release( vlc_object_t *obj )
+{
+    assert( obj->p_internals->i_refcount > 0 );
+    obj->p_internals->i_refcount--;
+}
+
+/*****************************************************************************
  * decrement an object refcount
  *****************************************************************************/
 void __vlc_object_release( vlc_object_t *p_this )
 {
     vlc_mutex_lock( &structure_lock );
-    p_this->i_refcount--;
+    Release( p_this );
     vlc_mutex_unlock( &structure_lock );
 }
 
@@ -1045,7 +1137,7 @@ void vlc_list_release( vlc_list_t *p_list )
     vlc_mutex_lock( &structure_lock );
     for( i_index = 0; i_index < p_list->i_count; i_index++ )
     {
-        p_list->p_values[i_index].p_object->i_refcount--;
+        Release( p_list->p_values[i_index].p_object );
     }
     vlc_mutex_unlock( &structure_lock );
 
@@ -1108,7 +1200,7 @@ static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
         {
             if( p_tmp->i_object_type == i_type )
             {
-                p_tmp->i_refcount++;
+                p_tmp->p_internals->i_refcount++;
                 return p_tmp;
             }
             else
@@ -1124,7 +1216,7 @@ static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
             p_tmp = p_this->pp_children[i];
             if( p_tmp->i_object_type == i_type )
             {
-                p_tmp->i_refcount++;
+                p_tmp->p_internals->i_refcount++;
                 return p_tmp;
             }
             else if( p_tmp->i_children )
@@ -1162,7 +1254,7 @@ static vlc_object_t * FindObjectName( vlc_object_t *p_this,
             if( p_tmp->psz_object_name
                 && !strcmp( p_tmp->psz_object_name, psz_name ) )
             {
-                p_tmp->i_refcount++;
+                p_tmp->p_internals->i_refcount++;
                 return p_tmp;
             }
             else
@@ -1179,7 +1271,7 @@ static vlc_object_t * FindObjectName( vlc_object_t *p_this,
             if( p_tmp->psz_object_name
                 && !strcmp( p_tmp->psz_object_name, psz_name ) )
             {
-                p_tmp->i_refcount++;
+                p_tmp->p_internals->i_refcount++;
                 return p_tmp;
             }
             else if( p_tmp->i_children )
@@ -1279,8 +1371,9 @@ static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
     }
 
     psz_refcount[0] = '\0';
-    if( p_this->i_refcount )
-        snprintf( psz_refcount, 19, ", refcount %i", p_this->i_refcount );
+    if( p_this->p_internals->i_refcount > 0 )
+        snprintf( psz_refcount, 19, ", refcount %u",
+                  p_this->p_internals->i_refcount );
 
     psz_thread[0] = '\0';
     if( p_this->p_internals->b_thread )
@@ -1379,7 +1472,7 @@ static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
         return;
     }
 
-    p_object->i_refcount++;
+    p_object->p_internals->i_refcount++;
 
     p_list->p_values[i_index].p_object = p_object;
 
@@ -1401,7 +1494,7 @@ static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
         return;
     }
 
-    p_object->i_refcount++;
+    p_object->p_internals->i_refcount++;
 
     p_list->p_values[p_list->i_count].p_object = p_object;
     p_list->i_count++;