Merge pull request #8924 from huffman/fix/batch-loader-race

Fix race condition in BatchLoader
This commit is contained in:
Chris Collins 2016-10-27 11:04:24 -07:00 committed by GitHub
commit e7ea30b1cc
2 changed files with 28 additions and 12 deletions

View file

@ -44,33 +44,40 @@ void BatchLoader::start() {
return;
}
for (const auto& rawURL : _urls) {
QUrl url = expandScriptUrl(normalizeScriptURL(rawURL));
qCDebug(scriptengine) << "Loading script at " << url;
QPointer<BatchLoader> self = this;
DependencyManager::get<ScriptCache>()->getScriptContents(url.toString(), [this, self](const QString& url, const QString& contents, bool isURL, bool success) {
if (!self) {
return;
}
auto scriptCache = DependencyManager::get<ScriptCache>();
// Because the ScriptCache may call this callback from differents threads,
// we need to make sure this is thread-safe.
std::lock_guard<std::mutex> lock(_dataLock);
// Use a proxy callback to handle the call and emit the signal in a thread-safe way.
// If BatchLoader is deleted before the callback is called, the subsequent "emit" call will not do
// anything.
ScriptCacheSignalProxy* proxy = new ScriptCacheSignalProxy(scriptCache.data());
scriptCache->getScriptContents(url.toString(), [proxy](const QString& url, const QString& contents, bool isURL, bool success) {
proxy->receivedContent(url, contents, isURL, success);
proxy->deleteLater();
}, false);
connect(proxy, &ScriptCacheSignalProxy::contentAvailable, this, [this](const QString& url, const QString& contents, bool isURL, bool success) {
if (isURL && success) {
_data.insert(url, contents);
qCDebug(scriptengine) << "Loaded: " << url;
} else {
_data.insert(url, QString());
qCDebug(scriptengine) << "Could not load" << url;
qCDebug(scriptengine) << "Could not load: " << url;
}
if (!_finished && _urls.size() == _data.size()) {
_finished = true;
emit finished(_data);
}
}, false);
});
}
}
void ScriptCacheSignalProxy::receivedContent(const QString& url, const QString& contents, bool isURL, bool success) {
emit contentAvailable(url, contents, isURL, success);
}

View file

@ -21,10 +21,20 @@
#include <mutex>
class ScriptCacheSignalProxy : public QObject {
Q_OBJECT
public:
ScriptCacheSignalProxy(QObject* parent) : QObject(parent) { }
void receivedContent(const QString& url, const QString& contents, bool isURL, bool success);
signals:
void contentAvailable(const QString& url, const QString& contents, bool isURL, bool success);
};
class BatchLoader : public QObject {
Q_OBJECT
public:
BatchLoader(const QList<QUrl>& urls) ;
BatchLoader(const QList<QUrl>& urls);
void start();
bool isFinished() const { return _finished; };
@ -39,7 +49,6 @@ private:
bool _finished;
QSet<QUrl> _urls;
QMap<QUrl, QString> _data;
std::mutex _dataLock;
};
#endif // hifi_BatchLoader_h