diff options
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/env.cpp | 27 | ||||
| -rw-r--r-- | src/env.h | 21 | ||||
| -rw-r--r-- | src/envdump.h | 30 | ||||
| -rw-r--r-- | src/main.cpp | 27 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 4 | ||||
| -rw-r--r-- | src/moapplication.cpp | 4 | ||||
| -rw-r--r-- | src/organizercore.cpp | 48 | ||||
| -rw-r--r-- | src/organizercore.h | 13 | ||||
| -rw-r--r-- | src/settings.cpp | 12 | ||||
| -rw-r--r-- | src/settings.h | 9 | ||||
| -rw-r--r-- | src/settingsdialogdiagnostics.cpp | 20 | ||||
| -rw-r--r-- | src/usvfsconnector.cpp | 33 | ||||
| -rw-r--r-- | src/usvfsconnector.h | 3 |
14 files changed, 146 insertions, 106 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eec33460..30614e59 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -70,6 +70,7 @@ add_filter(NAME src/downloads GROUPS add_filter(NAME src/env GROUPS env + envdump envfs envmetrics envmodule diff --git a/src/env.cpp b/src/env.cpp index 5bed84c1..98d2e6ea 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -4,6 +4,7 @@ #include "envsecurity.h" #include "envshortcut.h" #include "envwindows.h" +#include "envdump.h" #include "settings.h" #include <log.h> #include <utility.h> @@ -1182,8 +1183,16 @@ HandlePtr tempFile(const std::wstring dir) return {}; } -HandlePtr dumpFile() +HandlePtr dumpFile(const wchar_t* dir) { + // try the given directory, if any + if (dir) { + HandlePtr h = tempFile(dir); + if (h.get() != INVALID_HANDLE_VALUE) { + return h; + } + } + // try the current directory HandlePtr h = tempFile(L"."); if (h.get() != INVALID_HANDLE_VALUE) { @@ -1193,10 +1202,10 @@ HandlePtr dumpFile() std::wclog << L"cannot write dump file in current directory\n"; // try the temp directory - const auto dir = tempDir(); + const auto temp = tempDir(); - if (!dir.empty()) { - h = tempFile(dir.c_str()); + if (!temp.empty()) { + h = tempFile(temp.c_str()); if (h.get() != INVALID_HANDLE_VALUE) { return h; } @@ -1235,11 +1244,11 @@ std::string toString(CoreDumpTypes type) } -bool createMiniDump(HANDLE process, CoreDumpTypes type) +bool createMiniDump(const wchar_t* dir, HANDLE process, CoreDumpTypes type) { const DWORD pid = GetProcessId(process); - const HandlePtr file = dumpFile(); + const HandlePtr file = dumpFile(dir); if (!file) { std::wcerr << L"nowhere to write the dump file\n"; return false; @@ -1278,10 +1287,10 @@ bool createMiniDump(HANDLE process, CoreDumpTypes type) } -bool coredump(CoreDumpTypes type) +bool coredump(const wchar_t* dir, CoreDumpTypes type) { std::wclog << L"creating minidump for the current process\n"; - return createMiniDump(GetCurrentProcess(), type); + return createMiniDump(dir, GetCurrentProcess(), type); } bool coredumpOther(CoreDumpTypes type) @@ -1309,7 +1318,7 @@ bool coredumpOther(CoreDumpTypes type) return false; } - return createMiniDump(handle.get(), type); + return createMiniDump(nullptr, handle.get(), type); } } // namespace @@ -309,27 +309,6 @@ bool registryValueExists(const QString& key, const QString& value); // void deleteRegistryKeyIfEmpty(const QString& name); - -enum class CoreDumpTypes -{ - Mini = 1, - Data, - Full -}; - - -CoreDumpTypes coreDumpTypeFromString(const std::string& s); -std::string toString(CoreDumpTypes type); - -// creates a minidump file for this process -// -bool coredump(CoreDumpTypes type); - -// finds another process with the same name as this one and creates a minidump -// file for it -// -bool coredumpOther(CoreDumpTypes type); - } // namespace env #endif // ENV_ENV_H diff --git a/src/envdump.h b/src/envdump.h new file mode 100644 index 00000000..355df783 --- /dev/null +++ b/src/envdump.h @@ -0,0 +1,30 @@ +#ifndef MODORGANIZER_ENVDUMP_INCLUDED +#define MODORGANIZER_ENVDUMP_INCLUDED + +namespace env +{ + +enum class CoreDumpTypes +{ + None, + Mini, + Data, + Full +}; + + +CoreDumpTypes coreDumpTypeFromString(const std::string& s); +std::string toString(CoreDumpTypes type); + +// creates a minidump file for this process +// +bool coredump(const wchar_t* dir, CoreDumpTypes type); + +// finds another process with the same name as this one and creates a minidump +// file for it +// +bool coredumpOther(CoreDumpTypes type); + +} // namespace + +#endif // MODORGANIZER_ENVDUMP_INCLUDED diff --git a/src/main.cpp b/src/main.cpp index a2e16cc0..ad074501 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3,8 +3,9 @@ #include "moapplication.h" #include "organizercore.h" #include "commandline.h" +#include "env.h" +#include "thread_utils.h" #include "shared/util.h" -#include <usvfs.h> #include <log.h> using namespace MOBase; @@ -17,6 +18,7 @@ int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl); int main(int argc, char *argv[]) { MOShared::SetThisThreadName("main"); + setExceptionHandlers(); cl::CommandLine cl; if (auto r=cl.run(GetCommandLineW())) { @@ -53,20 +55,20 @@ int forwardToPrimary(SingleInstance& instance, const cl::CommandLine& cl) LONG WINAPI onUnhandledException(_EXCEPTION_POINTERS* ptrs) { - const std::wstring& dumpPath = OrganizerCore::crashDumpsPath(); + const auto path = OrganizerCore::getGlobalCoreDumpPath(); + const auto type = OrganizerCore::getGlobalCoreDumpType(); - const int r = CreateMiniDump( - ptrs, OrganizerCore::getGlobalCrashDumpsType(), dumpPath.c_str()); + const auto r = env::coredump(path.empty() ? nullptr : path.c_str(), type); - if (r == 0) { - log::error("ModOrganizer has crashed, crash dump created."); + if (r) { + log::error("ModOrganizer has crashed, core dump created."); } else { - log::error( - "ModOrganizer has crashed, CreateMiniDump failed ({}, error {}).", - r, GetLastError()); + log::error("ModOrganizer has crashed, core dump failed"); } - if (g_prevExceptionFilter && ptrs) + // g_prevExceptionFilter somehow sometimes point to this function, making this + // recurse and create hundreds of core dump, not sure why + if (g_prevExceptionFilter && ptrs && g_prevExceptionFilter != onUnhandledException) return g_prevExceptionFilter(ptrs); else return EXCEPTION_CONTINUE_SEARCH; @@ -95,6 +97,11 @@ void onTerminate() noexcept void setExceptionHandlers() { + if (g_prevExceptionFilter) { + // already called + return; + } + g_prevExceptionFilter = SetUnhandledExceptionFilter(onUnhandledException); g_prevTerminateHandler = std::set_terminate(onTerminate); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ea8a0efe..41958b80 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -5084,7 +5084,7 @@ void MainWindow::on_actionSettings_triggered() bool proxy = settings.network().useProxy(); DownloadManager *dlManager = m_OrganizerCore.downloadManager(); const bool oldCheckForUpdates = settings.checkForUpdates(); - const int oldMaxDumps = settings.diagnostics().crashDumpsMax(); + const int oldMaxDumps = settings.diagnostics().maxCoreDumps(); SettingsDialog dialog(&m_PluginContainer, settings, this); @@ -5171,7 +5171,7 @@ void MainWindow::on_actionSettings_triggered() m_OrganizerCore.setLogLevel(settings.diagnostics().logLevel()); - if (settings.diagnostics().crashDumpsMax() != oldMaxDumps) { + if (settings.diagnostics().maxCoreDumps() != oldMaxDumps) { m_OrganizerCore.cycleDiagnostics(); } diff --git a/src/moapplication.cpp b/src/moapplication.cpp index 24cafd05..bb7b4922 100644 --- a/src/moapplication.cpp +++ b/src/moapplication.cpp @@ -188,8 +188,6 @@ int MOApplication::doOneRun(SingleInstance& singleInstance) const QString dataPath = currentInstance->directory();
setProperty("dataPath", dataPath);
- setExceptionHandlers();
-
if (!setLogDirectory(dataPath)) {
reportError("Failed to create log folder");
InstanceManager::singleton().clearCurrentInstance();
@@ -272,7 +270,7 @@ int MOApplication::runApplication( // global crashDumpType sits in OrganizerCore to make a bit less ugly to
// update it when the settings are changed during runtime
- OrganizerCore::setGlobalCrashDumpsType(settings.diagnostics().crashDumpsType());
+ OrganizerCore::setGlobalCoreDumpType(settings.diagnostics().coreDumpType());
env::Environment env;
env.dump(settings);
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d01aab96..f57903e2 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -76,8 +76,7 @@ using namespace MOShared; using namespace MOBase; -//static -CrashDumpsType OrganizerCore::m_globalCrashDumpsType = CrashDumpsType::None; +static env::CoreDumpTypes g_coreDumpType = env::CoreDumpTypes::Mini; template <typename InputIterator> QStringList toStringList(InputIterator current, InputIterator end) @@ -478,7 +477,7 @@ bool OrganizerCore::bootstrap() m_Settings.paths().mods(), m_Settings.paths().downloads(), m_Settings.paths().overwrite(), - QString::fromStdWString(crashDumpsPath()) + QString::fromStdWString(getGlobalCoreDumpPath()) }; for (auto&& dir : dirs) { @@ -497,14 +496,14 @@ bool OrganizerCore::bootstrap() // log if there are any dmp files const auto hasCrashDumps = - !QDir(QString::fromStdWString(crashDumpsPath())) + !QDir(QString::fromStdWString(getGlobalCoreDumpPath())) .entryList({"*.dmp"}, QDir::Files) .empty(); if (hasCrashDumps) { log::debug( "there are crash dumps in '{}'", - QString::fromStdWString(crashDumpsPath())); + QString::fromStdWString(getGlobalCoreDumpPath())); } return true; @@ -528,13 +527,14 @@ void OrganizerCore::prepareVFS() } void OrganizerCore::updateVFSParams( - log::Levels logLevel, CrashDumpsType crashDumpsType, + log::Levels logLevel, env::CoreDumpTypes coreDumpType, const QString& crashDumpsPath, std::chrono::seconds spawnDelay, QString executableBlacklist) { - setGlobalCrashDumpsType(crashDumpsType); + setGlobalCoreDumpType(coreDumpType); + m_USVFS.updateParams( - logLevel, crashDumpsType, crashDumpsPath, spawnDelay, executableBlacklist); + logLevel, coreDumpType, crashDumpsPath, spawnDelay, executableBlacklist); } void OrganizerCore::setLogLevel(log::Levels level) @@ -543,8 +543,8 @@ void OrganizerCore::setLogLevel(log::Levels level) updateVFSParams( m_Settings.diagnostics().logLevel(), - m_Settings.diagnostics().crashDumpsType(), - QString::fromStdWString(crashDumpsPath()), + m_Settings.diagnostics().coreDumpType(), + QString::fromStdWString(getGlobalCoreDumpPath()), m_Settings.diagnostics().spawnDelay(), m_Settings.executablesBlacklist()); @@ -553,8 +553,8 @@ void OrganizerCore::setLogLevel(log::Levels level) bool OrganizerCore::cycleDiagnostics() { - const auto maxDumps = settings().diagnostics().crashDumpsMax(); - const auto path = QString::fromStdWString(crashDumpsPath()); + const auto maxDumps = settings().diagnostics().maxCoreDumps(); + const auto path = QString::fromStdWString(getGlobalCoreDumpPath()); if (maxDumps > 0) { removeOldFiles(path, "*.dmp", maxDumps, QDir::Time|QDir::Reversed); @@ -563,16 +563,26 @@ bool OrganizerCore::cycleDiagnostics() return true; } -void OrganizerCore::setGlobalCrashDumpsType(CrashDumpsType type) +env::CoreDumpTypes OrganizerCore::getGlobalCoreDumpType() +{ + return g_coreDumpType; +} + +void OrganizerCore::setGlobalCoreDumpType(env::CoreDumpTypes type) { - m_globalCrashDumpsType = type; + g_coreDumpType = type; } -std::wstring OrganizerCore::crashDumpsPath() { - return ( - qApp->property("dataPath").toString() + "/" - + QString::fromStdWString(AppConfig::dumpsDir()) - ).toStdWString(); +std::wstring OrganizerCore::getGlobalCoreDumpPath() +{ + if (qApp) { + const auto dp = qApp->property("dataPath"); + if (!dp.isNull()) { + return dp.toString().toStdWString() + L"/" + AppConfig::dumpsDir(); + } + } + + return {}; } void OrganizerCore::setCurrentProfile(const QString &profileName) diff --git a/src/organizercore.h b/src/organizercore.h index 80b89a43..b566e626 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -13,6 +13,7 @@ #include "moshortcut.h"
#include "processrunner.h"
#include "uilocker.h"
+#include "envdump.h"
#include <imoinfo.h>
#include <iplugindiagnose.h>
#include <versioninfo.h>
@@ -277,17 +278,17 @@ public: void prepareVFS();
void updateVFSParams(
- MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType,
- const QString& crashDumpsPath, std::chrono::seconds spawnDelay,
+ MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType,
+ const QString& coreDumpsPath, std::chrono::seconds spawnDelay,
QString executableBlacklist);
void setLogLevel(MOBase::log::Levels level);
bool cycleDiagnostics();
- static CrashDumpsType getGlobalCrashDumpsType() { return m_globalCrashDumpsType; }
- static void setGlobalCrashDumpsType(CrashDumpsType crashDumpsType);
- static std::wstring crashDumpsPath();
+ static env::CoreDumpTypes getGlobalCoreDumpType();
+ static void setGlobalCoreDumpType(env::CoreDumpTypes type);
+ static std::wstring getGlobalCoreDumpPath();
/**
* @brief Returns the name of all the mods in the priority order of the given profile.
@@ -487,8 +488,6 @@ private: UsvfsConnector m_USVFS;
UILocker m_UILocker;
-
- static CrashDumpsType m_globalCrashDumpsType;
};
#endif // ORGANIZERCORE_H
diff --git a/src/settings.cpp b/src/settings.cpp index 99b41e1f..a8ada6ba 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -2110,23 +2110,23 @@ void DiagnosticsSettings::setLootLogLevel(lootcli::LogLevels level) set(m_Settings, "Settings", "loot_log_level", level); } -CrashDumpsType DiagnosticsSettings::crashDumpsType() const +env::CoreDumpTypes DiagnosticsSettings::coreDumpType() const { - return get<CrashDumpsType>(m_Settings, - "Settings", "crash_dumps_type", CrashDumpsType::Mini); + return get<env::CoreDumpTypes>(m_Settings, + "Settings", "crash_dumps_type", env::CoreDumpTypes::Mini); } -void DiagnosticsSettings::setCrashDumpsType(CrashDumpsType type) +void DiagnosticsSettings::setCoreDumpType(env::CoreDumpTypes type) { set(m_Settings, "Settings", "crash_dumps_type", type); } -int DiagnosticsSettings::crashDumpsMax() const +int DiagnosticsSettings::maxCoreDumps() const { return get<int>(m_Settings, "Settings", "crash_dumps_max", 5); } -void DiagnosticsSettings::setCrashDumpsMax(int n) +void DiagnosticsSettings::setMaxCoreDumps(int n) { set(m_Settings, "Settings", "crash_dumps_max", n); } diff --git a/src/settings.h b/src/settings.h index fc7789f0..df081c5c 100644 --- a/src/settings.h +++ b/src/settings.h @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #define SETTINGS_H #include "loadmechanism.h" +#include "envdump.h" #include <filterwidget.h> #include <lootcli/lootcli.h> #include <questionboxmemory.h> @@ -651,13 +652,13 @@ public: // crash dump type for both MO and usvfs // - CrashDumpsType crashDumpsType() const; - void setCrashDumpsType(CrashDumpsType type); + env::CoreDumpTypes coreDumpType() const; + void setCoreDumpType(env::CoreDumpTypes type); // maximum number of dump files keps, for both MO and usvfs // - int crashDumpsMax() const; - void setCrashDumpsMax(int n); + int maxCoreDumps() const; + void setMaxCoreDumps(int n); std::chrono::seconds spawnDelay() const; void setSpawnDelay(std::chrono::seconds t); diff --git a/src/settingsdialogdiagnostics.cpp b/src/settingsdialogdiagnostics.cpp index 4ade6900..33175a66 100644 --- a/src/settingsdialogdiagnostics.cpp +++ b/src/settingsdialogdiagnostics.cpp @@ -13,7 +13,7 @@ DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d) setLootLogLevel(); setCrashDumpTypesBox(); - ui->dumpsMaxEdit->setValue(settings().diagnostics().crashDumpsMax()); + ui->dumpsMaxEdit->setValue(settings().diagnostics().maxCoreDumps()); QString logsPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()); @@ -22,7 +22,7 @@ DiagnosticsSettingsTab::DiagnosticsSettingsTab(Settings& s, SettingsDialog& d) ui->diagnosticsExplainedLabel->text() .replace("LOGS_FULL_PATH", logsPath) .replace("LOGS_DIR", QString::fromStdWString(AppConfig::logPath())) - .replace("DUMPS_FULL_PATH", QString::fromStdWString(OrganizerCore::crashDumpsPath())) + .replace("DUMPS_FULL_PATH", QString::fromStdWString(OrganizerCore::getGlobalCoreDumpPath())) .replace("DUMPS_DIR", QString::fromStdWString(AppConfig::dumpsDir())) ); } @@ -78,13 +78,13 @@ void DiagnosticsSettingsTab::setCrashDumpTypesBox() ui->dumpsTypeBox->addItem(text, static_cast<int>(type)); }; - add(QObject::tr("None"), CrashDumpsType::None); - add(QObject::tr("Mini (recommended)"), CrashDumpsType::Mini); - add(QObject::tr("Data"), CrashDumpsType::Data); - add(QObject::tr("Full"), CrashDumpsType::Full); + add(QObject::tr("None"), env::CoreDumpTypes::None); + add(QObject::tr("Mini (recommended)"), env::CoreDumpTypes::Mini); + add(QObject::tr("Data"), env::CoreDumpTypes::Data); + add(QObject::tr("Full"), env::CoreDumpTypes::Full); const auto current = static_cast<int>( - settings().diagnostics().crashDumpsType()); + settings().diagnostics().coreDumpType()); for (int i=0; i<ui->dumpsTypeBox->count(); ++i) { if (ui->dumpsTypeBox->itemData(i) == current) { @@ -99,10 +99,10 @@ void DiagnosticsSettingsTab::update() settings().diagnostics().setLogLevel( static_cast<log::Levels>(ui->logLevelBox->currentData().toInt())); - settings().diagnostics().setCrashDumpsType( - static_cast<CrashDumpsType>(ui->dumpsTypeBox->currentData().toInt())); + settings().diagnostics().setCoreDumpType( + static_cast<env::CoreDumpTypes>(ui->dumpsTypeBox->currentData().toInt())); - settings().diagnostics().setCrashDumpsMax(ui->dumpsMaxEdit->value()); + settings().diagnostics().setMaxCoreDumps(ui->dumpsMaxEdit->value()); settings().diagnostics().setLootLogLevel( static_cast<lootcli::LogLevels>(ui->lootLogLevel->currentData().toInt())); diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index ed6e31ce..c8f2f1c4 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -107,17 +107,22 @@ LogLevel toUsvfsLogLevel(log::Levels level) } } -CrashDumpsType crashDumpsType(int type) +CrashDumpsType toUsvfsCrashDumpsType(env::CoreDumpTypes type) { - switch (static_cast<CrashDumpsType>(type)) { - case CrashDumpsType::Mini: - return CrashDumpsType::Mini; - case CrashDumpsType::Data: - return CrashDumpsType::Data; - case CrashDumpsType::Full: - return CrashDumpsType::Full; - default: - return CrashDumpsType::None; + switch (type) + { + case env::CoreDumpTypes::None: + return CrashDumpsType::None; + + case env::CoreDumpTypes::Data: + return CrashDumpsType::Data; + + case env::CoreDumpTypes::Full: + return CrashDumpsType::Full; + + case env::CoreDumpTypes::Mini: + default: + return CrashDumpsType::Mini; } } @@ -128,9 +133,9 @@ UsvfsConnector::UsvfsConnector() const auto& s = Settings::instance(); const LogLevel logLevel = toUsvfsLogLevel(s.diagnostics().logLevel()); - const CrashDumpsType dumpType = s.diagnostics().crashDumpsType(); + const auto dumpType = toUsvfsCrashDumpsType(s.diagnostics().coreDumpType()); const auto delay = duration_cast<milliseconds>(s.diagnostics().spawnDelay()); - std::string dumpPath = MOShared::ToString(OrganizerCore::crashDumpsPath(), true); + std::string dumpPath = MOShared::ToString(OrganizerCore::getGlobalCoreDumpPath(), true); usvfsParameters* params = usvfsCreateParameters(); @@ -224,7 +229,7 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) } void UsvfsConnector::updateParams( - MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType, + MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType, const QString& crashDumpsPath, std::chrono::seconds spawnDelay, QString executableBlacklist) { @@ -234,7 +239,7 @@ void UsvfsConnector::updateParams( usvfsSetDebugMode(p, FALSE); usvfsSetLogLevel(p, toUsvfsLogLevel(logLevel)); - usvfsSetCrashDumpType(p, crashDumpsType); + usvfsSetCrashDumpType(p, toUsvfsCrashDumpsType(coreDumpType)); usvfsSetCrashDumpPath(p, crashDumpsPath.toStdString().c_str()); usvfsSetProcessDelay(p, duration_cast<milliseconds>(spawnDelay).count()); diff --git a/src/usvfsconnector.h b/src/usvfsconnector.h index 5982778b..bf5d49ce 100644 --- a/src/usvfsconnector.h +++ b/src/usvfsconnector.h @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <usvfsparameters.h> #include <log.h> #include "executableinfo.h" +#include "envdump.h" class LogWorker : public QThread { @@ -87,7 +88,7 @@ public: void updateMapping(const MappingType &mapping); void updateParams( - MOBase::log::Levels logLevel, CrashDumpsType crashDumpsType, + MOBase::log::Levels logLevel, env::CoreDumpTypes coreDumpType, const QString& crashDumpsPath, std::chrono::seconds spawnDelay, QString executableBlacklist); |
