mirror of https://github.com/OpenMW/openmw.git
Fork the current process to monitor exe, generate minidump on crash
parent
11eff02a1d
commit
73afc55462
@ -0,0 +1,200 @@
|
|||||||
|
#include <cassert>
|
||||||
|
#include <cwchar>
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "windows_crashcatcher.hpp"
|
||||||
|
#include "windows_crashmonitor.hpp"
|
||||||
|
#include "windows_crashshm.hpp"
|
||||||
|
#include <SDL_messagebox.h>
|
||||||
|
|
||||||
|
namespace Crash
|
||||||
|
{
|
||||||
|
|
||||||
|
HANDLE duplicateHandle(HANDLE handle)
|
||||||
|
{
|
||||||
|
HANDLE duplicate;
|
||||||
|
if (!DuplicateHandle(GetCurrentProcess(), handle,
|
||||||
|
GetCurrentProcess(), &duplicate,
|
||||||
|
0, TRUE, DUPLICATE_SAME_ACCESS))
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Crash monitor could not duplicate handle");
|
||||||
|
}
|
||||||
|
return duplicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashCatcher* CrashCatcher::sInstance = nullptr;
|
||||||
|
|
||||||
|
CrashCatcher::CrashCatcher(int argc, char **argv, const std::string& crashLogPath)
|
||||||
|
{
|
||||||
|
assert(sInstance == nullptr); // don't allow two instances
|
||||||
|
|
||||||
|
sInstance = this;
|
||||||
|
|
||||||
|
HANDLE shmHandle = nullptr;
|
||||||
|
for (int i=0; i<argc; ++i)
|
||||||
|
{
|
||||||
|
if (strcmp(argv[i], "--crash-monitor"))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (i >= argc - 1)
|
||||||
|
throw std::runtime_error("Crash monitor is missing the SHM handle argument");
|
||||||
|
|
||||||
|
sscanf(argv[i + 1], "%p", &shmHandle);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!shmHandle)
|
||||||
|
{
|
||||||
|
setupIpc();
|
||||||
|
startMonitorProcess(crashLogPath);
|
||||||
|
installHandler();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CrashMonitor(shmHandle).run();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashCatcher::~CrashCatcher()
|
||||||
|
{
|
||||||
|
sInstance = nullptr;
|
||||||
|
|
||||||
|
if (mShm && mSignalMonitorEvent)
|
||||||
|
{
|
||||||
|
shmLock();
|
||||||
|
mShm->mEvent = CrashSHM::Event::Shutdown;
|
||||||
|
shmUnlock();
|
||||||
|
|
||||||
|
SetEvent(mSignalMonitorEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mShmHandle)
|
||||||
|
CloseHandle(mShmHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashCatcher::setupIpc()
|
||||||
|
{
|
||||||
|
SECURITY_ATTRIBUTES attributes;
|
||||||
|
ZeroMemory(&attributes, sizeof(attributes));
|
||||||
|
attributes.bInheritHandle = TRUE;
|
||||||
|
|
||||||
|
mSignalAppEvent = CreateEventW(&attributes, FALSE, FALSE, NULL);
|
||||||
|
mSignalMonitorEvent = CreateEventW(&attributes, FALSE, FALSE, NULL);
|
||||||
|
|
||||||
|
mShmHandle = CreateFileMappingW(INVALID_HANDLE_VALUE, &attributes, PAGE_READWRITE, HIWORD(sizeof(CrashSHM)), LOWORD(sizeof(CrashSHM)), NULL);
|
||||||
|
if (mShmHandle == nullptr)
|
||||||
|
throw std::runtime_error("Failed to allocate crash catcher shared memory");
|
||||||
|
|
||||||
|
mShm = reinterpret_cast<CrashSHM*>(MapViewOfFile(mShmHandle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CrashSHM)));
|
||||||
|
if (mShm == nullptr)
|
||||||
|
throw std::runtime_error("Failed to map crash catcher shared memory");
|
||||||
|
|
||||||
|
mShmMutex = CreateMutexW(&attributes, FALSE, NULL);
|
||||||
|
if (mShmMutex == nullptr)
|
||||||
|
throw std::runtime_error("Failed to create crash catcher shared memory mutex");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashCatcher::shmLock()
|
||||||
|
{
|
||||||
|
if (WaitForSingleObject(mShmMutex, CrashCatcherTimeout) != WAIT_OBJECT_0)
|
||||||
|
throw std::runtime_error("SHM lock timed out");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashCatcher::shmUnlock()
|
||||||
|
{
|
||||||
|
ReleaseMutex(mShmMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashCatcher::waitMonitor()
|
||||||
|
{
|
||||||
|
if (WaitForSingleObject(mSignalAppEvent, CrashCatcherTimeout) != WAIT_OBJECT_0)
|
||||||
|
throw std::runtime_error("Waiting for monitor failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashCatcher::signalMonitor()
|
||||||
|
{
|
||||||
|
SetEvent(mSignalMonitorEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashCatcher::installHandler()
|
||||||
|
{
|
||||||
|
SetUnhandledExceptionFilter(vectoredExceptionHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashCatcher::startMonitorProcess(const std::string& crashLogPath)
|
||||||
|
{
|
||||||
|
WCHAR executablePath[MAX_PATH + 1];
|
||||||
|
GetModuleFileNameW(NULL, executablePath, MAX_PATH + 1);
|
||||||
|
|
||||||
|
memset(mShm->mStartup.mLogFilePath, 0, sizeof(mShm->mStartup.mLogFilePath));
|
||||||
|
int length = crashLogPath.length();
|
||||||
|
if (length > MAX_PATH) length = MAX_PATH;
|
||||||
|
strncpy(mShm->mStartup.mLogFilePath, crashLogPath.c_str(), length);
|
||||||
|
mShm->mStartup.mLogFilePath[length] = '\0';
|
||||||
|
|
||||||
|
// note that we don't need to lock the SHM here, the other process has not started yet
|
||||||
|
mShm->mEvent = CrashSHM::Event::Startup;
|
||||||
|
mShm->mStartup.mShmMutex = duplicateHandle(mShmMutex);
|
||||||
|
mShm->mStartup.mAppProcessHandle = duplicateHandle(GetCurrentProcess());
|
||||||
|
mShm->mStartup.mSignalApp = duplicateHandle(mSignalAppEvent);
|
||||||
|
mShm->mStartup.mSignalMonitor = duplicateHandle(mSignalMonitorEvent);
|
||||||
|
|
||||||
|
std::wstringstream ss;
|
||||||
|
ss << "--crash-monitor " << std::hex << duplicateHandle(mShmHandle);
|
||||||
|
std::wstring argumetns(ss.str());
|
||||||
|
|
||||||
|
STARTUPINFOW si;
|
||||||
|
ZeroMemory(&si, sizeof(si));
|
||||||
|
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
ZeroMemory(&pi, sizeof(pi));
|
||||||
|
|
||||||
|
if (!CreateProcessW(executablePath, &argumetns[0], NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
|
||||||
|
throw std::runtime_error("Could not start crash monitor process");
|
||||||
|
|
||||||
|
waitMonitor();
|
||||||
|
}
|
||||||
|
|
||||||
|
LONG CrashCatcher::vectoredExceptionHandler(PEXCEPTION_POINTERS info)
|
||||||
|
{
|
||||||
|
switch (info->ExceptionRecord->ExceptionCode)
|
||||||
|
{
|
||||||
|
case EXCEPTION_SINGLE_STEP:
|
||||||
|
case EXCEPTION_BREAKPOINT:
|
||||||
|
case DBG_PRINTEXCEPTION_C:
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
}
|
||||||
|
if (!sInstance)
|
||||||
|
return EXCEPTION_EXECUTE_HANDLER;
|
||||||
|
|
||||||
|
sInstance->handleVectoredException(info);
|
||||||
|
|
||||||
|
_Exit(1);
|
||||||
|
|
||||||
|
return EXCEPTION_CONTINUE_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashCatcher::handleVectoredException(PEXCEPTION_POINTERS info)
|
||||||
|
{
|
||||||
|
shmLock();
|
||||||
|
|
||||||
|
mShm->mEvent = CrashSHM::Event::Crashed;
|
||||||
|
mShm->mCrashed.mThreadId = GetCurrentThreadId();
|
||||||
|
mShm->mCrashed.mContext = *info->ContextRecord;
|
||||||
|
mShm->mCrashed.mExceptionRecord = *info->ExceptionRecord;
|
||||||
|
|
||||||
|
shmUnlock();
|
||||||
|
|
||||||
|
signalMonitor();
|
||||||
|
|
||||||
|
// must remain until monitor has finished
|
||||||
|
waitMonitor();
|
||||||
|
|
||||||
|
std::string message = "OpenMW has encountered a fatal error.\nCrash log saved to '" + std::string(mShm->mStartup.mLogFilePath) + "'.\n Please report this to https://gitlab.com/OpenMW/openmw/issues !";
|
||||||
|
SDL_ShowSimpleMessageBox(0, "Fatal Error", message.c_str(), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Crash
|
@ -0,0 +1,79 @@
|
|||||||
|
#ifndef WINDOWS_CRASHCATCHER_HPP
|
||||||
|
#define WINDOWS_CRASHCATCHER_HPP
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
#include <components/crashcatcher/crashcatcher.hpp>
|
||||||
|
|
||||||
|
namespace Crash
|
||||||
|
{
|
||||||
|
|
||||||
|
// The implementation spawns the current executable as a monitor process which waits
|
||||||
|
// for a global synchronization event which is sent when the parent process crashes.
|
||||||
|
// The monitor process then extracts crash information from the parent process while
|
||||||
|
// the parent process waits for the monitor process to finish. The crashed process
|
||||||
|
// quits and the monitor writes the crash information to a file.
|
||||||
|
//
|
||||||
|
// To detect unexpected shutdowns of the application which are not handled by the
|
||||||
|
// crash handler, the monitor periodically checks the exit code of the parent
|
||||||
|
// process and exits if it does not return STILL_ACTIVE. You can test this by closing
|
||||||
|
// the main openmw process in task manager.
|
||||||
|
|
||||||
|
static constexpr const int CrashCatcherTimeout = 2500;
|
||||||
|
|
||||||
|
struct CrashSHM;
|
||||||
|
|
||||||
|
class CrashCatcher final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CrashCatcher(int argc, char **argv, const std::string& crashLogPath);
|
||||||
|
~CrashCatcher();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static CrashCatcher* sInstance;
|
||||||
|
|
||||||
|
// mapped SHM area
|
||||||
|
CrashSHM* mShm = nullptr;
|
||||||
|
// the handle is allocated by the catcher and passed to the monitor
|
||||||
|
// process via the command line which maps the SHM and sends / receives
|
||||||
|
// events through it
|
||||||
|
HANDLE mShmHandle = nullptr;
|
||||||
|
// mutex which guards SHM area
|
||||||
|
HANDLE mShmMutex = nullptr;
|
||||||
|
|
||||||
|
// triggered when the monitor signals the application
|
||||||
|
HANDLE mSignalAppEvent = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
// triggered when the application wants to wake the monitor process
|
||||||
|
HANDLE mSignalMonitorEvent = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
|
void setupIpc();
|
||||||
|
|
||||||
|
void shmLock();
|
||||||
|
|
||||||
|
void shmUnlock();
|
||||||
|
|
||||||
|
void startMonitorProcess(const std::string& crashLogPath);
|
||||||
|
|
||||||
|
void waitMonitor();
|
||||||
|
|
||||||
|
void signalMonitor();
|
||||||
|
|
||||||
|
void installHandler();
|
||||||
|
|
||||||
|
void handleVectoredException(PEXCEPTION_POINTERS info);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
static LONG WINAPI vectoredExceptionHandler(PEXCEPTION_POINTERS info);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Crash
|
||||||
|
|
||||||
|
#endif // WINDOWS_CRASHCATCHER_HPP
|
@ -0,0 +1,185 @@
|
|||||||
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <Psapi.h>
|
||||||
|
|
||||||
|
#include <DbgHelp.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <memory>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "windows_crashcatcher.hpp"
|
||||||
|
#include "windows_crashmonitor.hpp"
|
||||||
|
#include "windows_crashshm.hpp"
|
||||||
|
#include <components/debug/debuglog.hpp>
|
||||||
|
|
||||||
|
namespace Crash
|
||||||
|
{
|
||||||
|
|
||||||
|
CrashMonitor::CrashMonitor(HANDLE shmHandle)
|
||||||
|
: mShmHandle(shmHandle)
|
||||||
|
{
|
||||||
|
mShm = reinterpret_cast<CrashSHM*>(MapViewOfFile(mShmHandle, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(CrashSHM)));
|
||||||
|
if (mShm == nullptr)
|
||||||
|
throw std::runtime_error("Failed to map crash monitor shared memory");
|
||||||
|
|
||||||
|
// accessing SHM without lock is OK here, the parent waits for a signal before continuing
|
||||||
|
|
||||||
|
mShmMutex = mShm->mStartup.mShmMutex;
|
||||||
|
mAppProcessHandle = mShm->mStartup.mAppProcessHandle;
|
||||||
|
mSignalAppEvent = mShm->mStartup.mSignalApp;
|
||||||
|
mSignalMonitorEvent = mShm->mStartup.mSignalMonitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
CrashMonitor::~CrashMonitor()
|
||||||
|
{
|
||||||
|
if (mShm)
|
||||||
|
UnmapViewOfFile(mShm);
|
||||||
|
|
||||||
|
// the handles received from the app are duplicates, we must close them
|
||||||
|
|
||||||
|
if (mShmHandle)
|
||||||
|
CloseHandle(mShmHandle);
|
||||||
|
|
||||||
|
if (mShmMutex)
|
||||||
|
CloseHandle(mShmMutex);
|
||||||
|
|
||||||
|
if (mSignalAppEvent)
|
||||||
|
CloseHandle(mSignalAppEvent);
|
||||||
|
|
||||||
|
if (mSignalMonitorEvent)
|
||||||
|
CloseHandle(mSignalMonitorEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashMonitor::shmLock()
|
||||||
|
{
|
||||||
|
if (WaitForSingleObject(mShmMutex, CrashCatcherTimeout) != WAIT_OBJECT_0)
|
||||||
|
throw std::runtime_error("SHM monitor lock timed out");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashMonitor::shmUnlock()
|
||||||
|
{
|
||||||
|
ReleaseMutex(mShmMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashMonitor::signalApp() const
|
||||||
|
{
|
||||||
|
SetEvent(mSignalAppEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CrashMonitor::waitApp() const
|
||||||
|
{
|
||||||
|
return WaitForSingleObject(mSignalMonitorEvent, CrashCatcherTimeout) == WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CrashMonitor::isAppAlive() const
|
||||||
|
{
|
||||||
|
DWORD code = 0;
|
||||||
|
GetExitCodeProcess(mAppProcessHandle, &code);
|
||||||
|
return code == STILL_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashMonitor::run()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// app waits for monitor start up, let it continue
|
||||||
|
signalApp();
|
||||||
|
|
||||||
|
bool running = true;
|
||||||
|
while (isAppAlive() && running)
|
||||||
|
{
|
||||||
|
if (waitApp())
|
||||||
|
{
|
||||||
|
shmLock();
|
||||||
|
|
||||||
|
switch (mShm->mEvent)
|
||||||
|
{
|
||||||
|
case CrashSHM::Event::None:
|
||||||
|
break;
|
||||||
|
case CrashSHM::Event::Crashed:
|
||||||
|
handleCrash();
|
||||||
|
running = false;
|
||||||
|
break;
|
||||||
|
case CrashSHM::Event::Shutdown:
|
||||||
|
running = false;
|
||||||
|
break;
|
||||||
|
case CrashSHM::Event::Startup:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
shmUnlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "Exception in crash monitor, exiting";
|
||||||
|
}
|
||||||
|
signalApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring utf8ToUtf16(const std::string& utf8)
|
||||||
|
{
|
||||||
|
const int nLenWide = MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), utf8.size(), nullptr, 0);
|
||||||
|
|
||||||
|
std::wstring utf16;
|
||||||
|
utf16.resize(nLenWide);
|
||||||
|
if (MultiByteToWideChar(CP_UTF8, 0, utf8.c_str(), utf8.size(), utf16.data(), nLenWide) != nLenWide)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return utf16;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CrashMonitor::handleCrash()
|
||||||
|
{
|
||||||
|
DWORD processId = GetProcessId(mAppProcessHandle);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HMODULE dbghelp = LoadLibraryA("dbghelp.dll");
|
||||||
|
if (dbghelp == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using MiniDumpWirteDumpFn = BOOL (WINAPI*)(
|
||||||
|
HANDLE hProcess, DWORD ProcessId, HANDLE hFile, MINIDUMP_TYPE DumpType, PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
|
||||||
|
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, PMINIDUMP_CALLBACK_INFORMATION CallbackParam
|
||||||
|
);
|
||||||
|
|
||||||
|
MiniDumpWirteDumpFn miniDumpWriteDump = (MiniDumpWirteDumpFn)GetProcAddress(dbghelp, "MiniDumpWriteDump");
|
||||||
|
if (miniDumpWriteDump == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const std::wstring utf16Path = utf8ToUtf16(mShm->mStartup.mLogFilePath);
|
||||||
|
if (utf16Path.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
HANDLE hCrashLog = CreateFileW(utf16Path.c_str(), GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||||
|
if (hCrashLog == NULL || hCrashLog == INVALID_HANDLE_VALUE)
|
||||||
|
return;
|
||||||
|
if (auto err = GetLastError(); err != ERROR_ALREADY_EXISTS && err != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
EXCEPTION_POINTERS exp;
|
||||||
|
exp.ContextRecord = &mShm->mCrashed.mContext;
|
||||||
|
exp.ExceptionRecord = &mShm->mCrashed.mExceptionRecord;
|
||||||
|
MINIDUMP_EXCEPTION_INFORMATION infos = {};
|
||||||
|
infos.ThreadId = mShm->mCrashed.mThreadId;
|
||||||
|
infos.ExceptionPointers = &exp;
|
||||||
|
infos.ClientPointers = FALSE;
|
||||||
|
MINIDUMP_TYPE type = (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData);
|
||||||
|
miniDumpWriteDump(mAppProcessHandle, processId, hCrashLog, type, &infos, 0, 0);
|
||||||
|
}
|
||||||
|
catch (const std::exception&e)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "CrashMonitor: " << e.what();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
Log(Debug::Error) << "CrashMonitor: unknown exception";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Crash
|
@ -0,0 +1,49 @@
|
|||||||
|
#ifndef WINDOWS_CRASHMONITOR_HPP
|
||||||
|
#define WINDOWS_CRASHMONITOR_HPP
|
||||||
|
|
||||||
|
#include <windef.h>
|
||||||
|
|
||||||
|
namespace Crash
|
||||||
|
{
|
||||||
|
|
||||||
|
struct CrashSHM;
|
||||||
|
|
||||||
|
class CrashMonitor final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
CrashMonitor(HANDLE shmHandle);
|
||||||
|
|
||||||
|
~CrashMonitor();
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
HANDLE mAppProcessHandle = nullptr;
|
||||||
|
|
||||||
|
// triggered when the monitor process wants to wake the parent process (received via SHM)
|
||||||
|
HANDLE mSignalAppEvent = nullptr;
|
||||||
|
// triggered when the application wants to wake the monitor process (received via SHM)
|
||||||
|
HANDLE mSignalMonitorEvent = nullptr;
|
||||||
|
|
||||||
|
CrashSHM* mShm = nullptr;
|
||||||
|
HANDLE mShmHandle = nullptr;
|
||||||
|
HANDLE mShmMutex = nullptr;
|
||||||
|
|
||||||
|
void signalApp() const;
|
||||||
|
|
||||||
|
bool waitApp() const;
|
||||||
|
|
||||||
|
bool isAppAlive() const;
|
||||||
|
|
||||||
|
void shmLock();
|
||||||
|
|
||||||
|
void shmUnlock();
|
||||||
|
|
||||||
|
void handleCrash();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Crash
|
||||||
|
|
||||||
|
#endif // WINDOWS_CRASHMONITOR_HPP
|
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef WINDOWS_CRASHSHM_HPP
|
||||||
|
#define WINDOWS_CRASHSHM_HPP
|
||||||
|
|
||||||
|
#undef WIN32_LEAN_AND_MEAN
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <Windows.h>
|
||||||
|
|
||||||
|
namespace Crash
|
||||||
|
{
|
||||||
|
|
||||||
|
// Used to communicate between the app and the monitor, fields are is overwritten with each event.
|
||||||
|
|
||||||
|
struct CrashSHM
|
||||||
|
{
|
||||||
|
enum class Event
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Startup,
|
||||||
|
Crashed,
|
||||||
|
Shutdown
|
||||||
|
};
|
||||||
|
|
||||||
|
Event mEvent;
|
||||||
|
|
||||||
|
struct Startup
|
||||||
|
{
|
||||||
|
HANDLE mAppProcessHandle;
|
||||||
|
HANDLE mSignalApp;
|
||||||
|
HANDLE mSignalMonitor;
|
||||||
|
HANDLE mShmMutex;
|
||||||
|
char mLogFilePath[MAX_PATH + 1];
|
||||||
|
} mStartup;
|
||||||
|
|
||||||
|
struct Crashed
|
||||||
|
{
|
||||||
|
DWORD mThreadId;
|
||||||
|
CONTEXT mContext;
|
||||||
|
EXCEPTION_RECORD mExceptionRecord;
|
||||||
|
} mCrashed;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Crash
|
||||||
|
|
||||||
|
#endif // WINDOWS_CRASHSHM_HPP
|
Loading…
Reference in New Issue