Compare commits

...
Author SHA1 Message Date
isanae b9f9e6af94 Merge pull request #1178 from isanae/2_3_0
Merge 2.3.1 changes
2020-08-01 11:33:35 -04:00
isanae b9078ffefd bump to 2.3.1 2020-08-01 11:29:09 -04:00
isanae 04c5986aa6 added startSafeThread() to get core dumps for threads other than the main thread
added terminate handler
2020-08-01 11:29:09 -04:00
isanae 1cb18b3c00 fixed warning when trying to get the file type of files without extensions 2020-08-01 11:29:09 -04:00
7 changed files with 59 additions and 16 deletions
+2 -1
View File
@@ -1,6 +1,7 @@
#ifndef ENV_ENVFS_H
#define ENV_ENVFS_H
#include "thread_utils.h"
#include <thread>
namespace env
@@ -125,7 +126,7 @@ private:
ThreadInfo()
: busy(true), ready(false), stop(false)
{
thread = std::thread([&]{ run(); });
thread = MOShared::startSafeThread([&]{ run(); });
}
~ThreadInfo()
+1 -1
View File
@@ -40,7 +40,7 @@ const QString& directoryFileType()
const QString& cachedFileTypeNoExtension()
{
static const QString name = [] {
const DWORD flags = SHGFI_TYPENAME;
const DWORD flags = SHGFI_TYPENAME | SHGFI_USEFILEATTRIBUTES;
SHFILEINFOW sfi = {};
// dummy filename with no extension
+2 -1
View File
@@ -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()
+26 -4
View File
@@ -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<std::wstring>& parsedArgs)
@@ -171,6 +192,7 @@ LPCWSTR UntouchedCommandLineArguments(int parseArgCount, std::vector<std::wstrin
return cmd;
}
static int SpawnWaitProcess(LPCWSTR workingDirectory, LPCWSTR commandLine) {
PROCESS_INFORMATION pi{ 0 };
STARTUPINFO si{ 0 };
@@ -947,7 +969,7 @@ int main(int argc, char *argv[])
application.setProperty("dataPath", dataPath);
// initialize dump collection only after "dataPath" since the crashes are stored under it
prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
setUnhandledExceptionHandler();
const auto logFile =
qApp->property("dataPath").toString() + "/logs/mo_interface.log";
+4 -4
View File
@@ -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");
+22 -3
View File
@@ -1,12 +1,31 @@
#ifndef MO2_THREAD_UTILS_H
#define MO2_THREAD_UTILS_H
#include <log.h>
#include <functional>
#include <mutex>
#include <thread>
// 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 <class F>
std::thread startSafeThread(F&& f)
{
return std::thread([f=std::forward<F>(f)] {
setUnhandledExceptionHandler();
f();
});
}
/**
* Class that can be used to perform thread-safe memoization.
*
@@ -26,7 +45,7 @@ struct MemoizedLocked {
template <class Callable>
MemoizedLocked(Callable &&callable, T value = {}) :
m_Fn{ std::forward<Callable>(callable) }, m_Value{ std::move(value) } { }
template <class... Args>
T& value(Args&&... args) const {
if (m_NeedUpdating) {
@@ -66,7 +85,7 @@ private:
*
*/
template <class It, class Callable>
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<std::thread> 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;
{
+2 -2
View File
@@ -3,8 +3,8 @@
// If VS_FF_PRERELEASE is not set, MO labels the build as a release and uses VER_FILEVERSION to determine version number.
// Otherwise, if letters are used in VER_FILEVERSION_STR, uses the full MOBase::VersionInfo parser
// Otherwise, uses the numbers from VER_FILEVERSION and sets the release type as pre-alpha
#define VER_FILEVERSION 2,3,0
#define VER_FILEVERSION_STR "2.3.0\0"
#define VER_FILEVERSION 2,3,1
#define VER_FILEVERSION_STR "2.3.1\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION