macos: Fix race conditions

This commit fixes two issues:
- The event must be posted *after* calling stop, otherwise a race condition can occur and the app never stops
- isFinishedLaunching and applicationDidFinishLaunching are not always synchronized, causing sometimes
  a deadlock on the g_cond_wait never catching the g_cond_signal

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7593>
This commit is contained in:
Corentin Damman 2024-10-01 12:26:40 +00:00
parent aaf9b46e2f
commit 16da96653a

View file

@ -11,11 +11,13 @@ struct _ThreadArgs {
gboolean is_simple; gboolean is_simple;
GMutex nsapp_mutex; GMutex nsapp_mutex;
GCond nsapp_cond; GCond nsapp_cond;
gboolean nsapp_running;
}; };
@interface GstCocoaApplicationDelegate : NSObject <NSApplicationDelegate> @interface GstCocoaApplicationDelegate : NSObject <NSApplicationDelegate>
@property (assign) GMutex *nsapp_mutex; @property (assign) GMutex *nsapp_mutex;
@property (assign) GCond *nsapp_cond; @property (assign) GCond *nsapp_cond;
@property (assign) gboolean *nsapp_running;
@end @end
@implementation GstCocoaApplicationDelegate @implementation GstCocoaApplicationDelegate
@ -23,6 +25,7 @@ struct _ThreadArgs {
- (void)applicationDidFinishLaunching:(NSNotification *)notification - (void)applicationDidFinishLaunching:(NSNotification *)notification
{ {
g_mutex_lock (self.nsapp_mutex); g_mutex_lock (self.nsapp_mutex);
*self.nsapp_running = TRUE;
g_cond_signal (self.nsapp_cond); g_cond_signal (self.nsapp_cond);
g_mutex_unlock (self.nsapp_mutex); g_mutex_unlock (self.nsapp_mutex);
} }
@ -35,7 +38,7 @@ gst_thread_func (ThreadArgs *args)
/* Only proceed once NSApp is running, otherwise we could /* Only proceed once NSApp is running, otherwise we could
* attempt to call [NSApp: stop] before it's even started. */ * attempt to call [NSApp: stop] before it's even started. */
g_mutex_lock (&args->nsapp_mutex); g_mutex_lock (&args->nsapp_mutex);
while (![[NSRunningApplication currentApplication] isFinishedLaunching]) { while (!args->nsapp_running) {
g_cond_wait (&args->nsapp_cond, &args->nsapp_mutex); g_cond_wait (&args->nsapp_cond, &args->nsapp_mutex);
} }
g_mutex_unlock (&args->nsapp_mutex); g_mutex_unlock (&args->nsapp_mutex);
@ -55,11 +58,11 @@ gst_thread_func (ThreadArgs *args)
windowNumber: 0 windowNumber: 0
context: nil context: nil
subtype: NSEventSubtypeApplicationActivated subtype: NSEventSubtypeApplicationActivated
data1: 0 data1: 0
data2: 0]; data2: 0];
[NSApp postEvent:event atStart:YES];
[NSApp stop:nil]; [NSApp stop:nil];
[NSApp postEvent:event atStart:YES];
return ret; return ret;
} }
@ -73,11 +76,13 @@ run_main_with_nsapp (ThreadArgs args)
g_mutex_init (&args.nsapp_mutex); g_mutex_init (&args.nsapp_mutex);
g_cond_init (&args.nsapp_cond); g_cond_init (&args.nsapp_cond);
args.nsapp_running = FALSE;
[NSApplication sharedApplication]; [NSApplication sharedApplication];
delegate = [[GstCocoaApplicationDelegate alloc] init]; delegate = [[GstCocoaApplicationDelegate alloc] init];
delegate.nsapp_mutex = &args.nsapp_mutex; delegate.nsapp_mutex = &args.nsapp_mutex;
delegate.nsapp_cond = &args.nsapp_cond; delegate.nsapp_cond = &args.nsapp_cond;
delegate.nsapp_running = &args.nsapp_running;
[NSApp setDelegate:delegate]; [NSApp setDelegate:delegate];
/* This lets us show an icon in the dock and correctly focus opened windows */ /* This lets us show an icon in the dock and correctly focus opened windows */
@ -102,11 +107,11 @@ run_main_with_nsapp (ThreadArgs args)
* @argv: (array length=argc): an array of arguments to be passed to the main function * @argv: (array length=argc): an array of arguments to be passed to the main function
* @user_data: (nullable): user data to be passed to the main function * @user_data: (nullable): user data to be passed to the main function
* *
* Starts an NSApplication on the main thread before calling * Starts an NSApplication on the main thread before calling
* the provided main() function on a secondary thread. * the provided main() function on a secondary thread.
* *
* This ensures that GStreamer can correctly perform actions * This ensures that GStreamer can correctly perform actions
* such as creating a GL window, which require a Cocoa main loop * such as creating a GL window, which require a Cocoa main loop
* to be running on the main thread. * to be running on the main thread.
* *
* Do not call this function more than once - especially while * Do not call this function more than once - especially while
@ -144,7 +149,7 @@ gst_macos_main (GstMainFunc main_func, int argc, char **argv, gpointer user_data
* *
* Since: 1.22 * Since: 1.22
*/ */
int int
gst_macos_main_simple (GstMainFuncSimple main_func, gpointer user_data) gst_macos_main_simple (GstMainFuncSimple main_func, gpointer user_data)
{ {
ThreadArgs args; ThreadArgs args;