summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2014-12-03 13:28:16 +0300
committerAndrey Nazarov <skuller@skuller.net>2014-12-03 18:33:25 +0300
commit924ff39aa48df1d6cd985b42a2fe5a60ff154030 (patch)
tree79dc211425cf4689ec56308fb93c4f4bbc17d464
parent7525450fb6d79d7371375d7f710ba4fe484494b3 (diff)
Stop fiddling around with jmp_buf.
Implement custom abort function handler for cleaning up CM after failed server startup. Less hacky and more portable than previous solution that involved swapping copies of jmp_buf around. Fixes a weird Win64 crash when loading savegames.
-rw-r--r--inc/common/common.h5
-rw-r--r--src/common/common.c19
-rw-r--r--src/server/commands.c22
-rw-r--r--src/server/mvd/client.h3
-rw-r--r--src/server/mvd/game.c2
-rw-r--r--src/server/save.c21
6 files changed, 42 insertions, 30 deletions
diff --git a/inc/common/common.h b/inc/common/common.h
index 643a9f1..1ed0a20 100644
--- a/inc/common/common.h
+++ b/inc/common/common.h
@@ -21,7 +21,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "common/cmd.h"
#include "common/utils.h"
-#include <setjmp.h>
//
// common.h -- definitions common between client and server, but not game.dll
@@ -83,6 +82,8 @@ typedef void (*rdflush_t)(int target, char *buffer, size_t len);
void Com_BeginRedirect(int target, char *buffer, size_t buffersize, rdflush_t flush);
void Com_EndRedirect(void);
+void Com_AbortFunc(void (*func)(void *), void *arg);
+
#ifdef _WIN32
void Com_AbortFrame(void);
#endif
@@ -175,8 +176,6 @@ extern unsigned time_before_ref;
extern unsigned time_after_ref;
#endif
-extern jmp_buf com_abortframe;
-
extern const char com_version_string[];
extern unsigned com_framenum;
diff --git a/src/common/common.c b/src/common/common.c
index 48a82ea..a136c43 100644
--- a/src/common/common.c
+++ b/src/common/common.c
@@ -49,7 +49,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "server/server.h"
#include "system/system.h"
-jmp_buf com_abortframe; // an ERR_DROP occured, exit the entire frame
+#include <setjmp.h>
+
+static jmp_buf com_abortframe; // an ERR_DROP occured, exit the entire frame
+
+static void (*com_abort_func)(void *);
+static void *com_abort_arg;
static qboolean com_errorEntered;
static char com_errorMsg[MAXERRORMSG]; // from Com_Printf/Com_Error
@@ -509,6 +514,12 @@ void Com_Error(error_type_t code, const char *fmt, ...)
// abort any console redirects
Com_AbortRedirect();
+ // call custom cleanup function if set
+ if (com_abort_func) {
+ com_abort_func(com_abort_arg);
+ com_abort_func = NULL;
+ }
+
// reset Com_Printf recursion level
com_printEntered = 0;
@@ -562,6 +573,12 @@ abort:
longjmp(com_abortframe, -1);
}
+void Com_AbortFunc(void (*func)(void *), void *arg)
+{
+ com_abort_func = func;
+ com_abort_arg = arg;
+}
+
#ifdef _WIN32
void Com_AbortFrame(void)
{
diff --git a/src/server/commands.c b/src/server/commands.c
index 09a7990..b5c09fe 100644
--- a/src/server/commands.c
+++ b/src/server/commands.c
@@ -257,11 +257,16 @@ another level:
map tram.cin+jail_e3
======================
*/
+
+static void abort_func(void *arg)
+{
+ CM_FreeMap(arg);
+}
+
static void SV_Map(qboolean restart)
{
mapcmd_t cmd;
size_t len;
- jmp_buf tmp;
memset(&cmd, 0, sizeof(cmd));
@@ -275,15 +280,8 @@ static void SV_Map(qboolean restart)
if (!SV_ParseMapCmd(&cmd))
return;
- // save error frame
- memcpy(tmp, com_abortframe, sizeof(jmp_buf));
-
- // catch ERR_DROP and free the map
- if (setjmp(com_abortframe)) {
- memcpy(com_abortframe, tmp, sizeof(jmp_buf));
- CM_FreeMap(&cmd.cm);
- return;
- }
+ // save pending CM to be freed later if ERR_DROP is thrown
+ Com_AbortFunc(abort_func, &cmd.cm);
// wipe savegames
cmd.endofunit |= restart;
@@ -294,8 +292,8 @@ static void SV_Map(qboolean restart)
if ((sv.state != ss_game && sv.state != ss_pic) || restart)
SV_InitGame(MVD_SPAWN_DISABLED); // the game is just starting
- // restore error frame
- memcpy(com_abortframe, tmp, sizeof(jmp_buf));
+ // clear pending CM
+ Com_AbortFunc(NULL, NULL);
SV_SpawnServer(&cmd);
diff --git a/src/server/mvd/client.h b/src/server/mvd/client.h
index f2ec522..278fb3f 100644
--- a/src/server/mvd/client.h
+++ b/src/server/mvd/client.h
@@ -17,6 +17,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "../server.h"
+#include <setjmp.h>
#define MVD_Malloc(size) Z_TagMalloc(size, TAG_MVD)
#define MVD_Mallocz(size) Z_TagMallocz(size, TAG_MVD)
@@ -187,6 +188,8 @@ extern qboolean mvd_dirty;
extern qboolean mvd_active;
extern unsigned mvd_last_activity;
+extern jmp_buf mvd_jmpbuf;
+
#ifdef _DEBUG
extern cvar_t *mvd_shownet;
#endif
diff --git a/src/server/mvd/game.c b/src/server/mvd/game.c
index 41eb7e1..db18ef4 100644
--- a/src/server/mvd/game.c
+++ b/src/server/mvd/game.c
@@ -38,8 +38,6 @@ mvd_client_t *mvd_clients;
mvd_player_t mvd_dummy;
-extern jmp_buf mvd_jmpbuf;
-
static int mvd_numplayers;
static void MVD_UpdateClient(mvd_client_t *client);
diff --git a/src/server/save.c b/src/server/save.c
index a5d8eaf..4413cee 100644
--- a/src/server/save.c
+++ b/src/server/save.c
@@ -304,12 +304,16 @@ char *SV_GetSaveInfo(const char *dir)
return Z_CopyString(va("%s %s", date, name));
}
+static void abort_func(void *arg)
+{
+ CM_FreeMap(arg);
+}
+
static int read_server_file(void)
{
char name[MAX_OSPATH], string[MAX_STRING_CHARS];
mapcmd_t cmd;
size_t len;
- jmp_buf tmp;
// errors like missing file, bad version, etc are
// non-fatal and just return to the command handler
@@ -342,15 +346,8 @@ static int read_server_file(void)
if (!SV_ParseMapCmd(&cmd))
return -1;
- // save error frame
- memcpy(tmp, com_abortframe, sizeof(jmp_buf));
-
- // catch ERR_DROP and free the map
- if (setjmp(com_abortframe)) {
- memcpy(com_abortframe, tmp, sizeof(jmp_buf));
- CM_FreeMap(&cmd.cm);
- return -1;
- }
+ // save pending CM to be freed later if ERR_DROP is thrown
+ Com_AbortFunc(abort_func, &cmd.cm);
// any error will drop from this point
SV_Shutdown("Server restarted\n", ERR_RECONNECT);
@@ -389,8 +386,8 @@ static int read_server_file(void)
ge->ReadGame(name);
- // restore error frame
- memcpy(com_abortframe, tmp, sizeof(jmp_buf));
+ // clear pending CM
+ Com_AbortFunc(NULL, NULL);
// go to the map
SV_SpawnServer(&cmd);