diff options
Diffstat (limited to 'src/zenutil/zenserverprocess.cpp')
| -rw-r--r-- | src/zenutil/zenserverprocess.cpp | 105 |
1 files changed, 83 insertions, 22 deletions
diff --git a/src/zenutil/zenserverprocess.cpp b/src/zenutil/zenserverprocess.cpp index 9a2ec9774..f5bc088a5 100644 --- a/src/zenutil/zenserverprocess.cpp +++ b/src/zenutil/zenserverprocess.cpp @@ -12,6 +12,7 @@ #include <zencore/string.h> #include <zencore/thread.h> #include <zencore/timer.h> +#include <zenutil/basicfile.h> #include <atomic> @@ -534,6 +535,8 @@ ZenServerInstance::~ZenServerInstance() try { Shutdown(); + std::error_code DummyEc; + std::filesystem::remove(std::filesystem::temp_directory_path() / ("zenserver_" + m_Name + ".log"), DummyEc); } catch (const std::exception& Err) { @@ -547,7 +550,7 @@ ZenServerInstance::SignalShutdown() m_ShutdownEvent.Set(); } -void +int ZenServerInstance::Shutdown() { if (m_Process.IsValid()) @@ -557,28 +560,44 @@ ZenServerInstance::Shutdown() if (m_Terminate) { ZEN_INFO("Terminating zenserver process {}", m_Name); - m_Process.Terminate(111); + int ExitCode = 111; + m_Process.Terminate(ExitCode); m_Process.Reset(); ZEN_DEBUG("zenserver process {} ({}) terminated", m_Name, m_Process.Pid()); + return ExitCode; } else { - ZEN_DEBUG("Requesting zenserver process {} ({}) to shut down", m_Name, m_Process.Pid()); - SignalShutdown(); - ZEN_DEBUG("Waiting for zenserver process {} ({}) to shut down", m_Name, m_Process.Pid()); - while (!m_Process.Wait(5000)) + if (m_Process.IsRunning()) { - ZEN_WARN("Waiting for zenserver process {} ({}) timed out", m_Name, m_Process.Pid()); + ZEN_DEBUG("Requesting zenserver process {} ({}) to shut down", m_Name, m_Process.Pid()); + SignalShutdown(); + ZEN_DEBUG("Waiting for zenserver process {} ({}) to shut down", m_Name, m_Process.Pid()); + while (!m_Process.Wait(5000)) + { + ZEN_WARN("Waiting for zenserver process {} ({}) timed out", m_Name, m_Process.Pid()); + } } + ZEN_DEBUG("zenserver process {} ({}) exited", m_Name, m_Process.Pid()); + int ExitCode = m_Process.GetExitCode(); m_Process.Reset(); + return ExitCode; } - ZEN_DEBUG("zenserver process {} ({}) exited", m_Name, m_Process.Pid()); } else { + if (m_Process.Wait(0)) + { + int ExitCode = m_Process.GetExitCode(); + ZEN_DEBUG("zenserver process {} ({}) exited", m_Name, m_Process.Pid()); + m_Process.Reset(); + return ExitCode; + } ZEN_DEBUG("Detached from zenserver process {} ({})", m_Name, m_Process.Pid()); + return 0; } } + return -1; } void @@ -654,11 +673,9 @@ ZenServerInstance::SpawnServer(int BasePort, std::string_view AdditionalServerAr const std::filesystem::path BaseDir = m_Env.ProgramBaseDir(); const std::filesystem::path Executable = BaseDir / "zenserver" ZEN_EXE_SUFFIX_LITERAL; - CreateProcOptions CreateOptions = { - .WorkingDirectory = &CurrentDirectory, - .Flags = CreationFlags, - }; - CreateProcResult ChildPid = CreateProc(Executable, CommandLine.ToView(), CreateOptions); + const std::filesystem::path OutputPath = std::filesystem::temp_directory_path() / ("zenserver_" + m_Name + ".log"); + CreateProcOptions CreateOptions = {.WorkingDirectory = &CurrentDirectory, .Flags = CreationFlags, .StdoutFile = OutputPath}; + CreateProcResult ChildPid = CreateProc(Executable, CommandLine.ToView(), CreateOptions); #if ZEN_PLATFORM_WINDOWS if (!ChildPid && ::GetLastError() == ERROR_ELEVATION_REQUIRED) { @@ -688,7 +705,11 @@ ZenServerInstance::SpawnServer(int BasePort, std::string_view AdditionalServerAr { if (!WaitUntilReady(WaitTimeoutMs)) { - throw std::runtime_error(fmt::format("server start of {} timeout after {}", m_Name, NiceTimeSpanMs(WaitTimeoutMs))); + throw std::runtime_error(fmt::format("server start of {} {} after {}: {}", + m_Name, + m_Process.IsRunning() ? "timeout" : "crash", + NiceTimeSpanMs(WaitTimeoutMs), + GetLogOutput())); } } } @@ -762,10 +783,14 @@ ZenServerInstance::WaitUntilReady() { while (m_ReadyEvent.Wait(100) == false) { - if (!m_Process.IsRunning() || !m_Process.IsValid()) + if (!m_Process.IsValid()) { - ZEN_WARN("Wait abandoned by invalid process (running={})", m_Process.IsRunning()); - + ZEN_WARN("Wait abandoned by invalid process"); + return 0; + } + if (!m_Process.IsRunning()) + { + ZEN_WARN("Wait abandoned by exited process"); return 0; } } @@ -778,14 +803,30 @@ ZenServerInstance::WaitUntilReady() bool ZenServerInstance::WaitUntilReady(int Timeout) { - if (m_ReadyEvent.Wait(Timeout)) + int TimeoutLeftMS = Timeout; + while (m_ReadyEvent.Wait(100) == false) { - OnServerReady(); - - return true; + if (!m_Process.IsValid()) + { + ZEN_WARN("Wait abandoned by invalid process"); + return false; + } + if (!m_Process.IsRunning()) + { + ZEN_WARN("Wait abandoned by exited process"); + return false; + } + TimeoutLeftMS -= 100; + if ((TimeoutLeftMS <= 0)) + { + ZEN_WARN("Wait abandoned due to timeout"); + return false; + } } - return false; + OnServerReady(); + + return true; } void @@ -851,6 +892,26 @@ ZenServerInstance::IsRunning() return m_Process.IsRunning(); } +std::string +ZenServerInstance::GetLogOutput() const +{ + std::filesystem::path OutputPath = std::filesystem::temp_directory_path() / ("zenserver_" + m_Name + ".log"); + if (std::filesystem::is_regular_file(OutputPath)) + { + FileContents Contents = ReadFile(OutputPath); + if (!Contents.ErrorCode) + { + IoBuffer Content = Contents.Flatten(); + if (Content) + { + std::string Log((const char*)Content.Data(), Content.Size()); + return Log; + } + } + } + return {}; +} + bool ZenServerInstance::Terminate() { |