From 1783abec1351ccd7b101307eb536b0e74e91b014 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Tue, 12 Apr 2016 00:50:59 -0400 Subject: [PATCH] Lock around LiStartConnection() and LiStopConnection() to fix thread-safety issues. This will hopefully address the crashes seen in 1.0.3 and 1.0.4. --- Limelight/Stream/Connection.h | 1 - Limelight/Stream/Connection.m | 31 +++++++++++-------- Limelight/Stream/StreamManager.h | 1 - Limelight/Stream/StreamManager.m | 9 ------ .../StreamFrameViewController.m | 4 +-- 5 files changed, 20 insertions(+), 26 deletions(-) diff --git a/Limelight/Stream/Connection.h b/Limelight/Stream/Connection.h index a151569..d1eaae1 100644 --- a/Limelight/Stream/Connection.h +++ b/Limelight/Stream/Connection.h @@ -27,7 +27,6 @@ -(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id)callbacks serverMajorVersion:(int)serverMajorVersion; -(void) terminate; --(void) terminateInternal; -(void) main; @end diff --git a/Limelight/Stream/Connection.m b/Limelight/Stream/Connection.m index 3eff486..aeedba9 100644 --- a/Limelight/Stream/Connection.m +++ b/Limelight/Stream/Connection.m @@ -23,6 +23,7 @@ int _serverMajorVersion; } +static NSLock* initLock; static OpusDecoder *opusDecoder; static id _callbacks; @@ -261,26 +262,28 @@ void ClDisplayTransientMessage(char* message) [_callbacks displayTransientMessage: message]; } --(void) terminateInternal -{ - // We dispatch this async to get out because this can be invoked - // on a thread inside common and we don't want to deadlock - dispatch_async(dispatch_get_main_queue(), ^{ - // This is safe to call even before LiStartConnection - LiStopConnection(); - }); -} - -(void) terminate { - // We're guaranteed to not be on a moonlight-common thread - // here so it's safe to call stop directly - LiStopConnection(); + // We dispatch this async to get out because this can be invoked + // on a thread inside common and we don't want to deadlock. It also avoids + // blocking on the caller's thread waiting to acquire initLock. + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + [initLock lock]; + LiStopConnection(); + [initLock unlock]; + }); } -(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id)callbacks serverMajorVersion:(int)serverMajorVersion { self = [super init]; + + // Use a lock to ensure that only one thread is initializing + // or deinitializing a connection at a time. + if (initLock == nil) { + initLock = [[NSLock alloc] init]; + } + _host = [config.host cStringUsingEncoding:NSUTF8StringEncoding]; renderer = myRenderer; _callbacks = callbacks; @@ -403,12 +406,14 @@ static OSStatus playbackCallback(void *inRefCon, -(void) main { + [initLock lock]; LiStartConnection(_host, &_streamConfig, &_clCallbacks, &_drCallbacks, &_arCallbacks, NULL, 0, _serverMajorVersion); + [initLock unlock]; } @end diff --git a/Limelight/Stream/StreamManager.h b/Limelight/Stream/StreamManager.h index 44c45ad..b2285e1 100644 --- a/Limelight/Stream/StreamManager.h +++ b/Limelight/Stream/StreamManager.h @@ -14,6 +14,5 @@ - (id) initWithConfig:(StreamConfiguration*)config renderView:(UIView*)view connectionCallbacks:(id)callback; - (void) stopStream; -- (void) stopStreamInternal; @end diff --git a/Limelight/Stream/StreamManager.m b/Limelight/Stream/StreamManager.m index 335b433..841015c 100644 --- a/Limelight/Stream/StreamManager.m +++ b/Limelight/Stream/StreamManager.m @@ -91,20 +91,11 @@ [opQueue addOperation:_connection]; } -// This should NEVER be called from within a thread -// owned by moonlight-common - (void) stopStream { [_connection terminate]; } -// This should only be called from within a thread -// owned by moonlight-common -- (void) stopStreamInternal -{ - [_connection terminateInternal]; -} - - (BOOL) launchApp:(HttpManager*)hMan { HttpResponse* launchResp = [[HttpResponse alloc] init]; [hMan executeRequestSynchronously:[HttpRequest requestForResponse:launchResp withUrlRequest: diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index 5b5b796..c871a89 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -84,7 +84,7 @@ [self presentViewController:conTermAlert animated:YES completion:nil]; }); - [_streamMan stopStreamInternal]; + [_streamMan stopStream]; } - (void) stageStarting:(char*)stageName { @@ -115,7 +115,7 @@ [self presentViewController:alert animated:YES completion:nil]; }); - [_streamMan stopStreamInternal]; + [_streamMan stopStream]; } - (void) launchFailed:(NSString*)message {