]> git.sesse.net Git - vlc/blobdiff - src/control/event_async.c
libvlc_media_player: fix object leak (input thread).
[vlc] / src / control / event_async.c
index 43db2138b0ed6851b8903bc73bd905f68b699ce3..8702f2930e0d17962db241ced07f3432d855ddfa 100644 (file)
@@ -61,6 +61,11 @@ static inline bool is_queue_initialized(libvlc_event_manager_t * p_em)
     return queue(p_em) != NULL;
 }
 
+static inline bool current_thread_is_asynch_thread(libvlc_event_manager_t * p_em)
+{
+    return vlc_threadvar_get(queue(p_em)->is_asynch_dispatch_thread_var);
+}
+
 /* Lock must be held */
 static void push(libvlc_event_manager_t * p_em, libvlc_event_listener_t * listener, libvlc_event_t * event)
 {
@@ -128,14 +133,18 @@ static void pop_listener(libvlc_event_manager_t * p_em, libvlc_event_listener_t
     while (iter) {
         if(listeners_are_equal(&iter->listener, listener))
         {
+            struct queue_elmt * to_delete = iter;
             if(!prev)
-                queue(p_em)->elements = iter->next;
+                queue(p_em)->elements = to_delete->next;
             else
-                prev->next = iter->next;
-            free(iter);
+                prev->next = to_delete->next;
+            iter = to_delete->next;
+            free(to_delete);
+        }
+        else {
+            prev = iter;
+            iter = iter->next;
         }
-        prev = iter;
-        iter = iter->next;
     }
 }
 
@@ -148,6 +157,12 @@ void
 libvlc_event_async_fini(libvlc_event_manager_t * p_em)
 {    
     if(!is_queue_initialized(p_em)) return;
+
+    if(current_thread_is_asynch_thread(p_em))
+    {
+        fprintf(stderr, "*** Error: releasing the last reference of the observed object from its callback thread is not (yet!) supported\n");
+        abort();
+    }
     
     vlc_thread_t thread = queue(p_em)->thread;
     if(thread)
@@ -181,7 +196,14 @@ libvlc_event_async_init(libvlc_event_manager_t * p_em)
 {
     p_em->async_event_queue = calloc(1, sizeof(struct libvlc_event_async_queue));
 
-    int error = vlc_clone (&queue(p_em)->thread, event_async_loop, p_em, VLC_THREAD_PRIORITY_LOW);
+    int error = vlc_threadvar_create(&queue(p_em)->is_asynch_dispatch_thread_var, NULL);
+    assert(!error);
+
+    vlc_mutex_init(&queue(p_em)->lock);
+    vlc_cond_init(&queue(p_em)->signal);
+    vlc_cond_init(&queue(p_em)->signal_idle);
+    
+    error = vlc_clone (&queue(p_em)->thread, event_async_loop, p_em, VLC_THREAD_PRIORITY_LOW);
     if(error)
     {
         free(p_em->async_event_queue);
@@ -189,11 +211,6 @@ libvlc_event_async_init(libvlc_event_manager_t * p_em)
         return;
     }
 
-    vlc_mutex_init(&queue(p_em)->lock);
-    vlc_cond_init(&queue(p_em)->signal);
-    vlc_cond_init(&queue(p_em)->signal_idle);
-    error = vlc_threadvar_create(&queue(p_em)->is_asynch_dispatch_thread_var, NULL);
-    assert(!error);
 }
 
 /**************************************************************************
@@ -209,13 +226,11 @@ libvlc_event_async_ensure_listener_removal(libvlc_event_manager_t * p_em, libvlc
     queue_lock(p_em);
     pop_listener(p_em, listener);
     
-    bool is_asynch_dispatch_thread = vlc_threadvar_get(queue(p_em)->is_asynch_dispatch_thread_var);
-
     // Wait for the asynch_loop to have processed all events.
-    if(!queue(p_em)->is_idle && !is_asynch_dispatch_thread)
+    if(!current_thread_is_asynch_thread(p_em))
     {
-        vlc_cond_wait(&queue(p_em)->signal_idle, &queue(p_em)->lock);
-        assert(queue(p_em)->is_idle);
+        while(!queue(p_em)->is_idle)
+            vlc_cond_wait(&queue(p_em)->signal_idle, &queue(p_em)->lock);
     }
     queue_unlock(p_em);
 }
@@ -251,7 +266,7 @@ static void * event_async_loop(void * arg)
     libvlc_event_listener_t listener;
     libvlc_event_t event;
 
-    vlc_threadvar_set(queue(p_em)->is_asynch_dispatch_thread_var, (void*)true);
+    vlc_threadvar_set(queue(p_em)->is_asynch_dispatch_thread_var, p_em);
 
     queue_lock(p_em);
     while (true) {