Skip to content

Commit

Permalink
Merge pull request #1178 from isanae/2_3_0
Browse files Browse the repository at this point in the history
Merge 2.3.1 changes
  • Loading branch information
isanae authored Aug 1, 2020
2 parents e34a9e7 + b9078ff commit b9f9e6a
Show file tree
Hide file tree
Showing 7 changed files with 59 additions and 16 deletions.
3 changes: 2 additions & 1 deletion src/envfs.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#ifndef ENV_ENVFS_H
#define ENV_ENVFS_H

#include "thread_utils.h"
#include <thread>

namespace env
Expand Down Expand Up @@ -125,7 +126,7 @@ class ThreadPool
ThreadInfo()
: busy(true), ready(false), stop(false)
{
thread = std::thread([&]{ run(); });
thread = MOShared::startSafeThread([&]{ run(); });
}

~ThreadInfo()
Expand Down
2 changes: 1 addition & 1 deletion src/filetreeitem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/iconfetcher.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "iconfetcher.h"
#include "thread_utils.h"
#include "shared/util.h"

void IconFetcher::Waiter::wait()
Expand All @@ -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()
Expand Down
30 changes: 26 additions & 4 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand All @@ -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)
Expand All @@ -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 };
Expand Down Expand Up @@ -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";
Expand Down
8 changes: 4 additions & 4 deletions src/organizercore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}

Expand Down Expand Up @@ -371,7 +371,7 @@ void OrganizerCore::downloadRequestedNXM(const QString &url)
}
}

void OrganizerCore::userInterfaceInitialized()
void OrganizerCore::userInterfaceInitialized()
{
m_UserInterfaceInitialized(m_UserInterface->mainWindow());
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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");
Expand Down
25 changes: 22 additions & 3 deletions src/thread_utils.h
Original file line number Diff line number Diff line change
@@ -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.
*
Expand All @@ -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) {
Expand Down Expand Up @@ -66,7 +85,7 @@ struct MemoizedLocked {
*
*/
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);
Expand All @@ -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;
{
Expand Down
4 changes: 2 additions & 2 deletions src/version.rc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit b9f9e6a

Please sign in to comment.