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 bubblesort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));
|
||||
void CSleep(int milliseconds);
|
||||
#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
|
||||
|
||||
NetworkGameList *NetworkQueryServer(const char* host, unsigned short port, bool game_info);
|
||||
void CSleep(int milliseconds);
|
||||
|
||||
#endif /* ENABLE_NETWORK */
|
||||
|
||||
|
36
openttd.c
36
openttd.c
@ -542,6 +542,38 @@ int ttd_main(int argc, char* argv[])
|
||||
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)
|
||||
{
|
||||
if (b) {
|
||||
@ -914,6 +946,10 @@ static void HandleKeyScrolling(void)
|
||||
void GameLoop(void)
|
||||
{
|
||||
int m;
|
||||
ThreadMsg message;
|
||||
|
||||
|
||||
if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message);
|
||||
|
||||
// autosave game?
|
||||
if (_do_autosave) {
|
||||
|
11
openttd.h
11
openttd.h
@ -543,4 +543,15 @@ enum {
|
||||
};
|
||||
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 */
|
||||
|
24
saveload.c
24
saveload.c
@ -1255,7 +1255,7 @@ static inline SaveOrLoadResult AbortSaveLoad(void)
|
||||
/** Update the gui accordingly when starting saving
|
||||
* and set locks on saveload. Also turn off fast-forward cause with that
|
||||
* saving takes Aaaaages */
|
||||
static inline void SaveFileStart(void)
|
||||
void SaveFileStart(void)
|
||||
{
|
||||
_ts.ff_state = _fast_forward;
|
||||
_fast_forward = false;
|
||||
@ -1267,7 +1267,7 @@ static inline void SaveFileStart(void)
|
||||
|
||||
/** Update the gui accordingly when saving is done and release locks
|
||||
* on saveload */
|
||||
static inline void SaveFileDone(void)
|
||||
void SaveFileDone(void)
|
||||
{
|
||||
_fast_forward = _ts.ff_state;
|
||||
if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE);
|
||||
@ -1276,6 +1276,13 @@ static inline void SaveFileDone(void)
|
||||
_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
|
||||
* and appropiate compressor and start writing to file.
|
||||
*/
|
||||
@ -1287,6 +1294,8 @@ static void* SaveFileToDisk(void* arg)
|
||||
static byte *tmp = NULL;
|
||||
uint32 hdr[2];
|
||||
|
||||
OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_START);
|
||||
|
||||
tmp = _sl.buf;
|
||||
|
||||
/* XXX - Setup setjmp error handler if an error occurs anywhere deep during
|
||||
@ -1297,9 +1306,7 @@ static void* SaveFileToDisk(void* arg)
|
||||
_sl.excpt_uninit();
|
||||
|
||||
ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
|
||||
ShowErrorMessage(STR_4007_GAME_SAVE_FAILED, STR_NULL, 0, 0);
|
||||
|
||||
SaveFileDone();
|
||||
OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1334,7 +1341,7 @@ static void* SaveFileToDisk(void* arg)
|
||||
GetSavegameFormat("memory")->uninit_write(); // clean the memorypool
|
||||
fclose(_sl.fh);
|
||||
|
||||
SaveFileDone();
|
||||
OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1405,11 +1412,11 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode)
|
||||
if (mode == SL_LOAD) {
|
||||
ShowInfoF("Load game failed: %s.", _sl.excpt_msg);
|
||||
return SL_REINIT;
|
||||
} else {
|
||||
}
|
||||
|
||||
ShowInfoF("Save game failed: %s.", _sl.excpt_msg);
|
||||
return SL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* We first initialize here to avoid: "warning: variable `version' might
|
||||
* be clobbered by `longjmp' or `vfork'" */
|
||||
@ -1434,7 +1441,6 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode)
|
||||
SlWriteFill(); // flush the save buffer
|
||||
|
||||
/* Write to file */
|
||||
SaveFileStart();
|
||||
if (_network_server ||
|
||||
(save_thread = OTTDCreateThread(&SaveFileToDisk, NULL)) == NULL) {
|
||||
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 SlGlobList(const SaveLoadGlobVarList *desc);
|
||||
|
||||
void SaveFileStart(void);
|
||||
void SaveFileDone(void);
|
||||
void SaveFileError(void);
|
||||
#endif /* SAVELOAD_H */
|
||||
|
8
thread.h
8
thread.h
@ -3,12 +3,6 @@
|
||||
#ifndef 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 void* (*ThreadFunc)(void*);
|
||||
@ -16,4 +10,4 @@ typedef void* (*ThreadFunc)(void*);
|
||||
Thread* OTTDCreateThread(ThreadFunc, void*);
|
||||
void* OTTDJoinThread(Thread*);
|
||||
|
||||
#endif
|
||||
#endif /* THREAD_H */
|
||||
|
Loading…
Reference in New Issue
Block a user