From 149ca17df6b1f0e0bd08cad236fd033ca04f4176 Mon Sep 17 00:00:00 2001 From: Kentucky Compass Date: Thu, 22 Feb 2018 03:04:12 -0800 Subject: [PATCH] iOS: fix hang on exit --- ios/ViewController.h | 4 +++ ios/ViewController.mm | 70 ++++++++++++++++++++++++++++++++----------- ios/main.mm | 9 +++++- 3 files changed, 65 insertions(+), 18 deletions(-) diff --git a/ios/ViewController.h b/ios/ViewController.h index eda8722ec..4eedd89e7 100644 --- a/ios/ViewController.h +++ b/ios/ViewController.h @@ -9,4 +9,8 @@ @interface ViewController : GLKViewController +- (void)shutdown; + @end + +extern __unsafe_unretained ViewController* sharedViewController; diff --git a/ios/ViewController.mm b/ios/ViewController.mm index f55496917..9551f6a45 100644 --- a/ios/ViewController.mm +++ b/ios/ViewController.mm @@ -75,8 +75,9 @@ static double lastSelectPress = 0.0f; static double lastStartPress = 0.0f; static bool simulateAnalog = false; static bool threadEnabled = true; +static bool threadStopped = false; -__unsafe_unretained static ViewController* sharedViewController; +__unsafe_unretained ViewController* sharedViewController; static GraphicsContext *graphicsContext; @interface ViewController () @@ -114,6 +115,8 @@ static GraphicsContext *graphicsContext; iCadeToKeyMap[iCadeButtonG] = NKCODE_BUTTON_1; // Triangle iCadeToKeyMap[iCadeButtonH] = NKCODE_BUTTON_3; // Circle + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillTerminate:) name:UIApplicationWillTerminateNotification object:nil]; + #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 if ([GCController class]) // Checking the availability of a GameController framework { @@ -196,15 +199,20 @@ static GraphicsContext *graphicsContext; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ NativeInitGraphics(graphicsContext); + ILOG("Emulation thread starting\n"); while (threadEnabled) { NativeUpdate(); NativeRender(graphicsContext); time_update(); } + threadStopped = true; + + ILOG("Emulation thread shutting down\n"); NativeShutdownGraphics(); // Also ask the main thread to stop, so it doesn't hang waiting for a new frame. + ILOG("Emulation thread stopping\n"); graphicsContext->StopThread(); }); } @@ -214,33 +222,60 @@ static GraphicsContext *graphicsContext; [super didReceiveMemoryWarning]; } -- (void)dealloc +- (void)appWillTerminate:(NSNotification *)notification { - sharedViewController = nil; - - if ([EAGLContext currentContext] == self.context) { - [EAGLContext setCurrentContext:nil]; + [self shutdown]; +} + +- (void)shutdown +{ + if (sharedViewController == nil) { + return; } - self.context = nil; + + Audio_Shutdown(); + + if (threadEnabled) { + threadEnabled = false; + while (graphicsContext->ThreadFrame()) { + continue; + } + while (!threadStopped) {} + graphicsContext->ThreadEnd(); + } + + sharedViewController = nil; + + if (self.context) { + if ([EAGLContext currentContext] == self.context) { + [EAGLContext setCurrentContext:nil]; + } + self.context = nil; + } + + [[NSNotificationCenter defaultCenter] removeObserver:self]; #if __IPHONE_OS_VERSION_MAX_ALLOWED > __IPHONE_6_1 if ([GCController class]) { - [[NSNotificationCenter defaultCenter] removeObserver:self name:GCControllerDidConnectNotification object:nil]; - [[NSNotificationCenter defaultCenter] removeObserver:self name:GCControllerDidDisconnectNotification object:nil]; self.gameController = nil; } #endif - threadEnabled = false; - while (graphicsContext->ThreadFrame()) { - continue; - } - graphicsContext->ThreadEnd(); + graphicsContext->Shutdown(); - delete graphicsContext; - graphicsContext = NULL; + + if (graphicsContext) { + delete graphicsContext; + graphicsContext = NULL; + } + NativeShutdown(); } +- (void)dealloc +{ + [self shutdown]; +} + // For iOS before 6.0 - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { @@ -255,7 +290,8 @@ static GraphicsContext *graphicsContext; - (void)glkView:(GLKView *)view drawInRect:(CGRect)rect { - graphicsContext->ThreadFrame(); + if (sharedViewController) + graphicsContext->ThreadFrame(); } - (void)touchX:(float)x y:(float)y code:(int)code pointerId:(int)pointerId diff --git a/ios/main.mm b/ios/main.mm index 8a5817982..7e614bce3 100644 --- a/ios/main.mm +++ b/ios/main.mm @@ -9,6 +9,7 @@ #import "AppDelegate.h" #import "PPSSPPUIApplication.h" +#import "ViewController.h" #include "base/NativeApp.h" #include "profiler/profiler.h" @@ -24,6 +25,8 @@ @implementation UIApplication (SpringBoardAnimatedExit) -(void) animatedExit { + [sharedViewController shutdown]; + BOOL multitaskingSupported = NO; if ([[UIDevice currentDevice] respondsToSelector:@selector(isMultitaskingSupported)]) { multitaskingSupported = [UIDevice currentDevice].multitaskingSupported; @@ -40,6 +43,8 @@ } -(void) exit { + [sharedViewController shutdown]; + if ([self respondsToSelector:@selector(terminateWithSuccess)]) { [self terminateWithSuccess]; } else { @@ -89,7 +94,9 @@ bool System_GetPropertyBool(SystemProperty prop) { void System_SendMessage(const char *command, const char *parameter) { if (!strcmp(command, "finish")) { - [[UIApplication sharedApplication] animatedExit]; + dispatch_async(dispatch_get_main_queue(), ^{ + [[UIApplication sharedApplication] animatedExit]; + }); } }