From 777229f28f8f5de19376459e85b434576af8e010 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Fri, 31 Jul 2020 09:56:19 -0400 Subject: added startSafeThread() to get core dumps for threads other than the main thread added terminate handler --- src/envfs.h | 3 ++- src/iconfetcher.cpp | 3 ++- src/main.cpp | 30 ++++++++++++++++++++++++++---- src/organizercore.cpp | 8 ++++---- src/thread_utils.h | 25 ++++++++++++++++++++++--- 5 files changed, 56 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/envfs.h b/src/envfs.h index bbc27005..e4d98d71 100644 --- a/src/envfs.h +++ b/src/envfs.h @@ -1,6 +1,7 @@ #ifndef ENV_ENVFS_H #define ENV_ENVFS_H +#include "thread_utils.h" #include namespace env @@ -125,7 +126,7 @@ private: ThreadInfo() : busy(true), ready(false), stop(false) { - thread = std::thread([&]{ run(); }); + thread = MOShared::startSafeThread([&]{ run(); }); } ~ThreadInfo() diff --git a/src/iconfetcher.cpp b/src/iconfetcher.cpp index 129be50e..c10adc8d 100644 --- a/src/iconfetcher.cpp +++ b/src/iconfetcher.cpp @@ -1,4 +1,5 @@ #include "iconfetcher.h" +#include "thread_utils.h" #include "shared/util.h" void IconFetcher::Waiter::wait() @@ -25,7 +26,7 @@ IconFetcher::IconFetcher() m_quickCache.file = getPixmapIcon(QFileIconProvider::File); m_quickCache.directory = getPixmapIcon(QFileIconProvider::Folder); - m_thread = std::thread([&]{ threadFun(); }); + m_thread = MOShared::startSafeThread([&]{ threadFun(); }); } IconFetcher::~IconFetcher() diff --git a/src/main.cpp b/src/main.cpp index 46f2f0aa..f008896b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -127,9 +127,9 @@ bool bootstrap() return true; } -LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr; +thread_local LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr; -static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs) +LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs) { const std::wstring& dumpPath = OrganizerCore::crashDumpsPath(); int dumpRes = @@ -139,12 +139,33 @@ static LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *except else log::error("ModOrganizer has crashed, CreateMiniDump failed ({}, error {}).", dumpRes, GetLastError()); - if (prevUnhandledExceptionFilter) + if (prevUnhandledExceptionFilter && exceptionPtrs) return prevUnhandledExceptionFilter(exceptionPtrs); else return EXCEPTION_CONTINUE_SEARCH; } +void terminateHandler() noexcept +{ + __try + { + // force an exception to get a valid stack trace for this thread + *(int*)0 = 42; + } + __except + ( + MyUnhandledExceptionFilter(GetExceptionInformation()), EXCEPTION_EXECUTE_HANDLER + ) + { + } +} + +void setUnhandledExceptionHandler() +{ + prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); + std::set_terminate(terminateHandler); +} + // Parses the first parseArgCount arguments of the current process command line and returns // them in parsedArgs, the rest of the command line is returned untouched. LPCWSTR UntouchedCommandLineArguments(int parseArgCount, std::vector& parsedArgs) @@ -171,6 +192,7 @@ LPCWSTR UntouchedCommandLineArguments(int parseArgCount, std::vectorproperty("dataPath").toString() + "/logs/mo_interface.log"; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 062369d6..1e2a0aa1 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -221,7 +221,7 @@ void OrganizerCore::updateExecutablesList() void OrganizerCore::updateModInfoFromDisc() { ModInfo::updateFromDisc( m_Settings.paths().mods(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.interface().displayForeign(), + m_PluginContainer, m_Settings.interface().displayForeign(), m_Settings.refreshThreadCount(), managedGame()); } @@ -371,7 +371,7 @@ void OrganizerCore::downloadRequestedNXM(const QString &url) } } -void OrganizerCore::userInterfaceInitialized() +void OrganizerCore::userInterfaceInitialized() { m_UserInterfaceInitialized(m_UserInterface->mainWindow()); } @@ -1139,7 +1139,7 @@ void OrganizerCore::refreshModList(bool saveChanges) ModInfo::updateFromDisc( m_Settings.paths().mods(), &m_DirectoryStructure, - m_PluginContainer, m_Settings.interface().displayForeign(), + m_PluginContainer, m_Settings.interface().displayForeign(), m_Settings.refreshThreadCount(), managedGame()); m_CurrentProfile->refreshModStatus(); @@ -1473,7 +1473,7 @@ void OrganizerCore::directory_refreshed() m_StructureDeleter.join(); } - m_StructureDeleter = std::thread([=]{ + m_StructureDeleter = MOShared::startSafeThread([=]{ log::debug("structure deleter thread start"); delete newStructure; log::debug("structure deleter thread done"); diff --git a/src/thread_utils.h b/src/thread_utils.h index f0067b6a..607d73a9 100644 --- a/src/thread_utils.h +++ b/src/thread_utils.h @@ -1,12 +1,31 @@ #ifndef MO2_THREAD_UTILS_H #define MO2_THREAD_UTILS_H +#include #include #include #include +// in main.cpp +void setUnhandledExceptionHandler(); +LONG WINAPI MyUnhandledExceptionFilter(struct _EXCEPTION_POINTERS *exceptionPtrs); + + namespace MOShared { +// starts an std::thread with an unhandled exception handler for core dumps +// and a top-level catch +// +template +std::thread startSafeThread(F&& f) +{ + return std::thread([f=std::forward(f)] { + setUnhandledExceptionHandler(); + f(); + }); +} + + /** * Class that can be used to perform thread-safe memoization. * @@ -26,7 +45,7 @@ struct MemoizedLocked { template MemoizedLocked(Callable &&callable, T value = {}) : m_Fn{ std::forward(callable) }, m_Value{ std::move(value) } { } - + template T& value(Args&&... args) const { if (m_NeedUpdating) { @@ -66,7 +85,7 @@ private: * */ template -void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) +void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) { std::mutex m; std::vector threads(nThreads); @@ -75,7 +94,7 @@ void parallelMap(It begin, It end, Callable callable, std::size_t nThreads) // - The mutex is only used to fetch/increment the iterator. // - The callable is copied in each thread to avoid conflicts. for (auto &thread: threads) { - thread = std::thread([&m, &begin, end, callable]() { + thread = startSafeThread([&m, &begin, end, callable]() { while (true) { decltype(begin) it; { -- cgit v1.3.1