aboutsummaryrefslogtreecommitdiff
path: root/src/zenutil/zenserverprocess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/zenutil/zenserverprocess.cpp')
-rw-r--r--src/zenutil/zenserverprocess.cpp105
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()
{