瀏覽代碼

Use exception throwing to shutdown main thread

Ivan Savenko 7 月之前
父節點
當前提交
a474803aaf
共有 4 個文件被更改,包括 30 次插入15 次删除
  1. 0 1
      client/CMT.h
  2. 5 3
      client/GameInstance.cpp
  3. 9 0
      client/GameInstance.h
  4. 16 11
      clientapp/EntryPoint.cpp

+ 0 - 1
client/CMT.h

@@ -16,4 +16,3 @@ extern SDL_Renderer * mainRenderer;
 /// Defined in clientapp EntryPoint
 /// TODO: decide on better location for this method
 [[noreturn]] void handleFatalError(const std::string & message, bool terminate);
-[[noreturn]] void quitApplication();

+ 5 - 3
client/GameInstance.cpp

@@ -100,13 +100,15 @@ bool GameInstance::capturedAllEvents()
 
 void GameInstance::onShutdownRequested(bool ask)
 {
+	auto doQuit = [](){ throw GameShutdownException(); };
+
 	if(!ask)
-		quitApplication();
+		doQuit();
 	else
 	{
 		if (interface())
-			interface()->showYesNoDialog(LIBRARY->generaltexth->allTexts[69], quitApplication, nullptr);
+			interface()->showYesNoDialog(LIBRARY->generaltexth->allTexts[69], doQuit, nullptr);
 		else
-			CInfoWindow::showYesNoDialog(LIBRARY->generaltexth->allTexts[69], {}, quitApplication, {}, PlayerColor(1));
+			CInfoWindow::showYesNoDialog(LIBRARY->generaltexth->allTexts[69], {}, doQuit, {}, PlayerColor(1));
 	}
 }

+ 9 - 0
client/GameInstance.h

@@ -21,6 +21,15 @@ VCMI_LIB_NAMESPACE_BEGIN
 class INetworkHandler;
 VCMI_LIB_NAMESPACE_END
 
+class GameShutdownException final : public std::exception
+{
+public:
+	const char* what() const noexcept final
+	{
+		return "Game shutdown has been requested";
+	}
+};
+
 class GameInstance final : boost::noncopyable, public IGameEngineUser
 {
 	std::unique_ptr<CServerHandler> serverInstance;

+ 16 - 11
clientapp/EntryPoint.cpp

@@ -62,7 +62,7 @@ namespace po_style = boost::program_options::command_line_style;
 static std::atomic<bool> headlessQuit = false;
 static std::optional<std::string> criticalInitializationError;
 
-[[noreturn]] extern void quitApplication();
+[[noreturn]] static void quitApplication();
 
 static void init()
 {
@@ -380,23 +380,28 @@ int main(int argc, char * argv[])
 	setThreadName("MainGUI");
 #endif
 
-	if(!settings["session"]["headless"].Bool())
+	try
 	{
-		checkForModLoadingFailure();
-		ENGINE->mainLoop();
+		if(!settings["session"]["headless"].Bool())
+		{
+			checkForModLoadingFailure();
+			ENGINE->mainLoop();
+		}
+		else
+		{
+			while(!headlessQuit)
+				std::this_thread::sleep_for(std::chrono::milliseconds(200));
+
+			std::this_thread::sleep_for(std::chrono::milliseconds(500));
+		}
 	}
-	else
+	catch (const GameShutdownException & )
 	{
-		while(!headlessQuit)
-			std::this_thread::sleep_for(std::chrono::milliseconds(200));
-
-		std::this_thread::sleep_for(std::chrono::milliseconds(500));
-
 		quitApplication();
 	}
 }
 
-[[noreturn]] void quitApplication()
+[[noreturn]] static void quitApplication()
 {
 	GAME->server().endNetwork();