mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-11 13:10:45 +00:00
(svn r2906) Fix some threaded saving problems. Now the thread only interfaces with the main program through a sort of mutex. Communication uses the function OTTD_SendThreadMessage() with the approiate message which is handled in ProcessSentMessage() during the main loop.
This commit is contained in:
parent
acf442102a
commit
a948fcb605
@ -276,4 +276,5 @@ int ttd_main(int argc, char* argv[]);
|
|||||||
void DeterminePaths(void);
|
void DeterminePaths(void);
|
||||||
|
|
||||||
void bubblesort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
|
void bubblesort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
|
||||||
|
void CSleep(int milliseconds);
|
||||||
#endif /* FUNCTIONS_H */
|
#endif /* FUNCTIONS_H */
|
||||||
|
@ -207,7 +207,6 @@ VARDEF uint8 _network_autoclean_protected; // Unprotect a company after X mont
|
|||||||
VARDEF uint16 _network_restart_game_date; // If this year is reached, the server automaticly restarts
|
VARDEF uint16 _network_restart_game_date; // If this year is reached, the server automaticly restarts
|
||||||
|
|
||||||
NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info);
|
NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info);
|
||||||
void CSleep(int milliseconds);
|
|
||||||
|
|
||||||
#endif /* ENABLE_NETWORK */
|
#endif /* ENABLE_NETWORK */
|
||||||
|
|
||||||
|
36
openttd.c
36
openttd.c
@ -542,6 +542,38 @@ int ttd_main(int argc, char* argv[])
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Mutex so that only one thread can communicate with the main program
|
||||||
|
* at any given time */
|
||||||
|
static ThreadMsg _message = 0;
|
||||||
|
|
||||||
|
static inline void OTTD_ReleaseMutex(void) {_message = 0;}
|
||||||
|
static inline ThreadMsg OTTD_PollThreadEvent(void) {return _message;}
|
||||||
|
|
||||||
|
/** Called by running thread to execute some action in the main game.
|
||||||
|
* It will stall as long as the mutex is not freed (handled) by the game */
|
||||||
|
void OTTD_SendThreadMessage(ThreadMsg msg)
|
||||||
|
{
|
||||||
|
while (_message != 0) CSleep(10);
|
||||||
|
|
||||||
|
_message = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Handle the user-messages sent to us
|
||||||
|
* @param message message sent
|
||||||
|
*/
|
||||||
|
void ProcessSentMessage(ThreadMsg message)
|
||||||
|
{
|
||||||
|
switch (message) {
|
||||||
|
case MSG_OTTD_SAVETHREAD_START: SaveFileStart(); break;
|
||||||
|
case MSG_OTTD_SAVETHREAD_DONE: SaveFileDone(); break;
|
||||||
|
case MSG_OTTD_SAVETHREAD_ERROR: SaveFileError(); break;
|
||||||
|
default: NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
OTTD_ReleaseMutex(); // release mutex so that other threads, messages can be handled
|
||||||
|
}
|
||||||
|
|
||||||
static void ShowScreenshotResult(bool b)
|
static void ShowScreenshotResult(bool b)
|
||||||
{
|
{
|
||||||
if (b) {
|
if (b) {
|
||||||
@ -914,6 +946,10 @@ static void HandleKeyScrolling(void)
|
|||||||
void GameLoop(void)
|
void GameLoop(void)
|
||||||
{
|
{
|
||||||
int m;
|
int m;
|
||||||
|
ThreadMsg message;
|
||||||
|
|
||||||
|
|
||||||
|
if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message);
|
||||||
|
|
||||||
// autosave game?
|
// autosave game?
|
||||||
if (_do_autosave) {
|
if (_do_autosave) {
|
||||||
|
11
openttd.h
11
openttd.h
@ -543,4 +543,15 @@ enum {
|
|||||||
};
|
};
|
||||||
VARDEF byte _no_scroll;
|
VARDEF byte _no_scroll;
|
||||||
|
|
||||||
|
/** To have a concurrently running thread interface with the main program, use
|
||||||
|
* the OTTD_SendThreadMessage() function. Actions to perform upon the message are handled
|
||||||
|
* in the ProcessSentMessage() function */
|
||||||
|
typedef enum ThreadMsgs {
|
||||||
|
MSG_OTTD_SAVETHREAD_START = 1,
|
||||||
|
MSG_OTTD_SAVETHREAD_DONE = 2,
|
||||||
|
MSG_OTTD_SAVETHREAD_ERROR = 3,
|
||||||
|
} ThreadMsg;
|
||||||
|
|
||||||
|
void OTTD_SendThreadMessage(ThreadMsg msg);
|
||||||
|
|
||||||
#endif /* OPENTTD_H */
|
#endif /* OPENTTD_H */
|
||||||
|
28
saveload.c
28
saveload.c
@ -1255,7 +1255,7 @@ static inline SaveOrLoadResult AbortSaveLoad(void)
|
|||||||
/** Update the gui accordingly when starting saving
|
/** Update the gui accordingly when starting saving
|
||||||
* and set locks on saveload. Also turn off fast-forward cause with that
|
* and set locks on saveload. Also turn off fast-forward cause with that
|
||||||
* saving takes Aaaaages */
|
* saving takes Aaaaages */
|
||||||
static inline void SaveFileStart(void)
|
void SaveFileStart(void)
|
||||||
{
|
{
|
||||||
_ts.ff_state = _fast_forward;
|
_ts.ff_state = _fast_forward;
|
||||||
_fast_forward = false;
|
_fast_forward = false;
|
||||||
@ -1267,7 +1267,7 @@ static inline void SaveFileStart(void)
|
|||||||
|
|
||||||
/** Update the gui accordingly when saving is done and release locks
|
/** Update the gui accordingly when saving is done and release locks
|
||||||
* on saveload */
|
* on saveload */
|
||||||
static inline void SaveFileDone(void)
|
void SaveFileDone(void)
|
||||||
{
|
{
|
||||||
_fast_forward = _ts.ff_state;
|
_fast_forward = _ts.ff_state;
|
||||||
if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
|
if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
|
||||||
@ -1276,10 +1276,17 @@ static inline void SaveFileDone(void)
|
|||||||
_ts.saveinprogress = false;
|
_ts.saveinprogress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Show a gui message when saving has failed */
|
||||||
|
void SaveFileError(void)
|
||||||
|
{
|
||||||
|
ShowErrorMessage(STR_4007_GAME_SAVE_FAILED, STR_NULL, 0, 0);
|
||||||
|
SaveFileDone();
|
||||||
|
}
|
||||||
|
|
||||||
/** We have written the whole game into memory, _save_pool, now find
|
/** We have written the whole game into memory, _save_pool, now find
|
||||||
* and appropiate compressor and start writing to file.
|
* and appropiate compressor and start writing to file.
|
||||||
*/
|
*/
|
||||||
static void* SaveFileToDisk(void* arg)
|
static void* SaveFileToDisk(void *arg)
|
||||||
{
|
{
|
||||||
const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format);
|
const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format);
|
||||||
/* XXX - backup _sl.buf cause it is used internally by the writer
|
/* XXX - backup _sl.buf cause it is used internally by the writer
|
||||||
@ -1287,6 +1294,8 @@ static void* SaveFileToDisk(void* arg)
|
|||||||
static byte *tmp = NULL;
|
static byte *tmp = NULL;
|
||||||
uint32 hdr[2];
|
uint32 hdr[2];
|
||||||
|
|
||||||
|
OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_START);
|
||||||
|
|
||||||
tmp = _sl.buf;
|
tmp = _sl.buf;
|
||||||
|
|
||||||
/* XXX - Setup setjmp error handler if an error occurs anywhere deep during
|
/* XXX - Setup setjmp error handler if an error occurs anywhere deep during
|
||||||
@ -1297,9 +1306,7 @@ static void* SaveFileToDisk(void* arg)
|
|||||||
_sl.excpt_uninit();
|
_sl.excpt_uninit();
|
||||||
|
|
||||||
ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
|
ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
|
||||||
ShowErrorMessage(STR_4007_GAME_SAVE_FAILED, STR_NULL, 0, 0);
|
OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
|
||||||
|
|
||||||
SaveFileDone();
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1334,7 +1341,7 @@ static void* SaveFileToDisk(void* arg)
|
|||||||
GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
|
GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
|
||||||
fclose(_sl.fh);
|
fclose(_sl.fh);
|
||||||
|
|
||||||
SaveFileDone();
|
OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1405,10 +1412,10 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode)
|
|||||||
if (mode == SL_LOAD) {
|
if (mode == SL_LOAD) {
|
||||||
ShowInfoF("Load game failed: %s.", _sl.excpt_msg);
|
ShowInfoF("Load game failed: %s.", _sl.excpt_msg);
|
||||||
return SL_REINIT;
|
return SL_REINIT;
|
||||||
} else {
|
|
||||||
ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
|
|
||||||
return SL_ERROR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
|
||||||
|
return SL_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We first initialize here to avoid: "warning: variable `version' might
|
/* We first initialize here to avoid: "warning: variable `version' might
|
||||||
@ -1434,7 +1441,6 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode)
|
|||||||
SlWriteFill(); // flush the save buffer
|
SlWriteFill(); // flush the save buffer
|
||||||
|
|
||||||
/* Write to file */
|
/* Write to file */
|
||||||
SaveFileStart();
|
|
||||||
if (_network_server ||
|
if (_network_server ||
|
||||||
(save_thread = OTTDCreateThread(&SaveFileToDisk, NULL)) == NULL) {
|
(save_thread = OTTDCreateThread(&SaveFileToDisk, NULL)) == NULL) {
|
||||||
DEBUG(misc, 1) ("cannot create savegame thread, reverting to single-threaded mode...");
|
DEBUG(misc, 1) ("cannot create savegame thread, reverting to single-threaded mode...");
|
||||||
|
@ -172,4 +172,7 @@ void SlSetLength(size_t length);
|
|||||||
void SlWriteByte(byte b);
|
void SlWriteByte(byte b);
|
||||||
void SlGlobList(const SaveLoadGlobVarList *desc);
|
void SlGlobList(const SaveLoadGlobVarList *desc);
|
||||||
|
|
||||||
|
void SaveFileStart(void);
|
||||||
|
void SaveFileDone(void);
|
||||||
|
void SaveFileError(void);
|
||||||
#endif /* SAVELOAD_H */
|
#endif /* SAVELOAD_H */
|
||||||
|
8
thread.h
8
thread.h
@ -3,12 +3,6 @@
|
|||||||
#ifndef THREAD_H
|
#ifndef THREAD_H
|
||||||
#define THREAD_H
|
#define THREAD_H
|
||||||
|
|
||||||
/*
|
|
||||||
* DO NOT USE THREADS if you don't know what race conditions, mutexes,
|
|
||||||
* semaphores, atomic operations, etc. are or how to properly handle them.
|
|
||||||
* Ask somebody who has a clue.
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct Thread Thread;
|
typedef struct Thread Thread;
|
||||||
|
|
||||||
typedef void* (*ThreadFunc)(void*);
|
typedef void* (*ThreadFunc)(void*);
|
||||||
@ -16,4 +10,4 @@ typedef void* (*ThreadFunc)(void*);
|
|||||||
Thread* OTTDCreateThread(ThreadFunc, void*);
|
Thread* OTTDCreateThread(ThreadFunc, void*);
|
||||||
void* OTTDJoinThread(Thread*);
|
void* OTTDJoinThread(Thread*);
|
||||||
|
|
||||||
#endif
|
#endif /* THREAD_H */
|
||||||
|
5
unix.c
5
unix.c
@ -531,8 +531,6 @@ bool InsertTextBufferClipboard(Textbuf *tb)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef ENABLE_NETWORK
|
|
||||||
|
|
||||||
// multi os compatible sleep function
|
// multi os compatible sleep function
|
||||||
|
|
||||||
#ifdef __AMIGA__
|
#ifdef __AMIGA__
|
||||||
@ -571,6 +569,3 @@ void CSleep(int milliseconds)
|
|||||||
}
|
}
|
||||||
#endif // __AMIGA__
|
#endif // __AMIGA__
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* ENABLE_NETWORK */
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user