aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/jsapi/qjsengine_p.h
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@theqtcompany.com>2014-11-20 09:07:52 +0100
committerSimon Hausmann <simon.hausmann@digia.com>2014-12-29 14:39:22 +0100
commitefc3cc717ac1a62965465e909cc99acef627cdb1 (patch)
tree9d181ca8e9e299fa99b9b7598bfb83bc53056dde /src/qml/jsapi/qjsengine_p.h
parent65953304a2775e69c7edd46b780aa39f769d32ac (diff)
Make QQmlPropertyCache available in QJSEngine
The QQmlEngine has two containers for property caches, one for QML types and one for all-purpose meta-objects. The latter is rather useful and now being moved to QJSEngine to be available there. Change-Id: Ieab65c400b8a2e410e5f9eee6d603162dbb864d9 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'src/qml/jsapi/qjsengine_p.h')
-rw-r--r--src/qml/jsapi/qjsengine_p.h125
1 files changed, 124 insertions, 1 deletions
diff --git a/src/qml/jsapi/qjsengine_p.h b/src/qml/jsapi/qjsengine_p.h
index 654d0dee56..eba8ffb4be 100644
--- a/src/qml/jsapi/qjsengine_p.h
+++ b/src/qml/jsapi/qjsengine_p.h
@@ -46,11 +46,13 @@
//
#include <QtCore/private/qobject_p.h>
+#include <QtCore/qmutex.h>
#include "qjsengine.h"
QT_BEGIN_NAMESPACE
+class QQmlPropertyCache;
class QJSEnginePrivate : public QObjectPrivate
{
@@ -58,10 +60,131 @@ class QJSEnginePrivate : public QObjectPrivate
public:
static QJSEnginePrivate* get(QJSEngine*e) { return e->d_func(); }
+ static const QJSEnginePrivate* get(const QJSEngine*e) { return e->d_func(); }
- QJSEnginePrivate() {}
+ QJSEnginePrivate() : mutex(QMutex::Recursive) {}
+ ~QJSEnginePrivate();
+
+ // Locker locks the QQmlEnginePrivate data structures for read and write, if necessary.
+ // Currently, locking is only necessary if the threaded loader is running concurrently. If it is
+ // either idle, or is running with the main thread blocked, no locking is necessary. This way
+ // we only pay for locking when we have to.
+ // Consequently, this class should only be used to protect simple accesses or modifications of the
+ // QQmlEnginePrivate structures or operations that can be guaranteed not to start activity
+ // on the loader thread.
+ // The Locker API is identical to QMutexLocker. Locker reuses the QQmlEnginePrivate::mutex
+ // QMutex instance and multiple Lockers are recursive in the same thread.
+ class Locker
+ {
+ public:
+ inline Locker(const QJSEngine *);
+ inline Locker(const QJSEnginePrivate *);
+ inline ~Locker();
+
+ inline void unlock();
+ inline void relock();
+
+ private:
+ const QJSEnginePrivate *m_ep;
+ quint32 m_locked:1;
+ };
+
+ // Shared by QQmlEngine
+ mutable QMutex mutex;
+
+
+ // These methods may be called from the QML loader thread
+ inline QQmlPropertyCache *cache(QObject *obj);
+ inline QQmlPropertyCache *cache(const QMetaObject *);
+
+private:
+ // Must be called locked
+ QQmlPropertyCache *createCache(const QMetaObject *);
+
+ // These members must be protected by a QJSEnginePrivate::Locker as they are required by
+ // the threaded loader. Only access them through their respective accessor methods.
+ QHash<const QMetaObject *, QQmlPropertyCache *> propertyCache;
};
+QJSEnginePrivate::Locker::Locker(const QJSEngine *e)
+: m_ep(QJSEnginePrivate::get(e))
+{
+ relock();
+}
+
+QJSEnginePrivate::Locker::Locker(const QJSEnginePrivate *e)
+: m_ep(e), m_locked(false)
+{
+ relock();
+}
+
+QJSEnginePrivate::Locker::~Locker()
+{
+ unlock();
+}
+
+void QJSEnginePrivate::Locker::unlock()
+{
+ if (m_locked) {
+ m_ep->mutex.unlock();
+ m_locked = false;
+ }
+}
+
+void QJSEnginePrivate::Locker::relock()
+{
+ Q_ASSERT(!m_locked);
+ m_ep->mutex.lock();
+ m_locked = true;
+}
+
+/*!
+Returns a QQmlPropertyCache for \a obj if one is available.
+
+If \a obj is null, being deleted or contains a dynamic meta object 0
+is returned.
+
+The returned cache is not referenced, so if it is to be stored, call addref().
+
+XXX thread There is a potential future race condition in this and all the cache()
+functions. As the QQmlPropertyCache is returned unreferenced, when called
+from the loader thread, it is possible that the cache will have been dereferenced
+and deleted before the loader thread has a chance to use or reference it. This
+can't currently happen as the cache holds a reference to the
+QQmlPropertyCache until the QQmlEngine is destroyed.
+*/
+QQmlPropertyCache *QJSEnginePrivate::cache(QObject *obj)
+{
+ if (!obj || QObjectPrivate::get(obj)->metaObject || QObjectPrivate::get(obj)->wasDeleted)
+ return 0;
+
+ Locker locker(this);
+ const QMetaObject *mo = obj->metaObject();
+ QQmlPropertyCache *rv = propertyCache.value(mo);
+ if (!rv) rv = createCache(mo);
+ return rv;
+}
+
+/*!
+Returns a QQmlPropertyCache for \a metaObject.
+
+As the cache is persisted for the life of the engine, \a metaObject must be
+a static "compile time" meta-object, or a meta-object that is otherwise known to
+exist for the lifetime of the QQmlEngine.
+
+The returned cache is not referenced, so if it is to be stored, call addref().
+*/
+QQmlPropertyCache *QJSEnginePrivate::cache(const QMetaObject *metaObject)
+{
+ Q_ASSERT(metaObject);
+
+ Locker locker(this);
+ QQmlPropertyCache *rv = propertyCache.value(metaObject);
+ if (!rv) rv = createCache(metaObject);
+ return rv;
+}
+
+
QT_END_NAMESPACE
#endif // QJSENGINE_P_H