glwindow: don't use g_thread_join() to join the navigation thread
authorMatthew Waters <matthew@centricular.com>
Wed, 5 Oct 2016 07:32:09 +0000 (18:32 +1100)
committerMatthew Waters <matthew@centricular.com>
Wed, 5 Oct 2016 07:32:09 +0000 (18:32 +1100)
Using g_thread_join() in _finalize() handlers may result in a deadlock
joining the current thread when the last reference is held by a signal
handler.

e.g.:

error 'Resource deadlock avoided' during 'pthread_join (pt->system_thread, NULL)'

The backtrace looks like this:
[...]
g_thread_join ()
gst_gl_window_finalize ()
gst_gl_window_x11_finalize ()
g_object_unref ()
g_value_unset ()
g_signal_emit_valist ()
g_signal_emit ()
gst_gl_window_send_mouse_event ()
gst_gl_window_mouse_event_cb ()
g_main_dispatch ()
[..]
g_main_loop_run ()
gst_gl_window_navigation_thread ()
g_thread_proxy ()
start_thread ()
clone ()

gst-libs/gst/gl/gstglwindow.c

index b74d397..0588f1d 100644 (file)
@@ -101,6 +101,7 @@ struct _GstGLWindowPrivate
   GMainLoop *navigation_loop;
   GMutex nav_lock;
   GCond nav_create_cond;
+  GCond nav_destroy_cond;
   gboolean nav_alive;
   GMutex sync_message_lock;
   GCond sync_message_cond;
@@ -335,12 +336,16 @@ gst_gl_window_finalize (GObject * object)
   GstGLWindowPrivate *priv = window->priv;
 
   GST_INFO ("quit navigation loop");
+
+  g_mutex_lock (&window->priv->nav_lock);
   if (window->priv->navigation_loop) {
     g_main_loop_quit (window->priv->navigation_loop);
     /* wait until navigation thread finished */
-    g_thread_join (window->priv->navigation_thread);
+    while (window->priv->nav_alive)
+      g_cond_wait (&window->priv->nav_destroy_cond, &window->priv->nav_lock);
     window->priv->navigation_thread = NULL;
   }
+  g_mutex_unlock (&window->priv->nav_lock);
 
   if (priv->loop)
     g_main_loop_unref (priv->loop);
@@ -353,6 +358,7 @@ gst_gl_window_finalize (GObject * object)
   g_mutex_clear (&window->lock);
   g_mutex_clear (&window->priv->nav_lock);
   g_cond_clear (&window->priv->nav_create_cond);
+  g_cond_clear (&window->priv->nav_destroy_cond);
   g_mutex_clear (&window->priv->sync_message_lock);
   g_cond_clear (&window->priv->sync_message_cond);
   gst_object_unref (window->display);
@@ -939,6 +945,7 @@ gst_gl_window_navigation_thread (GstGLWindow * window)
 
   g_main_loop_run (window->priv->navigation_loop);
 
+  g_mutex_lock (&window->priv->nav_lock);
   g_main_context_pop_thread_default (window->priv->navigation_context);
 
   g_main_loop_unref (window->priv->navigation_loop);
@@ -946,6 +953,10 @@ gst_gl_window_navigation_thread (GstGLWindow * window)
   window->priv->navigation_loop = NULL;
   window->priv->navigation_context = NULL;
 
+  window->priv->nav_alive = FALSE;
+  g_cond_signal (&window->priv->nav_destroy_cond);
+  g_mutex_unlock (&window->priv->nav_lock);
+
   GST_INFO ("navigation loop exited\n");
 
   return NULL;