diff --git a/application/application.cpp b/application/application.cpp index 119cb021e..56a83c29c 100644 --- a/application/application.cpp +++ b/application/application.cpp @@ -270,7 +270,11 @@ void eu07_application::DiscordRPCService() } if (currentMode != mode::driver) + { + // the editor and the other modes: nothing to tell, without spinning a core on it + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); continue; + } // Discord RPC updater if (simulation::is_ready) @@ -690,19 +694,29 @@ void eu07_application::release_python_lock() void eu07_application::exit() { Global.applicationQuitOrder = true; + // each step of the closing in the log, to tell from it where a closing that hangs stops + auto const closing{std::chrono::steady_clock::now()}; + auto const step = [&](char const *What) { + WriteLog(std::string{"Closing: "} + What + " at " + std::to_string(std::chrono::duration_cast(std::chrono::steady_clock::now() - closing).count()) + " ms"); + }; + step("the modes"); for (auto &mode : m_modes) mode.reset(); + step("the renderer"); GfxRenderer->Shutdown(); m_network.reset(); // SafeDelete( simulation::Train ); + step("the scenery"); SafeDelete(simulation::Region); + step("the ui and the python workers"); ui_layer::shutdown(); // the python workers detach their GL context on the way out, so they have to be done before the windows they use are destroyed m_taskqueue.exit(); + step("the windows"); for (auto *window : m_windows) { glfwDestroyWindow(window); @@ -713,6 +727,8 @@ void eu07_application::exit() if (!Global.exec_on_exit.empty()) system(Global.exec_on_exit.c_str()); + step("done"); + StopLogService(); auto it = Global.threads.find("LogService"); if (it != Global.threads.end()) { diff --git a/nodebank_previews_standalone.cpp b/nodebank_previews_standalone.cpp index 39884fd38..d94eb13ed 100644 --- a/nodebank_previews_standalone.cpp +++ b/nodebank_previews_standalone.cpp @@ -290,9 +290,9 @@ int generate_nodebank_previews(int Argc, char *Argv[]) std::thread logservice(LogService); auto const finish = [&](int const Result) { - // give the log service time to write out what's left - std::this_thread::sleep_for(std::chrono::milliseconds(200)); + // the log service writes out what's left before it stops Global.applicationQuitOrder = true; + StopLogService(); logservice.join(); return Result; }; diff --git a/utilities/Logs.cpp b/utilities/Logs.cpp index 38f8062b9..18020d6f1 100644 --- a/utilities/Logs.cpp +++ b/utilities/Logs.cpp @@ -73,12 +73,21 @@ std::deque ErrorStack; // lock for log stacks std::mutex logMutex; +// the log is written through the closing of the simulator, to the end +std::atomic logStop{false}; + +void StopLogService() +{ + logStop = true; +} void LogService() { - while (!Global.applicationQuitOrder) + // one more pass after the stop, so what came just before it gets written too + for (bool last{false}; false == last;) { + last = logStop; { // --- Obsługa InfoStack --- while (!InfoStack.empty()) diff --git a/utilities/Logs.h b/utilities/Logs.h index 93276d651..63727de9c 100644 --- a/utilities/Logs.h +++ b/utilities/Logs.h @@ -23,7 +23,9 @@ enum class logtype : unsigned int { traction = 1 << 9, powergrid = 1 << 10, }; +// writes the log until StopLogService(), and all of it that came before void LogService(); +void StopLogService(); void WriteLog( const char *str, logtype const Type = logtype::generic, bool isError = false ); void Error( const std::string &asMessage, bool box = false ); void Error( const char* &asMessage, bool box = false );