Restructure ContextAwareProfile from a (thread-blocking) polling to a threadsafe-notification

This commit is contained in:
Heather Anderson 2020-04-22 23:16:51 -07:00
parent bfb4eaeb21
commit 61e6e8dfc9
2 changed files with 89 additions and 16 deletions

View file

@ -20,20 +20,62 @@
static const QString RESTRICTED_FLAG_PROPERTY = "RestrictFileAccess"; static const QString RESTRICTED_FLAG_PROPERTY = "RestrictFileAccess";
ContextAwareProfile::ContextAwareProfile(QQmlContext* context) : QMutex RestrictedContextMonitor::gl_monitorMapProtect;
ContextAwareProfileParent(context), _context(context) { RestrictedContextMonitor::TMonitorMap RestrictedContextMonitor::gl_monitorMap;
assert(context);
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<RestrictedContextMonitor>(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) { void ContextAwareProfile::restrictContext(QQmlContext* context, bool restrict) {
RestrictedContextMonitor::TSharedPtr monitor = RestrictedContextMonitor::getMonitor(context, false);
context->setContextProperty(RESTRICTED_FLAG_PROPERTY, restrict); 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()) { if (QThread::currentThread() != thread()) {
bool restrictedResult = false; 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; return restrictedResult;
} }
@ -47,11 +89,10 @@ bool ContextAwareProfile::isRestrictedInternal() {
return true; return true;
} }
bool ContextAwareProfile::isRestricted() { void ContextAwareProfile::onIsRestrictedChanged(bool newValue) {
auto now = usecTimestampNow(); _isRestricted.store(newValue ? 1 : 0);
if (now > _cacheExpiry) { }
_cachedValue = isRestrictedInternal();
_cacheExpiry = now + MAX_CACHE_AGE; bool ContextAwareProfile::isRestricted() {
} return _isRestricted.load() != 0;
return _cachedValue;
} }

View file

@ -12,6 +12,7 @@
#define hifi_ContextAwareProfile_h #define hifi_ContextAwareProfile_h
#include <QtCore/QtGlobal> #include <QtCore/QtGlobal>
#include <QtCore/QMutex>
#if !defined(Q_OS_ANDROID) #if !defined(Q_OS_ANDROID)
#include <QtWebEngine/QQuickWebEngineProfile> #include <QtWebEngine/QQuickWebEngineProfile>
@ -30,12 +31,39 @@ using RequestInterceptorParent = QObject;
class QQmlContext; class QQmlContext;
class RestrictedContextMonitor : public QObject {
Q_OBJECT
public:
typedef std::shared_ptr<RestrictedContextMonitor> TSharedPtr;
typedef std::weak_ptr<RestrictedContextMonitor> 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<QQmlContext*, TWeakPtr> TMonitorMap;
static QMutex gl_monitorMapProtect;
static TMonitorMap gl_monitorMap;
};
class ContextAwareProfile : public ContextAwareProfileParent { class ContextAwareProfile : public ContextAwareProfileParent {
Q_OBJECT Q_OBJECT
public: public:
static void restrictContext(QQmlContext* context, bool restrict = true); static void restrictContext(QQmlContext* context, bool restrict = true);
bool isRestricted(); bool isRestricted();
Q_INVOKABLE bool isRestrictedInternal(); Q_INVOKABLE bool isRestrictedGetProperty();
protected: protected:
class RequestInterceptor : public RequestInterceptorParent { class RequestInterceptor : public RequestInterceptorParent {
@ -48,9 +76,13 @@ protected:
ContextAwareProfile(QQmlContext* parent); ContextAwareProfile(QQmlContext* parent);
QQmlContext* _context{ nullptr }; QQmlContext* _context{ nullptr };
bool _cachedValue{ false }; QAtomicInt _isRestricted{ 0 };
quint64 _cacheExpiry{ 0 };
constexpr static quint64 MAX_CACHE_AGE = MSECS_PER_SECOND; private slots:
void onIsRestrictedChanged(bool newValue);
private:
RestrictedContextMonitor::TSharedPtr _monitor;
}; };
#endif // hifi_FileTypeProfile_h #endif // hifi_FileTypeProfile_h