summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTiger Wang <ziwei.tiger@outlook.com>2021-04-21 17:07:48 +0200
committerGitHub <noreply@github.com>2021-04-21 17:07:48 +0200
commit1100b04b59b461f1a2cc3dfe7b53b5473daa7992 (patch)
treeef38a4a731e0c03c6f923708bac0249560ab611f
parentResets ticks alive on death (#5197) (diff)
downloadcuberite-1100b04b59b461f1a2cc3dfe7b53b5473daa7992.tar
cuberite-1100b04b59b461f1a2cc3dfe7b53b5473daa7992.tar.gz
cuberite-1100b04b59b461f1a2cc3dfe7b53b5473daa7992.tar.bz2
cuberite-1100b04b59b461f1a2cc3dfe7b53b5473daa7992.tar.lz
cuberite-1100b04b59b461f1a2cc3dfe7b53b5473daa7992.tar.xz
cuberite-1100b04b59b461f1a2cc3dfe7b53b5473daa7992.tar.zst
cuberite-1100b04b59b461f1a2cc3dfe7b53b5473daa7992.zip
-rw-r--r--CMake/AddDependencies.cmake4
-rw-r--r--src/Globals.h6
-rw-r--r--src/OSSupport/CMakeLists.txt4
-rw-r--r--src/OSSupport/ConsoleSignalHandler.h130
-rw-r--r--src/OSSupport/Errors.cpp53
-rw-r--r--src/OSSupport/Errors.h5
-rw-r--r--src/OSSupport/Event.cpp1
-rw-r--r--src/OSSupport/MiniDumpWriter.h137
-rw-r--r--src/OSSupport/SleepResolutionBooster.h66
-rw-r--r--src/OSSupport/StartAsService.h20
-rw-r--r--src/main.cpp203
11 files changed, 342 insertions, 287 deletions
diff --git a/CMake/AddDependencies.cmake b/CMake/AddDependencies.cmake
index e9f24db09..584fcb011 100644
--- a/CMake/AddDependencies.cmake
+++ b/CMake/AddDependencies.cmake
@@ -73,9 +73,9 @@ function(link_dependencies TARGET)
tolualib
)
- # Link process information library:
+ # Link process information, multimedia (for sleep resolution) libraries:
if (WIN32)
- target_link_libraries(${TARGET} PRIVATE Psapi.lib)
+ target_link_libraries(${TARGET} PRIVATE Psapi.lib Winmm.lib)
endif()
# Special case handling for libevent pthreads:
diff --git a/src/Globals.h b/src/Globals.h
index dc0bdc3ae..8da8c14c8 100644
--- a/src/Globals.h
+++ b/src/Globals.h
@@ -78,12 +78,14 @@
// OS-dependent stuff:
#ifdef _WIN32
+ #include <sdkddkver.h>
+
#define NOMINMAX // Windows SDK defines min and max macros, messing up with our std::min and std::max usage.
#define WIN32_LEAN_AND_MEAN
- #define _WIN32_WINNT 0x0501 // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher.
+ #define _WIN32_WINNT _WIN32_WINNT_WINXP // We want to target Windows XP with Service Pack 2 & Windows Server 2003 with Service Pack 1 and higher.
// Use CryptoAPI primitives when targeting a version that supports encrypting with AES-CFB8 smaller than a full block at a time.
- #define PLATFORM_CRYPTOGRAPHY (_WIN32_WINNT >= 0x0602)
+ #define PLATFORM_CRYPTOGRAPHY (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
#include <Windows.h>
#include <winsock2.h>
diff --git a/src/OSSupport/CMakeLists.txt b/src/OSSupport/CMakeLists.txt
index 42ce6934d..742bdcccf 100644
--- a/src/OSSupport/CMakeLists.txt
+++ b/src/OSSupport/CMakeLists.txt
@@ -2,7 +2,6 @@ target_sources(
${CMAKE_PROJECT_NAME} PRIVATE
CriticalSection.cpp
- Errors.cpp
Event.cpp
File.cpp
GZipFile.cpp
@@ -19,8 +18,8 @@ target_sources(
WinStackWalker.cpp
AtomicUniquePtr.h
+ ConsoleSignalHandler.h
CriticalSection.h
- Errors.h
Event.h
File.h
GetAddressInfoError.h
@@ -34,6 +33,7 @@ target_sources(
NetworkSingleton.h
Queue.h
ServerHandleImpl.h
+ SleepResolutionBooster.h
StackTrace.h
StartAsService.h
TCPLinkImpl.h
diff --git a/src/OSSupport/ConsoleSignalHandler.h b/src/OSSupport/ConsoleSignalHandler.h
new file mode 100644
index 000000000..23e63d555
--- /dev/null
+++ b/src/OSSupport/ConsoleSignalHandler.h
@@ -0,0 +1,130 @@
+
+// ConsoleSignalHandler.h
+
+// Intercepts signals for graceful CTRL-C (and others) handling.
+
+// This file MUST NOT be included from anywhere other than main.cpp.
+
+
+
+
+
+#include <csignal>
+
+
+
+
+
+// Because SIG_DFL or SIG_IGN could be NULL instead of nullptr, we need to disable the Clang warning here:
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-warning-option"
+#pragma clang diagnostic ignored "-Wunknown-pragmas"
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+
+static void NonCtrlHandler(int a_Signal)
+{
+ LOGD("Terminate event raised from std::signal");
+
+ switch (a_Signal)
+ {
+ case SIGSEGV:
+ {
+ PrintStackTrace();
+
+ LOGERROR(
+ "Failure report: \n\n"
+ " :( | Cuberite has encountered an error and needs to close\n"
+ " | SIGSEGV: Segmentation fault\n"
+ " |\n"
+#ifdef BUILD_ID
+ " | Cuberite " BUILD_SERIES_NAME " (id: " BUILD_ID ")\n"
+ " | from commit " BUILD_COMMIT_ID "\n"
+#endif
+ );
+
+ std::signal(SIGSEGV, SIG_DFL);
+ return;
+ }
+ case SIGABRT:
+#ifdef SIGABRT_COMPAT
+ case SIGABRT_COMPAT:
+#endif
+ {
+ PrintStackTrace();
+
+ LOGERROR(
+ "Failure report: \n\n"
+ " :( | Cuberite has encountered an error and needs to close\n"
+ " | SIGABRT: Server self-terminated due to an internal fault\n"
+ " |\n"
+#ifdef BUILD_ID
+ " | Cuberite " BUILD_SERIES_NAME " (id: " BUILD_ID ")\n"
+ " | from commit " BUILD_COMMIT_ID "\n"
+#endif
+ );
+
+ std::signal(SIGSEGV, SIG_DFL);
+ return;
+ }
+ case SIGINT:
+ case SIGTERM:
+ {
+ // Server is shutting down, wait for it...
+ cRoot::Stop();
+ return;
+ }
+ }
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+
+
+
+
+#ifdef _WIN32
+
+/** Handle CTRL events in windows, including console window close. */
+static BOOL CtrlHandler(DWORD fdwCtrlType)
+{
+ cRoot::Stop();
+ LOGD("Terminate event raised from the Windows CtrlHandler");
+
+ // Delay as much as possible to try to get the server to shut down cleanly - 10 seconds given by Windows:
+ std::this_thread::sleep_for(std::chrono::seconds(10));
+
+ // Returning from main() automatically aborts this handler thread.
+
+ return TRUE;
+}
+
+#endif
+
+
+
+
+
+namespace ConsoleSignalHandler
+{
+ static void Register()
+ {
+ std::signal(SIGSEGV, NonCtrlHandler);
+ std::signal(SIGTERM, NonCtrlHandler);
+ std::signal(SIGINT, NonCtrlHandler);
+ std::signal(SIGABRT, NonCtrlHandler);
+#ifdef SIGABRT_COMPAT
+ std::signal(SIGABRT_COMPAT, NonCtrlHandler);
+#endif
+#ifdef SIGPIPE
+ std::signal(SIGPIPE, SIG_IGN); // Ignore (PR #2487).
+#endif
+
+#ifdef _WIN32
+ SetConsoleCtrlHandler(reinterpret_cast<PHANDLER_ROUTINE>(CtrlHandler), TRUE);
+#endif
+ }
+};
diff --git a/src/OSSupport/Errors.cpp b/src/OSSupport/Errors.cpp
deleted file mode 100644
index df94d34da..000000000
--- a/src/OSSupport/Errors.cpp
+++ /dev/null
@@ -1,53 +0,0 @@
-
-#include "Globals.h"
-
-#include "Errors.h"
-
-AString GetOSErrorString( int a_ErrNo)
-{
- char buffer[ 1024 ];
- AString Out;
-
- #ifdef _WIN32
-
- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, a_ErrNo, 0, buffer, ARRAYCOUNT(buffer), nullptr);
- Printf(Out, "%d: %s", a_ErrNo, buffer);
- if (!Out.empty() && (Out[Out.length() - 1] == '\n'))
- {
- Out.erase(Out.length() - 2);
- }
- return Out;
-
- #else // _WIN32
-
- // According to https://linux.die.net/man/3/strerror_r there are two versions of strerror_r():
-
- #if defined(__GLIBC__) && defined( _GNU_SOURCE) // GNU version of strerror_r()
-
- char * res = strerror_r( errno, buffer, ARRAYCOUNT(buffer));
- if (res != nullptr)
- {
- Printf(Out, "%d: %s", a_ErrNo, res);
- return Out;
- }
-
- #else // XSI version of strerror_r():
-
- int res = strerror_r( errno, buffer, ARRAYCOUNT(buffer));
- if (res == 0)
- {
- Printf(Out, "%d: %s", a_ErrNo, buffer);
- return Out;
- }
-
- #endif // strerror_r() version
-
- else
- {
- Printf(Out, "Error %d while getting error string for error #%d!", errno, a_ErrNo);
- return Out;
- }
-
- #endif // else _WIN32
-}
-
diff --git a/src/OSSupport/Errors.h b/src/OSSupport/Errors.h
deleted file mode 100644
index 8ce9deb10..000000000
--- a/src/OSSupport/Errors.h
+++ /dev/null
@@ -1,5 +0,0 @@
-
-#pragma once
-
-AString GetOSErrorString(int a_ErrNo);
-
diff --git a/src/OSSupport/Event.cpp b/src/OSSupport/Event.cpp
index 4a16ddee7..623357766 100644
--- a/src/OSSupport/Event.cpp
+++ b/src/OSSupport/Event.cpp
@@ -7,7 +7,6 @@
#include "Globals.h" // NOTE: MSVC stupidness requires this to be the same across all modules
#include "Event.h"
-#include "Errors.h"
diff --git a/src/OSSupport/MiniDumpWriter.h b/src/OSSupport/MiniDumpWriter.h
index e5cd1a0ac..c223fa9fb 100644
--- a/src/OSSupport/MiniDumpWriter.h
+++ b/src/OSSupport/MiniDumpWriter.h
@@ -1,5 +1,11 @@
-#pragma once
+// MiniDumpWriter.h
+
+// 32-bit only:
+// When the server crashes, create a "dump file" containing the callstack of each thread and some variables;
+// let the user send us that crash file for analysis.
+
+// This file MUST NOT be included from anywhere other than main.cpp.
@@ -18,30 +24,64 @@ enum class MiniDumpFlags
#if defined(_WIN32) && !defined(_WIN64) && defined(_MSC_VER) // 32-bit Windows app compiled in MSVC
-#include <dbghelp.h>
+#include <DbgHelp.h>
+
+
+
+
+
+using MiniDumpWriteDumpFunction = decltype(&MiniDumpWriteDump);
+
+static HINSTANCE m_DbgHelp;
+static MiniDumpWriteDumpFunction s_WriteMiniDump; // The function in dbghlp DLL that creates dump files
+static wchar_t s_DumpFileName[MAX_PATH]; // Filename of the dump file; hes to be created before the dump handler kicks in
+static char s_ExceptionStack[128 * 1024]; // Substitute stack, just in case the handler kicks in because of "insufficient stack space"
+static MINIDUMP_TYPE s_DumpFlags = MiniDumpNormal; // By default dump only the stack and some helpers
+
+
+
+
+
+/** This function gets called just before the "program executed an illegal instruction and will be terminated" or similar.
+Its purpose is to create the crashdump using the dbghlp DLLs */
+static LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_ExceptionInfo)
+{
+ char * newStack = &s_ExceptionStack[sizeof(s_ExceptionStack) - 1];
+ char * oldStack;
+
+ // Use the substitute stack:
+ _asm
+ {
+ mov oldStack, esp
+ mov esp, newStack
+ }
+
+ MINIDUMP_EXCEPTION_INFORMATION ExcInformation;
+ ExcInformation.ThreadId = GetCurrentThreadId();
+ ExcInformation.ExceptionPointers = a_ExceptionInfo;
+ ExcInformation.ClientPointers = 0;
+
+ // Write the dump file:
+ HANDLE dumpFile = CreateFile(s_DumpFileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
+ s_WriteMiniDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, s_DumpFlags, (a_ExceptionInfo) ? &ExcInformation : nullptr, nullptr, nullptr);
+ CloseHandle(dumpFile);
+
+ // Revert to old stack:
+ _asm
+ {
+ mov esp, oldStack
+ }
+
+ return 0;
+}
-/** Windows 32-bit stuff:
-When the server crashes, create a "dump file" containing the callstack of each thread and some variables;
-let the user send us that crash file for analysis */
-class MiniDumpWriter
+namespace MiniDumpWriter
{
- typedef BOOL(WINAPI *pMiniDumpWriteDump)(
- HANDLE hProcess,
- DWORD ProcessId,
- HANDLE hFile,
- MINIDUMP_TYPE DumpType,
- PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
- PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
- PMINIDUMP_CALLBACK_INFORMATION CallbackParam
- );
-
-public:
-
- MiniDumpWriter()
+ static void Register()
{
// Magic code to produce dump-files on Windows if the server crashes:
@@ -51,7 +91,7 @@ public:
return;
}
- s_WriteMiniDump = (pMiniDumpWriteDump)GetProcAddress(m_DbgHelp, "MiniDumpWriteDump");
+ s_WriteMiniDump = (MiniDumpWriteDumpFunction)GetProcAddress(m_DbgHelp, "MiniDumpWriteDump");
if (s_WriteMiniDump != nullptr)
{
ASSERT(swprintf(s_DumpFileName, ARRAYCOUNT(s_DumpFileName), L"crash_mcs_%x.dmp", GetCurrentProcessId()) > 0);
@@ -61,7 +101,7 @@ public:
// End of dump-file magic
}
- void AddDumpFlags(const MiniDumpFlags a_Flags)
+ static void AddDumpFlags(const MiniDumpFlags a_Flags)
{
switch (a_Flags)
{
@@ -78,60 +118,25 @@ public:
}
}
- ~MiniDumpWriter()
+ static void Unregister()
{
FreeLibrary(m_DbgHelp);
}
+};
-private:
+#else
- /** This function gets called just before the "program executed an illegal instruction and will be terminated" or similar.
- Its purpose is to create the crashdump using the dbghlp DLLs */
- static LONG WINAPI LastChanceExceptionFilter(__in struct _EXCEPTION_POINTERS * a_ExceptionInfo)
+namespace MiniDumpWriter
+{
+ static void Register()
{
- char * newStack = &s_ExceptionStack[sizeof(s_ExceptionStack) - 1];
- char * oldStack;
-
- // Use the substitute stack:
- // This code is the reason why we don't support 64-bit (yet)
- _asm
- {
- mov oldStack, esp
- mov esp, newStack
- }
-
- MINIDUMP_EXCEPTION_INFORMATION ExcInformation;
- ExcInformation.ThreadId = GetCurrentThreadId();
- ExcInformation.ExceptionPointers = a_ExceptionInfo;
- ExcInformation.ClientPointers = 0;
-
- // Write the dump file:
- HANDLE dumpFile = CreateFile(s_DumpFileName, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
- s_WriteMiniDump(GetCurrentProcess(), GetCurrentProcessId(), dumpFile, s_DumpFlags, (a_ExceptionInfo) ? &ExcInformation : nullptr, nullptr, nullptr);
- CloseHandle(dumpFile);
-
- // Revert to old stack:
- _asm
- {
- mov esp, oldStack
- }
-
- return 0;
}
- HINSTANCE m_DbgHelp;
-
- static inline pMiniDumpWriteDump s_WriteMiniDump; // The function in dbghlp DLL that creates dump files
- static inline wchar_t s_DumpFileName[MAX_PATH]; // Filename of the dump file; hes to be created before the dump handler kicks in
- static inline char s_ExceptionStack[128 * 1024]; // Substitute stack, just in case the handler kicks in because of "insufficient stack space"
- static inline MINIDUMP_TYPE s_DumpFlags = MiniDumpNormal; // By default dump only the stack and some helpers
-};
-
-#else
+ static void AddDumpFlags(const MiniDumpFlags)
+ {
+ }
-struct MiniDumpWriter
-{
- void AddDumpFlags(const MiniDumpFlags)
+ static void Unregister()
{
}
};
diff --git a/src/OSSupport/SleepResolutionBooster.h b/src/OSSupport/SleepResolutionBooster.h
new file mode 100644
index 000000000..f090f6963
--- /dev/null
+++ b/src/OSSupport/SleepResolutionBooster.h
@@ -0,0 +1,66 @@
+
+// SleepResolutionBooster.h
+
+// Increases the accuracy of Sleep on Windows (GH #5140).
+
+// This file MUST NOT be included from anywhere other than main.cpp.
+
+
+
+
+
+#ifdef _WIN32
+
+#include <timeapi.h>
+
+
+
+
+
+static TIMECAPS g_Resolution;
+
+
+
+
+
+namespace SleepResolutionBooster
+{
+ static void Register()
+ {
+ // Default sleep resolution on Windows isn't accurate enough (GH #5140) so try to boost it:
+ if (
+ (timeGetDevCaps(&g_Resolution, sizeof(g_Resolution)) == MMSYSERR_NOERROR) &&
+ (timeBeginPeriod(g_Resolution.wPeriodMin) == MMSYSERR_NOERROR)
+ )
+ {
+ return;
+ }
+
+ // Max < Min sentinel for failure, to prevent bogus timeEndPeriod calls:
+ g_Resolution.wPeriodMax = 0;
+ g_Resolution.wPeriodMin = 1;
+ }
+
+ static void Unregister()
+ {
+ if (g_Resolution.wPeriodMax >= g_Resolution.wPeriodMin)
+ {
+ timeEndPeriod(g_Resolution.wPeriodMin);
+ }
+ }
+};
+
+#else
+
+namespace SleepResolutionBooster
+{
+ static void Register()
+ {
+ }
+
+ static void Unregister()
+ {
+ }
+};
+
+#endif
diff --git a/src/OSSupport/StartAsService.h b/src/OSSupport/StartAsService.h
index 472184367..fe078f303 100644
--- a/src/OSSupport/StartAsService.h
+++ b/src/OSSupport/StartAsService.h
@@ -1,19 +1,17 @@
-#pragma once
+// StartAsService.h
+// Handles startup as a Windows Service or UNIX daemon.
+// This file MUST NOT be included from anywhere other than main.cpp.
-#ifdef _WIN32
-
-#include <csignal>
-
-
+#ifdef _WIN32
-class cStartAsService
+class StartAsService
{
public:
@@ -79,7 +77,7 @@ private:
return;
}
- const auto LastComponent = wcsrchr(applicationFilename, L'\\');
+ const auto LastComponent = std::wcsrchr(applicationFilename, L'\\');
if (LastComponent == nullptr)
{
serviceSetState(0, SERVICE_STOPPED, E_UNEXPECTED);
@@ -89,7 +87,7 @@ private:
const auto LengthToLastComponent = LastComponent - applicationFilename;
// Strip off the filename, keep only the path:
- wcsncpy(applicationDirectory, applicationFilename, LengthToLastComponent);
+ std::wcsncpy(applicationDirectory, applicationFilename, LengthToLastComponent);
applicationDirectory[LengthToLastComponent] = L'\0'; // Make sure new path is null terminated
// Services are run by the SCM, and inherit its working directory - usually System32.
@@ -115,7 +113,7 @@ private:
char * MultibyteArgV[] = { MultibyteArgV0 };
const auto OutputSize = std::size(MultibyteArgV0);
- const auto TranslateResult = wcstombs(MultibyteArgV0, argv[0], OutputSize);
+ const auto TranslateResult = std::wcstombs(MultibyteArgV0, argv[0], OutputSize);
if (TranslateResult == static_cast<size_t>(-1))
{
@@ -141,7 +139,7 @@ private:
#else
-struct cStartAsService
+struct StartAsService
{
/** Make a UNIX daemon. */
template <auto>
diff --git a/src/main.cpp b/src/main.cpp
index f61971e08..dd84e3be4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -5,14 +5,14 @@
#include "BuildInfo.h"
#include "Logger.h"
#include "MemorySettingsRepository.h"
-#include "OSSupport/NetworkSingleton.h"
-#include "OSSupport/MiniDumpWriter.h"
-#include "OSSupport/StartAsService.h"
#include "Root.h"
#include "tclap/CmdLine.h"
-#include <csignal>
-#include <cstdlib>
+#include "OSSupport/ConsoleSignalHandler.h"
+#include "OSSupport/NetworkSingleton.h"
+#include "OSSupport/MiniDumpWriter.h"
+#include "OSSupport/SleepResolutionBooster.h"
+#include "OSSupport/StartAsService.h"
@@ -22,107 +22,6 @@ bool g_ShouldLogCommIn;
bool g_ShouldLogCommOut;
bool g_RunAsService;
-/** Global that registers itself as a last chance exception handler to write a minidump on crash. */
-static MiniDumpWriter g_MiniDumpWriter;
-
-
-
-
-
-// Because SIG_DFL or SIG_IGN could be NULL instead of nullptr, we need to disable the Clang warning here
-#ifdef __clang__
- #pragma clang diagnostic push
- #pragma clang diagnostic ignored "-Wunknown-warning-option"
- #pragma clang diagnostic ignored "-Wunknown-pragmas"
- #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
-#endif // __clang__
-
-static void NonCtrlHandler(int a_Signal)
-{
- LOGD("Terminate event raised from std::signal");
-
- switch (a_Signal)
- {
- case SIGSEGV:
- {
- PrintStackTrace();
-
- LOGERROR(
- "Failure report: \n\n"
- " :( | Cuberite has encountered an error and needs to close\n"
- " | SIGSEGV: Segmentation fault\n"
- " |\n"
-#ifdef BUILD_ID
- " | Cuberite " BUILD_SERIES_NAME " (id: " BUILD_ID ")\n"
- " | from commit " BUILD_COMMIT_ID "\n"
-#endif
- );
-
- std::signal(SIGSEGV, SIG_DFL);
- return;
- }
- case SIGABRT:
-#ifdef SIGABRT_COMPAT
- case SIGABRT_COMPAT:
-#endif
- {
- PrintStackTrace();
-
- LOGERROR(
- "Failure report: \n\n"
- " :( | Cuberite has encountered an error and needs to close\n"
- " | SIGABRT: Server self-terminated due to an internal fault\n"
- " |\n"
-#ifdef BUILD_ID
- " | Cuberite " BUILD_SERIES_NAME " (id: " BUILD_ID ")\n"
- " | from commit " BUILD_COMMIT_ID "\n"
-#endif
- );
-
- std::signal(SIGSEGV, SIG_DFL);
- return;
- }
- case SIGINT:
- case SIGTERM:
- {
- // Server is shutting down, wait for it...
- cRoot::Stop();
- return;
- }
-#ifdef SIGPIPE
- case SIGPIPE:
- {
- // Ignore (PR #2487)
- return;
- }
-#endif
- }
-}
-
-#ifdef __clang__
- #pragma clang diagnostic pop
-#endif // __clang__
-
-
-
-
-
-#ifdef _WIN32
-// Handle CTRL events in windows, including console window close
-static BOOL CtrlHandler(DWORD fdwCtrlType)
-{
- cRoot::Stop();
- LOGD("Terminate event raised from the Windows CtrlHandler");
-
- // Delay as much as possible to try to get the server to shut down cleanly - 10 seconds given by Windows
- std::this_thread::sleep_for(std::chrono::seconds(10));
-
- // Returning from main() automatically aborts this handler thread
-
- return TRUE;
-}
-#endif
-
@@ -130,7 +29,7 @@ static BOOL CtrlHandler(DWORD fdwCtrlType)
////////////////////////////////////////////////////////////////////////////////
// ParseArguments - Read the startup arguments and store into a settings object
-static void ParseArguments(int argc, char ** argv, cMemorySettingsRepository & Settings)
+static void ParseArguments(int argc, char ** argv, cMemorySettingsRepository & a_Settings)
{
// Parse the comand line args:
TCLAP::CmdLine cmd("Cuberite");
@@ -151,23 +50,23 @@ static void ParseArguments(int argc, char ** argv, cMemorySettingsRepository & S
if (confArg.isSet())
{
AString conf_file = confArg.getValue();
- Settings.AddValue("Server", "ConfigFile", conf_file);
+ a_Settings.AddValue("Server", "ConfigFile", conf_file);
}
if (slotsArg.isSet())
{
int slots = slotsArg.getValue();
- Settings.AddValue("Server", "MaxPlayers", static_cast<Int64>(slots));
+ a_Settings.AddValue("Server", "MaxPlayers", static_cast<Int64>(slots));
}
if (portsArg.isSet())
{
for (auto port: portsArg.getValue())
{
- Settings.AddValue("Server", "Ports", std::to_string(port));
+ a_Settings.AddValue("Server", "Ports", std::to_string(port));
}
}
if (noFileLogArg.getValue())
{
- Settings.AddValue("Server", "DisableLogFile", true);
+ a_Settings.AddValue("Server", "DisableLogFile", true);
}
if (commLogArg.getValue())
{
@@ -183,7 +82,7 @@ static void ParseArguments(int argc, char ** argv, cMemorySettingsRepository & S
{
setvbuf(stdout, nullptr, _IONBF, 0);
}
- Settings.SetReadOnly();
+ a_Settings.SetReadOnly();
if (runAsServiceArg.getValue())
{
@@ -193,11 +92,11 @@ static void ParseArguments(int argc, char ** argv, cMemorySettingsRepository & S
// Apply the CrashDump flags for platforms that support them:
if (crashDumpGlobals.getValue())
{
- g_MiniDumpWriter.AddDumpFlags(MiniDumpFlags::WithDataSegments);
+ MiniDumpWriter::AddDumpFlags(MiniDumpFlags::WithDataSegments);
}
if (crashDumpFull.getValue())
{
- g_MiniDumpWriter.AddDumpFlags(MiniDumpFlags::WithFullMemory);
+ MiniDumpWriter::AddDumpFlags(MiniDumpFlags::WithFullMemory);
}
}
@@ -208,36 +107,52 @@ static void ParseArguments(int argc, char ** argv, cMemorySettingsRepository & S
////////////////////////////////////////////////////////////////////////////////
// UniversalMain - Main startup logic for both standard running and as a service
-static int UniversalMain(int argc, char * argv[], bool RunningAsService)
+static int UniversalMain(int argc, char * argv[], const bool a_RunningAsService)
{
- // Initialize logging subsystem:
- cLogger::InitiateMultithreading();
+ const struct MiniDumpWriterRAII
+ {
+ MiniDumpWriterRAII()
+ {
+ // Registers a last chance exception handler to write a minidump on crash:
+ MiniDumpWriter::Register();
+ }
- struct NetworkRAII
+ ~MiniDumpWriterRAII()
+ {
+ MiniDumpWriter::Unregister();
+ }
+ } MiniDumpWriter;
+
+ const struct SleepResolutionBoosterRAII
{
- NetworkRAII()
+ SleepResolutionBoosterRAII()
{
- // Initialize LibEvent:
- cNetworkSingleton::Get().Initialise();
+ // Boost timer resolution to keep TPS high:
+ SleepResolutionBooster::Register();
}
- ~NetworkRAII()
+ ~SleepResolutionBoosterRAII()
{
- // Shutdown all of LibEvent:
- cNetworkSingleton::Get().Terminate();
+ SleepResolutionBooster::Unregister();
}
- };
+ } SleepResolutionBooster;
+
+ // Register signal handlers, enabling graceful shutdown from the terminal:
+ ConsoleSignalHandler::Register();
+
+ // Initialize logging subsystem:
+ cLogger::InitiateMultithreading();
try
{
cMemorySettingsRepository Settings;
- ParseArguments(argc, argv, Settings); // Make sure g_RunAsService is set correctly before checking it's value
+ ParseArguments(argc, argv, Settings); // Make sure g_RunAsService is set correctly before checking its value.
// Attempt to run as a service:
- if (!RunningAsService && g_RunAsService)
+ if (g_RunAsService && !a_RunningAsService)
{
// This will either fork or call UniversalMain again:
- if (cStartAsService::MakeIntoService<&UniversalMain>())
+ if (StartAsService::MakeIntoService<&UniversalMain>())
{
return EXIT_SUCCESS;
}
@@ -245,9 +160,22 @@ static int UniversalMain(int argc, char * argv[], bool RunningAsService)
while (true)
{
- NetworkRAII LibEvent;
- cRoot Root;
+ const struct NetworkRAII
+ {
+ NetworkRAII()
+ {
+ // Initialize LibEvent:
+ cNetworkSingleton::Get().Initialise();
+ }
+
+ ~NetworkRAII()
+ {
+ // Shutdown all of LibEvent:
+ cNetworkSingleton::Get().Terminate();
+ }
+ } LibEvent;
+ cRoot Root;
if (!Root.Run(Settings))
{
break;
@@ -291,20 +219,5 @@ int main(int argc, char ** argv)
#endif // !NDEBUG && _MSC_VER
- std::signal(SIGSEGV, NonCtrlHandler);
- std::signal(SIGTERM, NonCtrlHandler);
- std::signal(SIGINT, NonCtrlHandler);
- std::signal(SIGABRT, NonCtrlHandler);
-#ifdef SIGABRT_COMPAT
- std::signal(SIGABRT_COMPAT, NonCtrlHandler);
-#endif
-#ifdef SIGPIPE
- std::signal(SIGPIPE, SIG_IGN);
-#endif
-
-#ifdef _WIN32
- VERIFY(SetConsoleCtrlHandler(reinterpret_cast<PHANDLER_ROUTINE>(CtrlHandler), TRUE) == TRUE);
-#endif
-
return UniversalMain(argc, argv, false);
}