mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
15
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1412befe1b | ||
|
|
e6e88074ea | ||
|
|
2388f2471b | ||
|
|
2c6c223cb0 | ||
|
|
f16738ffd6 | ||
|
|
f2dc4ddd30 | ||
|
|
322b5d59f0 | ||
|
|
06d356e48f | ||
|
|
8db55c451c | ||
|
|
768e6291b3 | ||
|
|
2cdb7c5b13 | ||
|
|
b9f9e6af94 | ||
|
|
b9078ffefd | ||
|
|
04c5986aa6 | ||
|
|
1cb18b3c00 |
+2
-1
@@ -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()
|
||||
|
||||
@@ -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
@@ -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()
|
||||
|
||||
+33
-4
@@ -127,9 +127,10 @@ bool bootstrap()
|
||||
return true;
|
||||
}
|
||||
|
||||
LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr;
|
||||
thread_local LPTOP_LEVEL_EXCEPTION_FILTER prevUnhandledExceptionFilter = nullptr;
|
||||
thread_local std::terminate_handler prevTerminateHandler = 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 +140,39 @@ 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
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
if (prevTerminateHandler) {
|
||||
prevTerminateHandler();
|
||||
} else {
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
|
||||
void setUnhandledExceptionHandler()
|
||||
{
|
||||
prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
|
||||
prevTerminateHandler = 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 +199,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 +976,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";
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -65,7 +65,7 @@ private:
|
||||
OrganizerCore *m_Proxied;
|
||||
PluginContainer *m_PluginContainer;
|
||||
|
||||
const QString &m_PluginName;
|
||||
QString m_PluginName;
|
||||
|
||||
};
|
||||
|
||||
|
||||
+22
-3
@@ -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
@@ -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,2
|
||||
#define VER_FILEVERSION_STR "2.3.2\0"
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION VER_FILEVERSION
|
||||
|
||||
Reference in New Issue
Block a user