From 348675876dfacb6cdd2373a1a4ae9d814e057df2 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Wed, 3 Feb 2010 18:43:00 +1000 Subject: Really run image reader in its own thread. --- src/declarative/qml/qmlengine.cpp | 15 +- src/declarative/qml/qmlengine.h | 3 - src/declarative/qml/qmlengine_p.h | 1 - .../qml/qmlnetworkaccessmanagerfactory.cpp | 14 -- .../qml/qmlnetworkaccessmanagerfactory.h | 6 +- src/declarative/util/qmlpixmapcache.cpp | 257 +++++++++++---------- src/declarative/util/qmlpixmapcache_p.h | 1 + tools/qmlviewer/qmlviewer.cpp | 6 +- 8 files changed, 140 insertions(+), 163 deletions(-) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index a33aea7..8b52684 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -122,7 +122,7 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) contextClass(0), sharedContext(0), sharedScope(0), objectClass(0), valueTypeClass(0), globalClass(0), cleanup(0), erroredBindings(0), inProgressCreations(0), scriptEngine(this), workerScriptEngine(0), componentAttacheds(0), inBeginCreate(false), - networkAccessManager(0), networkAccessManagerFactory(0), accessManagerValid(false), + networkAccessManager(0), networkAccessManagerFactory(0), typeManager(e), uniqueId(1) { globalClass = new QmlGlobalScriptClass(&scriptEngine); @@ -412,12 +412,6 @@ QmlNetworkAccessManagerFactory *QmlEngine::networkAccessManagerFactory() const return d->networkAccessManagerFactory; } -void QmlEngine::namInvalidated() -{ - Q_D(QmlEngine); - d->accessManagerValid = false; -} - /*! Returns a common QNetworkAccessManager which can be used by any QML element instantiated by this engine. @@ -432,19 +426,12 @@ void QmlEngine::namInvalidated() QNetworkAccessManager *QmlEngine::networkAccessManager() const { Q_D(const QmlEngine); - if (!d->accessManagerValid) { - delete d->networkAccessManagerFactory; - d->networkAccessManagerFactory = 0; - } if (!d->networkAccessManager) { if (d->networkAccessManagerFactory) { - connect(d->networkAccessManagerFactory, SIGNAL(invalidated()) - , this, SLOT(namInvalidated()), Qt::UniqueConnection); d->networkAccessManager = d->networkAccessManagerFactory->create(const_cast(this)); } else { d->networkAccessManager = new QNetworkAccessManager(const_cast(this)); } - d->accessManagerValid = true; } return d->networkAccessManager; } diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h index b9ec277..7ee014a 100644 --- a/src/declarative/qml/qmlengine.h +++ b/src/declarative/qml/qmlengine.h @@ -95,9 +95,6 @@ public: Q_SIGNALS: void quit (); -private Q_SLOTS: - void namInvalidated(); - private: Q_DECLARE_PRIVATE(QmlEngine) }; diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 6f62b40..ddb25a0 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -211,7 +211,6 @@ public: bool inBeginCreate; mutable QNetworkAccessManager *networkAccessManager; mutable QmlNetworkAccessManagerFactory *networkAccessManagerFactory; - mutable bool accessManagerValid; QmlCompositeTypeManager typeManager; QStringList fileImportPath; diff --git a/src/declarative/qml/qmlnetworkaccessmanagerfactory.cpp b/src/declarative/qml/qmlnetworkaccessmanagerfactory.cpp index 6ae20de..76f20d8 100644 --- a/src/declarative/qml/qmlnetworkaccessmanagerfactory.cpp +++ b/src/declarative/qml/qmlnetworkaccessmanagerfactory.cpp @@ -76,18 +76,4 @@ QmlNetworkAccessManagerFactory::~QmlNetworkAccessManagerFactory() implementation of this method is reentrant. */ -/*! - Invalidates all currently created QNetworkAccessManager(s) which - will cause create() to be called for subsequent network access. -*/ -void QmlNetworkAccessManagerFactory::invalidate() -{ - emit invalidated(); -} - -/*! - \internal - \fn QmlNetworkAccessManagerFactory::invalidated() -*/ - QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlnetworkaccessmanagerfactory.h b/src/declarative/qml/qmlnetworkaccessmanagerfactory.h index f64918b..ce9860f 100644 --- a/src/declarative/qml/qmlnetworkaccessmanagerfactory.h +++ b/src/declarative/qml/qmlnetworkaccessmanagerfactory.h @@ -51,16 +51,12 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) class QNetworkAccessManager; -class Q_DECLARATIVE_EXPORT QmlNetworkAccessManagerFactory : public QObject +class Q_DECLARATIVE_EXPORT QmlNetworkAccessManagerFactory { - Q_OBJECT public: virtual ~QmlNetworkAccessManagerFactory(); - void invalidate(); virtual QNetworkAccessManager *create(QObject *parent) = 0; -Q_SIGNALS: - void invalidated(); }; QT_END_NAMESPACE diff --git a/src/declarative/util/qmlpixmapcache.cpp b/src/declarative/util/qmlpixmapcache.cpp index bfe99ac..755863a 100644 --- a/src/declarative/util/qmlpixmapcache.cpp +++ b/src/declarative/util/qmlpixmapcache.cpp @@ -75,6 +75,20 @@ inline uint qHash(const QUrl &uri) return qHash(uri.toEncoded(QUrl::FormattingOption(0x100))); } + +class QmlImageReaderEvent : public QEvent +{ +public: + enum ReadError { NoError, Loading, Decoding }; + + QmlImageReaderEvent(QmlImageReaderEvent::ReadError err, QImage &img) + : QEvent(QEvent::User), error(err), image(img) {} + + ReadError error; + QImage image; +}; + +class QmlImageRequestHandler; class QmlImageReader : public QThread { Q_OBJECT @@ -89,130 +103,61 @@ public: protected: void run(); - bool event(QEvent *event); - -private slots: - void networkRequestDone(); - void namInvalidated() { - accessManagerValid = false; - } private: - QNetworkAccessManager *networkAccessManager() { - if (!accessManagerValid) { - delete accessManager; - accessManager = 0; - } - if (!accessManager) { - if (engine && engine->networkAccessManagerFactory()) { - connect(engine->networkAccessManagerFactory(), SIGNAL(invalidated()) - , this, SLOT(namInvalidated()), Qt::UniqueConnection); - accessManager = engine->networkAccessManagerFactory()->create(this); - } else { - accessManager = new QNetworkAccessManager(this); - } - accessManagerValid = true; - } - return accessManager; - } - QList jobs; QList cancelled; - QHash replies; - QNetworkAccessManager *accessManager; - bool accessManagerValid; QmlEngine *engine; + QmlImageRequestHandler *handler; QMutex mutex; + static QHash readers; + friend class QmlImageRequestHandler; }; QHash QmlImageReader::readers; -class QmlImageReaderEvent : public QEvent -{ -public: - enum ReadError { NoError, Loading, Decoding }; - - QmlImageReaderEvent(QmlImageReaderEvent::ReadError err, QImage &img) - : QEvent(QEvent::User), error(err), image(img) {} - - ReadError error; - QImage image; -}; - -QmlImageReader::QmlImageReader(QmlEngine *eng) - : QThread(eng), accessManager(0), accessManagerValid(false), engine(eng) +class QmlImageRequestHandler : public QObject { - start(QThread::LowPriority); -} - -QmlImageReader::~QmlImageReader() -{ -} - -QmlImageReader *QmlImageReader::instance(QmlEngine *engine) -{ - QmlImageReader *reader = readers.value(engine); - if (!reader) { - static QMutex rmutex; - rmutex.lock(); - reader = new QmlImageReader(engine); - readers.insert(engine, reader); - rmutex.unlock(); + Q_OBJECT +public: + QmlImageRequestHandler(QmlImageReader *read, QmlEngine *eng) + : QObject(), accessManager(0), engine(eng), reader(read) + { + QCoreApplication::postEvent(this, new QEvent(QEvent::User)); } - return reader; -} + QmlPixmapReply *getImage(const QUrl &url); + void cancel(QmlPixmapReply *reply); -QmlPixmapReply *QmlImageReader::getImage(const QUrl &url) -{ - mutex.lock(); - QmlPixmapReply *reply = new QmlPixmapReply(engine, url); - jobs.append(reply); - if (jobs.count() == 1) - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); - mutex.unlock(); - return reply; -} +protected: + bool event(QEvent *event); -void QmlImageReader::cancel(QmlPixmapReply *reply) -{ - mutex.lock(); - if (reply->isLoading()) { - // Already requested. Add to cancel list to be cancelled in reader thread. - cancelled.append(reply); - if (cancelled.count() == 1) - QCoreApplication::postEvent(this, new QEvent(QEvent::User)); - } else { - // Not yet processed - just remove from waiting list - QList::iterator it = jobs.begin(); - while (it != jobs.end()) { - QmlPixmapReply *job = *it; - if (job == reply) { - jobs.erase(it); - break; +private slots: + void networkRequestDone(); + +private: + QNetworkAccessManager *networkAccessManager() { + if (!accessManager) { + if (engine && engine->networkAccessManagerFactory()) { + accessManager = engine->networkAccessManagerFactory()->create(this); + } else { + accessManager = new QNetworkAccessManager(this); } - ++it; } + return accessManager; } - mutex.unlock(); -} -void QmlImageReader::run() -{ -#if defined(Q_OS_LINUX) && defined(SCHED_IDLE) - struct sched_param param; - int policy; - - pthread_getschedparam(pthread_self(), &policy, ¶m); - pthread_setschedparam(pthread_self(), SCHED_IDLE, ¶m); -#endif + QHash replies; + QNetworkAccessManager *accessManager; + QmlEngine *engine; + QmlImageReader *reader; +}; - exec(); -} +//=========================================================================== -bool QmlImageReader::event(QEvent *event) +bool QmlImageRequestHandler::event(QEvent *event) { if (event->type() == QEvent::User) { static int replyDownloadProgress = -1; @@ -224,15 +169,15 @@ bool QmlImageReader::event(QEvent *event) replyDownloadProgress = QNetworkReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); replyFinished = QNetworkReply::staticMetaObject.indexOfSignal("finished()"); downloadProgress = QmlPixmapReply::staticMetaObject.indexOfSignal("downloadProgress(qint64,qint64)"); - thisNetworkRequestDone = QmlImageReader::staticMetaObject.indexOfSlot("networkRequestDone()"); + thisNetworkRequestDone = QmlImageRequestHandler::staticMetaObject.indexOfSlot("networkRequestDone()"); } while (1) { - mutex.lock(); + reader->mutex.lock(); - if (cancelled.count()) { - for (int i = 0; i < cancelled.count(); ++i) { - QmlPixmapReply *job = cancelled.at(i); + if (reader->cancelled.count()) { + for (int i = 0; i < reader->cancelled.count(); ++i) { + QmlPixmapReply *job = reader->cancelled.at(i); QNetworkReply *reply = replies.key(job, 0); if (reply && reply->isRunning()) { replies.remove(reply); @@ -240,29 +185,19 @@ bool QmlImageReader::event(QEvent *event) job->release(true); } } - cancelled.clear(); + reader->cancelled.clear(); } - if (!accessManagerValid) { - // throw away existing requests and reschedule. - QHash::iterator it = replies.begin(); - for (; it != replies.end(); ++it) { - delete it.key(); - jobs.prepend(*it); - } - replies.clear(); - } - - if (!jobs.count() || replies.count() > maxImageRequestCount) { - mutex.unlock(); + if (!reader->jobs.count() || replies.count() > maxImageRequestCount) { + reader->mutex.unlock(); break; } - QmlPixmapReply *runningJob = jobs.takeFirst(); + QmlPixmapReply *runningJob = reader->jobs.takeFirst(); runningJob->addRef(); runningJob->setLoading(); QUrl url = runningJob->url(); - mutex.unlock(); + reader->mutex.unlock(); // fetch QNetworkRequest req(url); @@ -280,7 +215,7 @@ bool QmlImageReader::event(QEvent *event) return QObject::event(event); } -void QmlImageReader::networkRequestDone() +void QmlImageRequestHandler::networkRequestDone() { QNetworkReply *reply = static_cast(sender()); QmlPixmapReply *job = replies.take(reply); @@ -306,6 +241,84 @@ void QmlImageReader::networkRequestDone() reply->deleteLater(); } +//=========================================================================== + +QmlImageReader::QmlImageReader(QmlEngine *eng) + : QThread(eng), engine(eng), handler(0) +{ + start(QThread::LowPriority); +} + +QmlImageReader::~QmlImageReader() +{ + delete handler; +} + +QmlImageReader *QmlImageReader::instance(QmlEngine *engine) +{ + QmlImageReader *reader = readers.value(engine); + if (!reader) { + static QMutex rmutex; + rmutex.lock(); + reader = new QmlImageReader(engine); + readers.insert(engine, reader); + rmutex.unlock(); + } + + return reader; +} + +QmlPixmapReply *QmlImageReader::getImage(const QUrl &url) +{ + mutex.lock(); + QmlPixmapReply *reply = new QmlPixmapReply(engine, url); + jobs.append(reply); + if (jobs.count() == 1 && handler) + QCoreApplication::postEvent(handler, new QEvent(QEvent::User)); + mutex.unlock(); + return reply; +} + +void QmlImageReader::cancel(QmlPixmapReply *reply) +{ + mutex.lock(); + if (reply->isLoading()) { + // Already requested. Add to cancel list to be cancelled in reader thread. + cancelled.append(reply); + if (cancelled.count() == 1 && handler) + QCoreApplication::postEvent(handler, new QEvent(QEvent::User)); + } else { + // Not yet processed - just remove from waiting list + QList::iterator it = jobs.begin(); + while (it != jobs.end()) { + QmlPixmapReply *job = *it; + if (job == reply) { + jobs.erase(it); + break; + } + ++it; + } + } + mutex.unlock(); +} + +void QmlImageReader::run() +{ +#if defined(Q_OS_LINUX) && defined(SCHED_IDLE) + struct sched_param param; + int policy; + + pthread_getschedparam(pthread_self(), &policy, ¶m); + pthread_setschedparam(pthread_self(), SCHED_IDLE, ¶m); +#endif + + handler = new QmlImageRequestHandler(this, engine); + + exec(); +} + +//=========================================================================== + static bool readImage(QIODevice *dev, QPixmap *pixmap) { QImageReader imgio(dev); diff --git a/src/declarative/util/qmlpixmapcache_p.h b/src/declarative/util/qmlpixmapcache_p.h index 0140352..c202ea8 100644 --- a/src/declarative/util/qmlpixmapcache_p.h +++ b/src/declarative/util/qmlpixmapcache_p.h @@ -83,6 +83,7 @@ private: private: Q_DISABLE_COPY(QmlPixmapReply) Q_DECLARE_PRIVATE(QmlPixmapReply) + friend class QmlImageRequestHandler; friend class QmlImageReader; friend class QmlPixmapCache; }; diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index 71ba81c..2b69d97 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -349,9 +349,9 @@ public: QMutexLocker lock(&mutex); QNetworkAccessManager *manager = new QNetworkAccessManager(parent); if (!cookieJar) - cookieJar = new PersistentCookieJar(this); + cookieJar = new PersistentCookieJar(manager); manager->setCookieJar(cookieJar); - cookieJar->setParent(this); + cookieJar->setParent(0); setupProxy(manager); if (cacheSize > 0) { QNetworkDiskCache *cache = new QNetworkDiskCache; @@ -405,7 +405,6 @@ public: void setCacheSize(int size) { if (size != cacheSize) { cacheSize = size; - invalidate(); } } @@ -691,7 +690,6 @@ void QmlViewer::showProxySettings() void QmlViewer::proxySettingsChanged() { - namFactory->invalidate(); reload (); } -- cgit v0.12