From 39f26e35f0733f396c98e07e0a1fdb32715e08fe Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 22 Jan 2018 17:17:48 -0800 Subject: [PATCH] backtrace for rc-63 --- interface/src/Application.cpp | 18 +++++++++- interface/src/main.cpp | 7 ++++ libraries/shared/src/SettingInterface.cpp | 41 ++++++++++++----------- libraries/shared/src/SharedUtil.cpp | 38 +++++++++++++++++++++ libraries/shared/src/SharedUtil.h | 26 ++++++++++++-- 5 files changed, 107 insertions(+), 23 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5854501809..62dd1c97cd 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -600,7 +600,23 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { qApp->setProperty(hifi::properties::APP_LOCAL_DATA_PATH, cacheDir); } - Setting::init(); + // FIXME fix the OSX installer to install the resources.rcc binary instead of resource files and remove + // this conditional exclusion +#if !defined(Q_OS_OSX) + { +#if defined(Q_OS_ANDROID) + const QString resourcesBinaryFile = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/resources.rcc"; +#else + const QString resourcesBinaryFile = QCoreApplication::applicationDirPath() + "/resources.rcc"; +#endif + if (!QFile::exists(resourcesBinaryFile)) { + throw std::runtime_error("Unable to find primary resources"); + } + if (!QResource::registerResource(resourcesBinaryFile)) { + throw std::runtime_error("Unable to load primary resources"); + } + } +#endif // Tell the plugin manager about our statically linked plugins auto pluginManager = PluginManager::getInstance(); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 069aeb6775..6bede00558 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -57,6 +57,13 @@ int main(int argc, const char* argv[]) { QCoreApplication::setOrganizationDomain(BuildInfo::ORGANIZATION_DOMAIN); QCoreApplication::setApplicationVersion(BuildInfo::VERSION); + Setting::init(); + + // Instance UserActivityLogger now that the settings are loaded + auto& ual = UserActivityLogger::getInstance(); + + qDebug() << "UserActivityLogger is enabled:" << ual.isEnabled(); + QStringList arguments; for (int i = 0; i < argc; ++i) { arguments << argv[i]; diff --git a/libraries/shared/src/SettingInterface.cpp b/libraries/shared/src/SettingInterface.cpp index 01b9f3884f..9dc126a6ce 100644 --- a/libraries/shared/src/SettingInterface.cpp +++ b/libraries/shared/src/SettingInterface.cpp @@ -20,12 +20,13 @@ #include "SettingHelpers.h" #include "SettingManager.h" #include "SharedLogging.h" +#include "SharedUtil.h" namespace Setting { static QSharedPointer globalManager; // cleans up the settings private instance. Should only be run once at closing down. - void cleanupPrivateInstance() { + static void cleanupPrivateInstance() { // grab the thread before we nuke the instance QThread* settingsManagerThread = DependencyManager::get()->thread(); @@ -34,12 +35,30 @@ namespace Setting { // globalManager.reset(); - + // quit the settings manager thread and wait on it to make sure it's gone settingsManagerThread->quit(); settingsManagerThread->wait(); } - + + static void setupPrivateInstance() { + // Let's set up the settings Private instance on its own thread + QThread* thread = new QThread(); + Q_CHECK_PTR(thread); + thread->setObjectName("Settings Thread"); + + QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer())); + QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + QObject::connect(thread, SIGNAL(finished()), globalManager.data(), SLOT(deleteLater())); + globalManager->moveToThread(thread); + thread->start(); + qCDebug(shared) << "Settings thread started."; + + // Register cleanupPrivateInstance to run inside QCoreApplication's destructor. + qAddPostRoutine(cleanupPrivateInstance); + } + FIXED_Q_COREAPP_STARTUP_FUNCTION(setupPrivateInstance) + // Sets up the settings private instance. Should only be run once at startup. preInit() must be run beforehand, void init() { // Set settings format @@ -59,23 +78,7 @@ namespace Setting { qCDebug(shared) << (deleted ? "Deleted" : "Failed to delete") << "settings lock file" << settingsLockFilename; } - - // Let's set up the settings Private instance on its own thread - QThread* thread = new QThread(); - Q_CHECK_PTR(thread); - thread->setObjectName("Settings Thread"); - globalManager = DependencyManager::set(); - - QObject::connect(thread, SIGNAL(started()), globalManager.data(), SLOT(startTimer())); - QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - QObject::connect(thread, SIGNAL(finished()), globalManager.data(), SLOT(deleteLater())); - globalManager->moveToThread(thread); - thread->start(); - qCDebug(shared) << "Settings thread started."; - - // Register cleanupPrivateInstance to run inside QCoreApplication's destructor. - qAddPostRoutine(cleanupPrivateInstance); } void Interface::init() { diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 2d2ec7c28f..8e5c30711c 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -62,6 +63,43 @@ extern "C" FILE * __cdecl __iob_func(void) { #include "OctalCode.h" #include "SharedLogging.h" +static std::unordered_map stagedGlobalInstances; + + +std::mutex& globalInstancesMutex() { + static std::mutex mutex; + return mutex; +} + +static void commitGlobalInstances() { + std::unique_lock lock(globalInstancesMutex()); + for (const auto& it : stagedGlobalInstances) { + qApp->setProperty(it.first.c_str(), it.second); + } + stagedGlobalInstances.clear(); +} +FIXED_Q_COREAPP_STARTUP_FUNCTION(commitGlobalInstances) + +QVariant getGlobalInstance(const char* propertyName) { + if (qApp) { + return qApp->property(propertyName); + } else { + auto it = stagedGlobalInstances.find(propertyName); + if (it != stagedGlobalInstances.end()) { + return it->second; + } + } + return QVariant(); +} + +void setGlobalInstance(const char* propertyName, const QVariant& variant) { + if (qApp) { + qApp->setProperty(propertyName, variant); + } else { + stagedGlobalInstances[propertyName] = variant; + } +} + static qint64 usecTimestampNowAdjust = 0; // in usec void usecTimestampNowForceClockSkew(qint64 clockSkew) { ::usecTimestampNowAdjust = clockSkew; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 6cf5a4755d..940dc095b8 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -25,6 +25,22 @@ #include #include +// Workaround for https://bugreports.qt.io/browse/QTBUG-54479 +// Wrap target function inside another function that holds +// a unique string identifier and uses it to ensure it only runs once +// by storing a state within the qApp +// We cannot used std::call_once with a static once_flag because +// this is used in shared libraries that are linked by several DLLs +// (ie. plugins), meaning the static will be useless in that case +#define FIXED_Q_COREAPP_STARTUP_FUNCTION(AFUNC) \ + static void AFUNC ## _fixed() { \ + const auto propertyName = std::string(Q_FUNC_INFO) + __FILE__; \ + if (!qApp->property(propertyName.c_str()).toBool()) { \ + AFUNC(); \ + qApp->setProperty(propertyName.c_str(), QVariant(true)); \ + } \ + } \ + Q_COREAPP_STARTUP_FUNCTION(AFUNC ## _fixed) // When writing out avatarEntities to a QByteArray, if the parentID is the ID of MyAvatar, use this ID instead. This allows // the value to be reset when the sessionID changes. @@ -52,6 +68,10 @@ bool destroyGlobalInstance() { return false; } +std::mutex& globalInstancesMutex(); +QVariant getGlobalInstance(const char* propertyName); +void setGlobalInstance(const char* propertyName, const QVariant& variant); + // Provides efficient access to a named global type. By storing the value // in the QApplication by name we can implement the singleton pattern and // have the single instance function across DLL boundaries. @@ -60,9 +80,9 @@ T* globalInstance(const char* propertyName, Args&&... args) { static T* resultInstance { nullptr }; static std::mutex mutex; if (!resultInstance) { - std::unique_lock lock(mutex); + std::unique_lock lock(globalInstancesMutex()); if (!resultInstance) { - auto variant = qApp->property(propertyName); + auto variant = getGlobalInstance(propertyName); if (variant.isNull()) { std::unique_ptr& instancePtr = globalInstancePointer(); if (!instancePtr.get()) { @@ -72,7 +92,7 @@ T* globalInstance(const char* propertyName, Args&&... args) { } void* voidInstance = &(*instancePtr); variant = QVariant::fromValue(voidInstance); - qApp->setProperty(propertyName, variant); + setGlobalInstance(propertyName, variant); } void* returnedVoidInstance = variant.value(); resultInstance = static_cast(returnedVoidInstance);