thread-pool: avoid race in shutdown
authorWim Taymans <wim.taymans@gmail.com>
Tue, 12 Nov 2013 09:28:55 +0000 (10:28 +0100)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 12 Nov 2013 09:28:55 +0000 (10:28 +0100)
If we call g_main_loop_quit before the thread has entered g_main_loop_run, we
don't actually stop the mainloop ever. Solve this race by adding an idle source
to the mainloop that calls the _quit. This way we immediately exit the mainloop
if quit was called before we started it.

gst/rtsp-server/rtsp-thread-pool.c

index eb82e34..0a12fd1 100644 (file)
@@ -141,6 +141,14 @@ gst_rtsp_thread_reuse (GstRTSPThread * thread)
   return g_atomic_int_add (&impl->reused, 1) > 0;
 }
 
+static gboolean
+do_quit (GstRTSPThread * thread)
+{
+  GST_DEBUG ("stop mainloop of thread %p", thread);
+  g_main_loop_quit (thread->loop);
+  return FALSE;
+}
+
 /**
  * gst_rtsp_thread_stop:
  * @thread: (transfer full): a #GstRTSPThread
@@ -158,11 +166,15 @@ gst_rtsp_thread_stop (GstRTSPThread * thread)
   GST_DEBUG ("stop thread %p", thread);
 
   if (g_atomic_int_dec_and_test (&impl->reused)) {
-    GST_DEBUG ("stop mainloop of thread %p", thread);
-    g_main_loop_quit (thread->loop);
+    GSource *source;
+
+    GST_DEBUG ("add idle source to quit mainloop of thread %p", thread);
+    source = g_idle_source_new ();
+    g_source_set_callback (source, (GSourceFunc) do_quit,
+        thread, (GDestroyNotify) gst_rtsp_thread_unref);
+    g_source_attach (source, thread->context);
+    g_source_unref (source);
   }
-
-  gst_rtsp_thread_unref (thread);
 }
 
 #define GST_RTSP_THREAD_POOL_GET_PRIVATE(obj)  \
@@ -453,7 +465,7 @@ default_get_thread (GstRTSPThreadPool * pool,
           thread = make_thread (pool, type, ctx);
 
           if (!g_thread_pool_push (klass->pool, gst_rtsp_thread_ref (thread),
-              &error))
+                  &error))
             goto thread_error;
         }
         g_queue_push_tail (&priv->threads, thread);
@@ -465,7 +477,7 @@ default_get_thread (GstRTSPThreadPool * pool,
       thread = make_thread (pool, type, ctx);
 
       if (!g_thread_pool_push (klass->pool, gst_rtsp_thread_ref (thread),
-          &error))
+              &error))
         goto thread_error;
       break;
     default:
@@ -535,8 +547,9 @@ gst_rtsp_thread_pool_cleanup (void)
 {
   GstRTSPThreadPoolClass *klass;
 
-  klass = GST_RTSP_THREAD_POOL_CLASS (
-      g_type_class_peek (gst_rtsp_thread_pool_get_type ()));
+  klass =
+      GST_RTSP_THREAD_POOL_CLASS (g_type_class_peek
+      (gst_rtsp_thread_pool_get_type ()));
   if (klass->pool != NULL) {
     g_thread_pool_free (klass->pool, FALSE, TRUE);
     klass->pool = NULL;