Crashlog: Update thread/lock handling to match GameLoop changes
This commit is contained in:
@@ -78,7 +78,6 @@
|
|||||||
/* static */ const char *CrashLog::message = nullptr;
|
/* static */ const char *CrashLog::message = nullptr;
|
||||||
/* static */ char *CrashLog::gamelog_buffer = nullptr;
|
/* static */ char *CrashLog::gamelog_buffer = nullptr;
|
||||||
/* static */ const char *CrashLog::gamelog_last = nullptr;
|
/* static */ const char *CrashLog::gamelog_last = nullptr;
|
||||||
/* static */ const CrashLog *CrashLog::main_thread_pending_crashlog = nullptr;
|
|
||||||
|
|
||||||
char *CrashLog::LogCompiler(char *buffer, const char *last) const
|
char *CrashLog::LogCompiler(char *buffer, const char *last) const
|
||||||
{
|
{
|
||||||
@@ -441,7 +440,7 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const
|
|||||||
buffer = this->LogError(buffer, last, CrashLog::message);
|
buffer = this->LogError(buffer, last, CrashLog::message);
|
||||||
|
|
||||||
#ifdef USE_SCOPE_INFO
|
#ifdef USE_SCOPE_INFO
|
||||||
if (IsMainThread()) {
|
if (IsMainThread() || IsGameThread()) {
|
||||||
buffer += WriteScopeLog(buffer, last);
|
buffer += WriteScopeLog(buffer, last);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -644,6 +643,10 @@ bool CrashLog::MakeCrashLog()
|
|||||||
if (crashlogged) return false;
|
if (crashlogged) return false;
|
||||||
crashlogged = true;
|
crashlogged = true;
|
||||||
|
|
||||||
|
if (!VideoDriver::EmergencyAcquireGameLock(20, 2)) {
|
||||||
|
printf("Failed to acquire gamelock before filling crash log\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
char filename[MAX_PATH];
|
char filename[MAX_PATH];
|
||||||
char buffer[65536 * 4];
|
char buffer[65536 * 4];
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
@@ -679,15 +682,10 @@ bool CrashLog::MakeCrashLog()
|
|||||||
_savegame_DBGL_data = buffer;
|
_savegame_DBGL_data = buffer;
|
||||||
_save_DBGC_data = true;
|
_save_DBGC_data = true;
|
||||||
|
|
||||||
if (IsNonMainThread()) {
|
if (!VideoDriver::EmergencyAcquireGameLock(1000, 5)) {
|
||||||
printf("Asking main thread to write crash savegame and screenshot...\n\n");
|
printf("Failed to acquire gamelock before writing crash savegame and screenshot, proceeding without lock as current owner is probably stuck\n\n");
|
||||||
CrashLog::main_thread_pending_crashlog = this;
|
|
||||||
_exit_game = true;
|
|
||||||
CSleep(60000);
|
|
||||||
if (!CrashLog::main_thread_pending_crashlog) return ret;
|
|
||||||
printf("Main thread did not write crash savegame and screenshot within 60s, trying it from this thread...\n\n");
|
|
||||||
}
|
}
|
||||||
CrashLog::main_thread_pending_crashlog = nullptr;
|
|
||||||
bret = CrashLog::MakeCrashSavegameAndScreenshot();
|
bret = CrashLog::MakeCrashSavegameAndScreenshot();
|
||||||
if (!bret) ret = false;
|
if (!bret) ret = false;
|
||||||
|
|
||||||
@@ -802,18 +800,6 @@ bool CrashLog::MakeCrashSavegameAndScreenshot() const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */ void CrashLog::MainThreadExitCheckPendingCrashlog()
|
|
||||||
{
|
|
||||||
const CrashLog *cl = CrashLog::main_thread_pending_crashlog;
|
|
||||||
if (cl) {
|
|
||||||
CrashLog::main_thread_pending_crashlog = nullptr;
|
|
||||||
cl->MakeCrashSavegameAndScreenshot();
|
|
||||||
|
|
||||||
CrashLog::AfterCrashLogCleanup();
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a message for the error message handler.
|
* Sets a message for the error message handler.
|
||||||
* @param message The error message of the error.
|
* @param message The error message of the error.
|
||||||
|
@@ -173,10 +173,6 @@ public:
|
|||||||
inline const char *GetMessage() const { return this->message; }
|
inline const char *GetMessage() const { return this->message; }
|
||||||
|
|
||||||
static const char *GetAbortCrashlogReason();
|
static const char *GetAbortCrashlogReason();
|
||||||
|
|
||||||
static const CrashLog *main_thread_pending_crashlog;
|
|
||||||
|
|
||||||
static void MainThreadExitCheckPendingCrashlog();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CRASHLOG_H */
|
#endif /* CRASHLOG_H */
|
||||||
|
@@ -997,8 +997,6 @@ int openttd_main(int argc, char *argv[])
|
|||||||
|
|
||||||
VideoDriver::GetInstance()->MainLoop();
|
VideoDriver::GetInstance()->MainLoop();
|
||||||
|
|
||||||
CrashLog::MainThreadExitCheckPendingCrashlog();
|
|
||||||
|
|
||||||
WaitTillSaved();
|
WaitTillSaved();
|
||||||
|
|
||||||
/* only save config if we have to */
|
/* only save config if we have to */
|
||||||
|
@@ -219,8 +219,10 @@ void SetCurrentThreadName(const char *)
|
|||||||
int GetCurrentThreadName(char *str, const char *last) { return 0; }
|
int GetCurrentThreadName(char *str, const char *last) { return 0; }
|
||||||
|
|
||||||
void SetSelfAsMainThread() { }
|
void SetSelfAsMainThread() { }
|
||||||
|
void SetSelfAsGameThread() { }
|
||||||
void PerThreadSetup() { }
|
void PerThreadSetup() { }
|
||||||
void PerThreadSetupInit() { }
|
void PerThreadSetupInit() { }
|
||||||
|
|
||||||
bool IsMainThread() { return false; }
|
bool IsMainThread() { return false; }
|
||||||
bool IsNonMainThread() { return false; }
|
bool IsNonMainThread() { return false; }
|
||||||
|
bool IsGameThread() { return false; }
|
||||||
|
@@ -341,6 +341,7 @@ int GetCurrentThreadName(char *str, const char *last)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static pthread_t main_thread;
|
static pthread_t main_thread;
|
||||||
|
static pthread_t game_thread;
|
||||||
|
|
||||||
void SetSelfAsMainThread()
|
void SetSelfAsMainThread()
|
||||||
{
|
{
|
||||||
@@ -349,6 +350,13 @@ void SetSelfAsMainThread()
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetSelfAsGameThread()
|
||||||
|
{
|
||||||
|
#if !defined(NO_THREADS)
|
||||||
|
game_thread = pthread_self();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void PerThreadSetup() { }
|
void PerThreadSetup() { }
|
||||||
|
|
||||||
void PerThreadSetupInit() { }
|
void PerThreadSetupInit() { }
|
||||||
@@ -370,3 +378,12 @@ bool IsNonMainThread()
|
|||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsGameThread()
|
||||||
|
{
|
||||||
|
#if !defined(NO_THREADS)
|
||||||
|
return game_thread == pthread_self();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@@ -639,6 +639,8 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
|
|||||||
ExitProcess(3);
|
ExitProcess(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VideoDriver::EmergencyAcquireGameLock(1000, 5);
|
||||||
|
|
||||||
CrashLogWindows *log = new CrashLogWindows(ep);
|
CrashLogWindows *log = new CrashLogWindows(ep);
|
||||||
CrashLogWindows::current = log;
|
CrashLogWindows::current = log;
|
||||||
char *buf = log->FillCrashLog(log->crashlog, lastof(log->crashlog));
|
char *buf = log->FillCrashLog(log->crashlog, lastof(log->crashlog));
|
||||||
|
@@ -734,12 +734,18 @@ int OTTDStringCompare(const char *s1, const char *s2)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static DWORD main_thread_id;
|
static DWORD main_thread_id;
|
||||||
|
static DWORD game_thread_id;
|
||||||
|
|
||||||
void SetSelfAsMainThread()
|
void SetSelfAsMainThread()
|
||||||
{
|
{
|
||||||
main_thread_id = GetCurrentThreadId();
|
main_thread_id = GetCurrentThreadId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetSelfAsGameThread()
|
||||||
|
{
|
||||||
|
game_thread_id = GetCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
static BOOL (WINAPI *_SetThreadStackGuarantee)(PULONG) = nullptr;
|
static BOOL (WINAPI *_SetThreadStackGuarantee)(PULONG) = nullptr;
|
||||||
|
|
||||||
void PerThreadSetup()
|
void PerThreadSetup()
|
||||||
@@ -765,6 +771,11 @@ bool IsNonMainThread()
|
|||||||
return main_thread_id != GetCurrentThreadId();
|
return main_thread_id != GetCurrentThreadId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsGameThread()
|
||||||
|
{
|
||||||
|
return game_thread_id == GetCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
static std::map<DWORD, std::string> _thread_name_map;
|
static std::map<DWORD, std::string> _thread_name_map;
|
||||||
static std::mutex _thread_name_map_mutex;
|
static std::mutex _thread_name_map_mutex;
|
||||||
|
|
||||||
|
14
src/thread.h
14
src/thread.h
@@ -46,6 +46,11 @@ int GetCurrentThreadName(char *str, const char *last);
|
|||||||
*/
|
*/
|
||||||
void SetSelfAsMainThread();
|
void SetSelfAsMainThread();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the current thread as the "game" thread
|
||||||
|
*/
|
||||||
|
void SetSelfAsGameThread();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform per-thread setup
|
* Perform per-thread setup
|
||||||
*/
|
*/
|
||||||
@@ -57,15 +62,20 @@ void PerThreadSetup();
|
|||||||
void PerThreadSetupInit();
|
void PerThreadSetupInit();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the current thread definitely the "main" thread. If in doubt returns false.
|
* @return true if the current thread is definitely the "main" thread. If in doubt returns false.
|
||||||
*/
|
*/
|
||||||
bool IsMainThread();
|
bool IsMainThread();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if the current thread definitely a "non-main" thread. If in doubt returns false.
|
* @return true if the current thread is definitely a "non-main" thread. If in doubt returns false.
|
||||||
*/
|
*/
|
||||||
bool IsNonMainThread();
|
bool IsNonMainThread();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the current thread is definitely the "game" thread. If in doubt returns false.
|
||||||
|
*/
|
||||||
|
bool IsGameThread();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a new thread.
|
* Start a new thread.
|
||||||
|
@@ -31,7 +31,7 @@ void VideoDriver::GameLoop()
|
|||||||
if (this->next_game_tick < now - ALLOWED_DRIFT * this->GetGameInterval()) this->next_game_tick = now;
|
if (this->next_game_tick < now - ALLOWED_DRIFT * this->GetGameInterval()) this->next_game_tick = now;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(this->game_state_mutex);
|
std::lock_guard<std::recursive_mutex> lock(this->game_state_mutex);
|
||||||
|
|
||||||
::GameLoop();
|
::GameLoop();
|
||||||
}
|
}
|
||||||
@@ -75,8 +75,23 @@ void VideoDriver::GameLoopPause()
|
|||||||
this->game_state_mutex.lock();
|
this->game_state_mutex.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ bool VideoDriver::EmergencyAcquireGameLock(uint tries, uint delay_ms)
|
||||||
|
{
|
||||||
|
VideoDriver *drv = VideoDriver::GetInstance();
|
||||||
|
if (drv == nullptr) return true;
|
||||||
|
|
||||||
|
|
||||||
|
for (uint i = 0; i < tries; i++) {
|
||||||
|
if (drv->game_state_mutex.try_lock()) return true;
|
||||||
|
CSleep(delay_ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* static */ void VideoDriver::GameThreadThunk(VideoDriver *drv)
|
/* static */ void VideoDriver::GameThreadThunk(VideoDriver *drv)
|
||||||
{
|
{
|
||||||
|
SetSelfAsGameThread();
|
||||||
drv->GameThread();
|
drv->GameThread();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +150,7 @@ void VideoDriver::Tick()
|
|||||||
{
|
{
|
||||||
/* Tell the game-thread to stop so we can have a go. */
|
/* Tell the game-thread to stop so we can have a go. */
|
||||||
std::lock_guard<std::mutex> lock_wait(this->game_thread_wait_mutex);
|
std::lock_guard<std::mutex> lock_wait(this->game_thread_wait_mutex);
|
||||||
std::lock_guard<std::mutex> lock_state(this->game_state_mutex);
|
std::lock_guard<std::recursive_mutex> lock_state(this->game_state_mutex);
|
||||||
|
|
||||||
this->next_draw_tick += this->GetDrawInterval();
|
this->next_draw_tick += this->GetDrawInterval();
|
||||||
/* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
|
/* Avoid next_draw_tick getting behind more and more if it cannot keep up. */
|
||||||
|
@@ -212,6 +212,8 @@ public:
|
|||||||
bool unlock; ///< Stores if the lock did anything that has to be undone.
|
bool unlock; ///< Stores if the lock did anything that has to be undone.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool EmergencyAcquireGameLock(uint tries, uint delay_ms);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const uint ALLOWED_DRIFT = 5; ///< How many times videodriver can miss deadlines without it being overly compensated.
|
const uint ALLOWED_DRIFT = 5; ///< How many times videodriver can miss deadlines without it being overly compensated.
|
||||||
|
|
||||||
@@ -322,7 +324,7 @@ protected:
|
|||||||
|
|
||||||
bool is_game_threaded;
|
bool is_game_threaded;
|
||||||
std::thread game_thread;
|
std::thread game_thread;
|
||||||
std::mutex game_state_mutex;
|
std::recursive_mutex game_state_mutex;
|
||||||
std::mutex game_thread_wait_mutex;
|
std::mutex game_thread_wait_mutex;
|
||||||
|
|
||||||
static void GameThreadThunk(VideoDriver *drv);
|
static void GameThreadThunk(VideoDriver *drv);
|
||||||
|
Reference in New Issue
Block a user