Merge branch 'crashlog_improvements' into jgrpp
This commit is contained in:
@@ -78,6 +78,7 @@
|
|||||||
/* static */ const char *CrashLog::message = NULL;
|
/* static */ const char *CrashLog::message = NULL;
|
||||||
/* static */ char *CrashLog::gamelog_buffer = NULL;
|
/* static */ char *CrashLog::gamelog_buffer = NULL;
|
||||||
/* static */ const char *CrashLog::gamelog_last = NULL;
|
/* static */ const char *CrashLog::gamelog_last = NULL;
|
||||||
|
/* static */ const CrashLog *CrashLog::main_thread_pending_crashlog = NULL;
|
||||||
|
|
||||||
char *CrashLog::LogCompiler(char *buffer, const char *last) const
|
char *CrashLog::LogCompiler(char *buffer, const char *last) const
|
||||||
{
|
{
|
||||||
@@ -398,6 +399,12 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (IsNonMainThread()) {
|
||||||
|
buffer += seprintf(buffer, last, "Non-main thread (");
|
||||||
|
buffer += GetThreadName(buffer, last);
|
||||||
|
buffer += seprintf(buffer, last, ")\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
buffer = this->LogOpenTTDVersion(buffer, last);
|
buffer = this->LogOpenTTDVersion(buffer, last);
|
||||||
buffer = this->LogStacktrace(buffer, last);
|
buffer = this->LogStacktrace(buffer, last);
|
||||||
buffer = this->LogRegisters(buffer, last);
|
buffer = this->LogRegisters(buffer, last);
|
||||||
@@ -528,8 +535,33 @@ bool CrashLog::MakeCrashLog() const
|
|||||||
printf("Crash dump written to %s. Please add this file to any bug reports.\n\n", filename);
|
printf("Crash dump written to %s. Please add this file to any bug reports.\n\n", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsNonMainThread()) {
|
||||||
|
printf("Asking main thread to write crash savegame and screenshot...\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();
|
||||||
|
if (!bret) ret = false;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes a crash dump and crash savegame. It uses DEBUG to write
|
||||||
|
* information like paths to the console.
|
||||||
|
* @return true when everything is made successfully.
|
||||||
|
*/
|
||||||
|
bool CrashLog::MakeCrashSavegameAndScreenshot() const
|
||||||
|
{
|
||||||
|
char filename[MAX_PATH];
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
printf("Writing crash savegame...\n");
|
printf("Writing crash savegame...\n");
|
||||||
bret = this->WriteSavegame(filename, lastof(filename));
|
bool bret = this->WriteSavegame(filename, lastof(filename));
|
||||||
if (bret) {
|
if (bret) {
|
||||||
printf("Crash savegame written to %s. Please add this file and the last (auto)save to any bug reports.\n\n", filename);
|
printf("Crash savegame written to %s. Please add this file and the last (auto)save to any bug reports.\n\n", filename);
|
||||||
} else {
|
} else {
|
||||||
@@ -549,6 +581,18 @@ bool CrashLog::MakeCrashLog() 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.
|
||||||
|
@@ -127,6 +127,7 @@ public:
|
|||||||
bool WriteScreenshot(char *filename, const char *filename_last) const;
|
bool WriteScreenshot(char *filename, const char *filename_last) const;
|
||||||
|
|
||||||
bool MakeCrashLog() const;
|
bool MakeCrashLog() const;
|
||||||
|
bool MakeCrashSavegameAndScreenshot() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialiser for crash logs; do the appropriate things so crashes are
|
* Initialiser for crash logs; do the appropriate things so crashes are
|
||||||
@@ -141,6 +142,10 @@ 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 */
|
||||||
|
@@ -922,6 +922,8 @@ 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 */
|
||||||
|
@@ -12,6 +12,8 @@
|
|||||||
#ifndef SCOPE_H
|
#ifndef SCOPE_H
|
||||||
#define SCOPE_H
|
#define SCOPE_H
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class scope_exit_obj {
|
class scope_exit_obj {
|
||||||
T f;
|
T f;
|
||||||
|
@@ -133,4 +133,17 @@ void SetSelfAsMainThread();
|
|||||||
*/
|
*/
|
||||||
bool IsMainThread();
|
bool IsMainThread();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the current thread definitely a "non-main" thread. If in doubt returns false.
|
||||||
|
*/
|
||||||
|
bool IsNonMainThread();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the name of the current thread, if any.
|
||||||
|
* @param str The start of the buffer.
|
||||||
|
* @param last The last char of the buffer.
|
||||||
|
* @return Number of chars written to str.
|
||||||
|
*/
|
||||||
|
int GetThreadName(char *str, const char *last);
|
||||||
|
|
||||||
#endif /* THREAD_H */
|
#endif /* THREAD_H */
|
||||||
|
@@ -199,3 +199,6 @@ private:
|
|||||||
void SetSelfAsMainThread() { }
|
void SetSelfAsMainThread() { }
|
||||||
|
|
||||||
bool IsMainThread() { return false; }
|
bool IsMainThread() { return false; }
|
||||||
|
bool IsNonMainThread() { return false; }
|
||||||
|
|
||||||
|
int GetThreadName(char *str, const char *last) { return 0; }
|
||||||
|
@@ -37,3 +37,6 @@ public:
|
|||||||
void SetSelfAsMainThread() { }
|
void SetSelfAsMainThread() { }
|
||||||
|
|
||||||
bool IsMainThread() { return true; }
|
bool IsMainThread() { return true; }
|
||||||
|
bool IsNonMainThread() { return false; }
|
||||||
|
|
||||||
|
int GetThreadName(char *str, const char *last) { return 0; }
|
||||||
|
@@ -149,3 +149,7 @@ public:
|
|||||||
void SetSelfAsMainThread() { }
|
void SetSelfAsMainThread() { }
|
||||||
|
|
||||||
bool IsMainThread() { return false; }
|
bool IsMainThread() { return false; }
|
||||||
|
|
||||||
|
bool IsNonMainThread() { return false; }
|
||||||
|
|
||||||
|
int GetThreadName(char *str, const char *last) { return 0; }
|
||||||
|
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
|
#include "../string_func.h"
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
@@ -201,3 +202,22 @@ bool IsMainThread()
|
|||||||
{
|
{
|
||||||
return main_thread == pthread_self();
|
return main_thread == pthread_self();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsNonMainThread()
|
||||||
|
{
|
||||||
|
return main_thread != pthread_self();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetThreadName(char *str, const char *last)
|
||||||
|
{
|
||||||
|
#if defined(__GLIBC__)
|
||||||
|
#if __GLIBC_PREREQ(2, 12)
|
||||||
|
char buffer[16];
|
||||||
|
int result = pthread_getname_np(pthread_self(), buffer, sizeof(buffer));
|
||||||
|
if (result == 0) {
|
||||||
|
return seprintf(str, last, "%s", buffer);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -13,13 +13,19 @@
|
|||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../core/alloc_func.hpp"
|
#include "../core/alloc_func.hpp"
|
||||||
|
#include "../scope.h"
|
||||||
|
#include "../string_func.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <process.h>
|
#include <process.h>
|
||||||
#include "../os/windows/win32.h"
|
#include "../os/windows/win32.h"
|
||||||
|
#include <map>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
|
static void Win32SetThreadName(uint id, const char *name);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Win32 thread version for ThreadObject.
|
* Win32 thread version for ThreadObject.
|
||||||
*/
|
*/
|
||||||
@@ -46,6 +52,7 @@ public:
|
|||||||
{
|
{
|
||||||
this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
|
this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
|
||||||
if (this->thread == NULL) return;
|
if (this->thread == NULL) return;
|
||||||
|
Win32SetThreadName(this->id, name);
|
||||||
ResumeThread(this->thread);
|
ResumeThread(this->thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,3 +184,31 @@ bool IsMainThread()
|
|||||||
{
|
{
|
||||||
return main_thread_id == GetCurrentThreadId();
|
return main_thread_id == GetCurrentThreadId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsNonMainThread()
|
||||||
|
{
|
||||||
|
return main_thread_id != GetCurrentThreadId();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::map<uint, std::string> _thread_name_map;
|
||||||
|
static ThreadMutex_Win32 _thread_name_map_mutex;
|
||||||
|
|
||||||
|
static void Win32SetThreadName(uint id, const char *name)
|
||||||
|
{
|
||||||
|
_thread_name_map_mutex.BeginCritical();
|
||||||
|
_thread_name_map[id] = name;
|
||||||
|
_thread_name_map_mutex.EndCritical();
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetThreadName(char *str, const char *last)
|
||||||
|
{
|
||||||
|
_thread_name_map_mutex.BeginCritical();
|
||||||
|
auto guard = scope_guard([&]() {
|
||||||
|
_thread_name_map_mutex.EndCritical();
|
||||||
|
});
|
||||||
|
auto iter = _thread_name_map.find(GetCurrentThreadId());
|
||||||
|
if (iter != _thread_name_map.end()) {
|
||||||
|
return seprintf(str, last, "%s", iter->second.c_str());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user