+ // prepare the dialogtext: signal, backtrace, version
+ // the dp_st* funcs are POSIX async-signal-safe IF we don't trigger their warnings
+ dp_strlcpy(dialogtext, sigdesc, sizeof(dialogtext));
+ dp_strlcat(dialogtext, "\n\n", sizeof(dialogtext));
+#if __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1
+ btstrings = backtrace_symbols(stackframes + 2, framecount - 2); // calls malloc :(
+ if (btstrings)
+ for (int i = 0; i < framecount - 2; ++i)
+ {
+ dp_strlcat(dialogtext, btstrings[i], sizeof(dialogtext));
+ dp_strlcat(dialogtext, "\n", sizeof(dialogtext));
+ }
+#endif
+ dp_strlcat(dialogtext, "\n", sizeof(dialogtext));
+ dp_strlcat(dialogtext, engineversion, sizeof(dialogtext));
+
+ host.state = host_failed; // make Sys_HandleSignal() call _Exit()
+ Sys_SDL_Dialog("Engine Crash", dialogtext);
+
+ fflush(stderr); // not async-signal-safe :(
+
+ // Continue execution with default signal handling.
+ // A real crash will be re-triggered so the platform can handle it,
+ // a fake crash (kill -SEGV) will cause a graceful shutdown.
+ signal(sig, SIG_DFL);
+}
+
+static void Sys_HandleSignal(int sig)
+{
+ const char *sigdesc;
+
+ // Break any loop, eg if each Sys_Print triggers a SIGPIPE
+ if (host.state == host_shutdown || host.state == host_failing)
+ return;
+
+ sigdesc = Sys_SigDesc(sig);
+ Sys_Print("\nReceived ", 10);
+ Sys_Print(sigdesc, strlen(sigdesc));
+ Sys_Print(" signal, exiting...\n", 20);
+ if (host.state == host_failed)
+ {
+ // user is trying to kill the process while the SDL dialog is open
+ fflush(stderr); // not async-signal-safe :(
+ _Exit(sig);
+ }
+ host.state = host_shutdown;
+}
+
+/// SDL2 only handles SIGINT and SIGTERM by default and doesn't log anything
+static void Sys_InitSignals(void)
+{
+ // Windows only supports the C99 signals
+ signal(SIGINT, Sys_HandleSignal);
+ signal(SIGILL, Sys_HandleCrash);
+ signal(SIGABRT, Sys_HandleCrash);
+ signal(SIGFPE, Sys_HandleCrash);
+ signal(SIGSEGV, Sys_HandleCrash);
+ signal(SIGTERM, Sys_HandleSignal);
+#ifndef WIN32
+ // POSIX has several others worth catching
+ signal(SIGHUP, Sys_HandleSignal);
+ signal(SIGQUIT, Sys_HandleSignal);
+ signal(SIGBUS, Sys_HandleCrash);
+ signal(SIGPIPE, Sys_HandleSignal);
+#endif
+}
+
+/** main() but renamed so we can wrap it in sys_sdl.c and sys_null.c
+ * to avoid needing to include SDL.h in this file (would make the dedicated server require SDL).
+ * SDL builds need SDL.h in the file where main() is defined because SDL renames and wraps main().
+ */
+int Sys_Main(int argc, char *argv[])
+{