mirror of
https://bitbucket.org/CPMADevs/cnq3
synced 2024-12-11 13:02:23 +00:00
158 lines
4.3 KiB
C++
158 lines
4.3 KiB
C++
/*
|
|
===========================================================================
|
|
Copyright (C) 1999-2005 Id Software, Inc.
|
|
|
|
This file is part of Quake III Arena source code.
|
|
|
|
Quake III Arena source code is free software; you can redistribute it
|
|
and/or modify it under the terms of the GNU General Public License as
|
|
published by the Free Software Foundation; either version 2 of the License,
|
|
or (at your option) any later version.
|
|
|
|
Quake III Arena source code is distributed in the hope that it will be
|
|
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Quake III Arena source code; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
===========================================================================
|
|
*/
|
|
#include <signal.h>
|
|
|
|
#include "../qcommon/q_shared.h"
|
|
#include "../qcommon/qcommon.h"
|
|
#ifndef DEDICATED
|
|
#include "../renderer/tr_local.h"
|
|
#endif
|
|
#include "linux_local.h"
|
|
|
|
|
|
// columns: Symbol, IsCrash, Desc
|
|
#define SIGNAL_LIST(X) \
|
|
X(SIGHUP, qfalse, "hangup detected on controlling terminal or death of controlling process") \
|
|
X(SIGQUIT, qfalse, "quit from keyboard") \
|
|
X(SIGILL, qtrue, "illegal instruction") \
|
|
X(SIGTRAP, qfalse, "trace/breakpoint trap") \
|
|
X(SIGIOT, qtrue, "IOT trap (a synonym for SIGABRT)") \
|
|
X(SIGBUS, qtrue, "bus error (bad memory access)") \
|
|
X(SIGFPE, qtrue, "fatal arithmetic error") \
|
|
X(SIGSEGV, qtrue, "invalid memory reference") \
|
|
X(SIGTERM, qfalse, "termination signal") \
|
|
X(SIGINT, qfalse, "interrupt")
|
|
|
|
|
|
static qboolean Sig_IsCrashSignal(int sig)
|
|
{
|
|
#define SIGNAL_ITEM(Symbol, IsCrash, Desc) case Symbol: return IsCrash;
|
|
switch (sig) {
|
|
SIGNAL_LIST(SIGNAL_ITEM)
|
|
default: return qfalse;
|
|
}
|
|
#undef SIGNAL_ITEM
|
|
}
|
|
|
|
|
|
static const char* Sig_GetDescription(int sig)
|
|
{
|
|
#define SIGNAL_ITEM(Symbol, IsCrash, Desc) case Symbol: return Desc;
|
|
switch (sig) {
|
|
SIGNAL_LIST(SIGNAL_ITEM)
|
|
default: return "unhandled signal";
|
|
}
|
|
#undef SIGNAL_ITEM
|
|
}
|
|
|
|
|
|
static const char* Sig_GetName(int sig)
|
|
{
|
|
#define SIGNAL_ITEM(Symbol, IsCrash, Desc) case Symbol: return #Symbol;
|
|
switch (sig) {
|
|
SIGNAL_LIST(SIGNAL_ITEM)
|
|
default: return "unhandled signal";
|
|
}
|
|
#undef SIGNAL_ITEM
|
|
}
|
|
|
|
|
|
// Every call in there needs to be safe when called more than once.
|
|
static void SIG_HandleCrash()
|
|
{
|
|
// We crashed and only care about restoring system settings
|
|
// that the process clean-up won't handle for us.
|
|
#ifndef DEDICATED
|
|
LIN_RestoreGamma();
|
|
#endif
|
|
}
|
|
|
|
|
|
static void Sig_HandleSignal(int sig)
|
|
{
|
|
static int faultCounter = 0;
|
|
static qbool crashHandled = qfalse;
|
|
|
|
faultCounter++;
|
|
|
|
if (faultCounter >= 3)
|
|
{
|
|
// We're here because the double fault handler failed.
|
|
// We take no chances this time and exit right away to avoid
|
|
// calling this function many more times.
|
|
exit(3);
|
|
}
|
|
|
|
const qbool crashed = Sig_IsCrashSignal(sig);
|
|
if (faultCounter == 2)
|
|
{
|
|
// The termination handler failed which means that if we exit right now,
|
|
// some system settings might still be in a bad state.
|
|
printf("DOUBLE SIGNAL FAULT: Received signal %d (%s), exiting...\n", sig, Sig_GetName(sig));
|
|
if (crashed && !crashHandled)
|
|
{
|
|
SIG_HandleCrash();
|
|
}
|
|
exit(2);
|
|
}
|
|
|
|
fprintf(crashed ? stderr : stdout, "Received %s signal %d: %s (%s), exiting...\n",
|
|
crashed ? "crash" : "termination", sig, Sig_GetName(sig), Sig_GetDescription(sig));
|
|
|
|
if (crashed)
|
|
{
|
|
SIG_HandleCrash();
|
|
crashHandled = qtrue;
|
|
exit(1);
|
|
}
|
|
else
|
|
{
|
|
// attempt a proper shutdown sequence
|
|
#ifndef DEDICATED
|
|
CL_Shutdown();
|
|
#endif
|
|
SV_Shutdown("Signal caught");
|
|
Sys_Exit(0);
|
|
}
|
|
}
|
|
|
|
|
|
void SIG_Init(void)
|
|
{
|
|
// This is unfortunately needed because some code might
|
|
// call exit and bypass all the clean-up work without
|
|
// there ever being a real crash.
|
|
// This happens for instance with the "fatal IO error"
|
|
// of the X server.
|
|
atexit(SIG_HandleCrash);
|
|
|
|
signal(SIGILL, Sig_HandleSignal);
|
|
signal(SIGIOT, Sig_HandleSignal);
|
|
signal(SIGBUS, Sig_HandleSignal);
|
|
signal(SIGFPE, Sig_HandleSignal);
|
|
signal(SIGSEGV, Sig_HandleSignal);
|
|
signal(SIGHUP, Sig_HandleSignal);
|
|
signal(SIGQUIT, Sig_HandleSignal);
|
|
signal(SIGTRAP, Sig_HandleSignal);
|
|
signal(SIGTERM, Sig_HandleSignal);
|
|
signal(SIGINT, Sig_HandleSignal);
|
|
}
|