From 61e6e8dfc9b39c85a4e2865012c1e47723717376 Mon Sep 17 00:00:00 2001 From: Heather Anderson Date: Wed, 22 Apr 2020 23:16:51 -0700 Subject: [PATCH] Restructure ContextAwareProfile from a (thread-blocking) polling to a threadsafe-notification --- .../ui/src/ui/types/ContextAwareProfile.cpp | 65 +++++++++++++++---- .../ui/src/ui/types/ContextAwareProfile.h | 40 ++++++++++-- 2 files changed, 89 insertions(+), 16 deletions(-) diff --git a/libraries/ui/src/ui/types/ContextAwareProfile.cpp b/libraries/ui/src/ui/types/ContextAwareProfile.cpp index f74e8754c9..d5b8d958b6 100644 --- a/libraries/ui/src/ui/types/ContextAwareProfile.cpp +++ b/libraries/ui/src/ui/types/ContextAwareProfile.cpp @@ -20,20 +20,62 @@ static const QString RESTRICTED_FLAG_PROPERTY = "RestrictFileAccess"; -ContextAwareProfile::ContextAwareProfile(QQmlContext* context) : - ContextAwareProfileParent(context), _context(context) { - assert(context); +QMutex RestrictedContextMonitor::gl_monitorMapProtect; +RestrictedContextMonitor::TMonitorMap RestrictedContextMonitor::gl_monitorMap; + +RestrictedContextMonitor::~RestrictedContextMonitor() { + gl_monitorMapProtect.lock(); + TMonitorMap::iterator lookup = gl_monitorMap.find(context); + if (lookup != gl_monitorMap.end()) { + gl_monitorMap.erase(lookup); + } + gl_monitorMapProtect.unlock(); } +RestrictedContextMonitor::TSharedPtr RestrictedContextMonitor::getMonitor(QQmlContext* context, bool createIfMissing) { + TSharedPtr monitor; + + gl_monitorMapProtect.lock(); + TMonitorMap::const_iterator lookup = gl_monitorMap.find(context); + if (lookup != gl_monitorMap.end()) { + monitor = lookup->second.lock(); + assert(monitor); + } else if(createIfMissing) { + monitor = std::make_shared(context); + monitor->selfPtr = monitor; + gl_monitorMap.insert(TMonitorMap::value_type(context, monitor)); + } + gl_monitorMapProtect.unlock(); + return monitor; +} + +ContextAwareProfile::ContextAwareProfile(QQmlContext* context) : ContextAwareProfileParent(context), _context(context) { + assert(context); + + _monitor = RestrictedContextMonitor::getMonitor(context, true); + assert(_monitor); + connect(_monitor.get(), &RestrictedContextMonitor::onIsRestrictedChanged, this, &ContextAwareProfile::onIsRestrictedChanged); + if (_monitor->isUninitialized) { + _monitor->isRestricted = isRestrictedGetProperty(); + _monitor->isUninitialized = false; + } + _isRestricted.store(_monitor->isRestricted ? 1 : 0); +} void ContextAwareProfile::restrictContext(QQmlContext* context, bool restrict) { + RestrictedContextMonitor::TSharedPtr monitor = RestrictedContextMonitor::getMonitor(context, false); + context->setContextProperty(RESTRICTED_FLAG_PROPERTY, restrict); + if (monitor && monitor->isRestricted != restrict) { + monitor->isRestricted = restrict; + monitor->onIsRestrictedChanged(restrict); + } } -bool ContextAwareProfile::isRestrictedInternal() { +bool ContextAwareProfile::isRestrictedGetProperty() { if (QThread::currentThread() != thread()) { bool restrictedResult = false; - BLOCKING_INVOKE_METHOD(this, "isRestrictedInternal", Q_RETURN_ARG(bool, restrictedResult)); + BLOCKING_INVOKE_METHOD(this, "isRestrictedGetProperty", Q_RETURN_ARG(bool, restrictedResult)); return restrictedResult; } @@ -47,11 +89,10 @@ bool ContextAwareProfile::isRestrictedInternal() { return true; } -bool ContextAwareProfile::isRestricted() { - auto now = usecTimestampNow(); - if (now > _cacheExpiry) { - _cachedValue = isRestrictedInternal(); - _cacheExpiry = now + MAX_CACHE_AGE; - } - return _cachedValue; +void ContextAwareProfile::onIsRestrictedChanged(bool newValue) { + _isRestricted.store(newValue ? 1 : 0); +} + +bool ContextAwareProfile::isRestricted() { + return _isRestricted.load() != 0; } diff --git a/libraries/ui/src/ui/types/ContextAwareProfile.h b/libraries/ui/src/ui/types/ContextAwareProfile.h index 3192d2be54..30bdad4b78 100644 --- a/libraries/ui/src/ui/types/ContextAwareProfile.h +++ b/libraries/ui/src/ui/types/ContextAwareProfile.h @@ -12,6 +12,7 @@ #define hifi_ContextAwareProfile_h #include +#include #if !defined(Q_OS_ANDROID) #include @@ -30,12 +31,39 @@ using RequestInterceptorParent = QObject; class QQmlContext; +class RestrictedContextMonitor : public QObject { + Q_OBJECT +public: + typedef std::shared_ptr TSharedPtr; + typedef std::weak_ptr TWeakPtr; + + inline RestrictedContextMonitor(QQmlContext* c) : context(c) {} + ~RestrictedContextMonitor(); + + static TSharedPtr getMonitor(QQmlContext* context, bool createIfMissing); + +signals: + void onIsRestrictedChanged(bool newValue); + +public: + TWeakPtr selfPtr; + QQmlContext* context{ nullptr }; + bool isRestricted{ true }; + bool isUninitialized{ true }; + +private: + typedef std::map TMonitorMap; + + static QMutex gl_monitorMapProtect; + static TMonitorMap gl_monitorMap; +}; + class ContextAwareProfile : public ContextAwareProfileParent { Q_OBJECT public: static void restrictContext(QQmlContext* context, bool restrict = true); bool isRestricted(); - Q_INVOKABLE bool isRestrictedInternal(); + Q_INVOKABLE bool isRestrictedGetProperty(); protected: class RequestInterceptor : public RequestInterceptorParent { @@ -48,9 +76,13 @@ protected: ContextAwareProfile(QQmlContext* parent); QQmlContext* _context{ nullptr }; - bool _cachedValue{ false }; - quint64 _cacheExpiry{ 0 }; - constexpr static quint64 MAX_CACHE_AGE = MSECS_PER_SECOND; + QAtomicInt _isRestricted{ 0 }; + +private slots: + void onIsRestrictedChanged(bool newValue); + +private: + RestrictedContextMonitor::TSharedPtr _monitor; }; #endif // hifi_FileTypeProfile_h