osxvideosink: fix race in starting the runloop thread
authorAlessandro Decina <alessandro.decina@collabora.co.uk>
Sat, 26 May 2012 10:21:18 +0000 (12:21 +0200)
committerSebastian Dröge <sebastian.droege@collabora.co.uk>
Thu, 31 May 2012 08:26:10 +0000 (10:26 +0200)
Block gst_osx_video_sink_run_cocoa_loop until the loop thread has started and
finished initializing NSApp. Fixes occasional warnings/crashes due to two
threads going inside NSApp before finishLaunching had completed.

sys/osxvideo/osxvideosink.h
sys/osxvideo/osxvideosink.m

index 2d18f13..5d32f5c 100644 (file)
@@ -77,10 +77,12 @@ struct _GstOSXVideoSink {
   NSView *superview;
 #ifdef RUN_NS_APP_THREAD
   NSThread *ns_app_thread;
+  GMutex *loop_thread_lock;
+  GCond *loop_thread_cond;
 #else
   guint cocoa_timeout;
-  gboolean app_started;
 #endif
+  gboolean app_started;
   gboolean keep_par;
   gboolean embed;
 };
index d4f3330..a444223 100644 (file)
@@ -115,7 +115,7 @@ run_ns_app_loop (void) {
 }
 
 static void
-gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * osxvideosink )
+gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * sink )
 {
   /* Cocoa applications require a main runloop running to dispatch UI
    * events and process deferred calls to the main thread through
@@ -138,14 +138,19 @@ gst_osx_video_sink_run_cocoa_loop (GstOSXVideoSink * osxvideosink )
 
     method_exchangeImplementations(origIsMainThread, ourIsMainThread);
 
-    osxvideosink->ns_app_thread = [[NSThread alloc]
-        initWithTarget:osxvideosink->osxvideosinkobject
+    sink->ns_app_thread = [[NSThread alloc]
+        initWithTarget:sink->osxvideosinkobject
         selector:@selector(nsAppThread) object:nil];
-    [osxvideosink->ns_app_thread start];
+    [sink->ns_app_thread start];
+
+    g_mutex_lock (sink->loop_thread_lock);
+    while (!sink->app_started)
+      g_cond_wait (sink->loop_thread_cond, sink->loop_thread_lock);
+    g_mutex_unlock (sink->loop_thread_lock);
 #else
   /* assume that there is a GMainLoop and iterate the main runloop from there
    */
-    osxvideosink->cocoa_timeout = g_timeout_add (10,
+    sink->cocoa_timeout = g_timeout_add (10,
         (GSourceFunc) run_ns_app_loop, NULL);
 #endif
   }
@@ -356,9 +361,7 @@ gst_osx_video_sink_change_state (GstElement * element,
     case GST_STATE_CHANGE_PAUSED_TO_READY:
       GST_VIDEO_SINK_WIDTH (osxvideosink) = 0;
       GST_VIDEO_SINK_HEIGHT (osxvideosink) = 0;
-#ifndef RUN_NS_APP_THREAD
       osxvideosink->app_started = FALSE;
-#endif
       gst_osx_video_sink_osxwindow_destroy (osxvideosink);
       break;
     case GST_STATE_CHANGE_READY_TO_NULL:
@@ -450,16 +453,17 @@ gst_osx_video_sink_get_property (GObject * object, guint prop_id,
 
 
 static void
-gst_osx_video_sink_init (GstOSXVideoSink * osxvideosink)
+gst_osx_video_sink_init (GstOSXVideoSink * sink)
 {
-  osxvideosink->osxwindow = NULL;
-  osxvideosink->superview = NULL;
-  osxvideosink->osxvideosinkobject = [[GstOSXVideoSinkObject alloc]
-    initWithSink:osxvideosink];
-#ifndef RUN_NS_APP_THREAD
-  osxvideosink->app_started = FALSE;
+  sink->osxwindow = NULL;
+  sink->superview = NULL;
+  sink->osxvideosinkobject = [[GstOSXVideoSinkObject alloc] initWithSink:sink];
+#ifdef RUN_NS_APP_THREAD
+  sink->loop_thread_lock = g_mutex_new ();
+  sink->loop_thread_cond = g_cond_new ();
 #endif
-  osxvideosink->keep_par = FALSE;
+  sink->app_started = FALSE;
+  sink->keep_par = FALSE;
 }
 
 static void
@@ -857,6 +861,7 @@ gst_osx_video_sink_get_type (void)
 -(void) nsAppThread
 {
   NSAutoreleasePool *pool;
+  GstOSXVideoSink *sink = osxvideosink;
 
   /* set the main runloop as the runloop for the current thread. This has the
    * effect that calling NSApp nextEventMatchingMask:untilDate:inMode:dequeue
@@ -874,6 +879,11 @@ gst_osx_video_sink_get_type (void)
   [NSApplication sharedApplication];
   [NSApp finishLaunching];
 
+  g_mutex_lock (sink->loop_thread_lock);
+  sink->app_started = TRUE;
+  g_cond_signal (sink->loop_thread_cond);
+  g_mutex_unlock (sink->loop_thread_lock);
+
   /* run the loop */
   run_ns_app_loop ();