mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-07-16 03:16:54 +02:00
thread 15 locks Octree thread 1 blocks waiting for Octree lock thread 15 tries to pass a message to thread 1 with QMetaObject::invokeMethod, and hangs thread 15 is blocked on qt message passing to thread 1 ResourceCache::getResource libraries/networking/src/ResourceCache.cpp:57 GeometryCache::getGeometry libraries/render-utils/src/GeometryCache.cpp:1774 ModelEntityItem::isReadyToComputeShape libraries/entities/src/ModelEntityItem.cpp:431 PhysicsEngine::addEntityInternal libraries/physics/src/PhysicsEngine.cpp:67 EntitySimulation::addEntity libraries/entities/src/EntitySimulation.cpp:129 EntityTree::postAddEntity libraries/entities/src/EntityTree.cpp:91 ^ locks simulation EntityTreeElement::readElementDataFromBuffer libraries/entities/src/EntityTreeElement.cpp:773 Octree::readElementData libraries/octree/src/Octree.cpp:301 Octree::readElementData libraries/octree/src/Octree.cpp:354 ... Octree::readBitstreamToTree libraries/octree/src/Octree.cpp:439 OctreeRenderer::processDatagram libraries/octree/src/OctreeRenderer.cpp:136 ^ lockForWrite Octree::_lock OctreePacketProcessor::processPacket interface/src/octree/OctreePacketProcessor.cpp:91 ReceivedPacketProcessor::process libraries/networking/src/ReceivedPacketProcessor.cpp:51 thread 1 is blocked on lockForWrite of Octree::_lock Octree::lockForWrite libraries/octree/src/Octree.h:292 EntityTree::update libraries/entities/src/EntityTree.cpp:668 ^ lockForWrite on Octree:_lock EntityTreeRenderer::update libraries/entities-renderer/src/EntityTreeRenderer.cpp:258 Application::update interface/src/Application.cpp:2189 ^ calls _physicsEngine.stepSimulation() before this Application::idle interface/src/Application.cpp:1535 timer
226 lines
7 KiB
C++
226 lines
7 KiB
C++
//
|
|
// ResourceCache.h
|
|
// libraries/shared/src
|
|
//
|
|
// Created by Andrzej Kapolka on 2/27/14.
|
|
// Copyright 2014 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#ifndef hifi_ResourceCache_h
|
|
#define hifi_ResourceCache_h
|
|
|
|
#include <QHash>
|
|
#include <QList>
|
|
#include <QNetworkReply>
|
|
#include <QNetworkRequest>
|
|
#include <QObject>
|
|
#include <QPointer>
|
|
#include <QSharedPointer>
|
|
#include <QUrl>
|
|
#include <QWeakPointer>
|
|
|
|
#include <DependencyManager.h>
|
|
|
|
class QNetworkReply;
|
|
class QTimer;
|
|
|
|
class Resource;
|
|
|
|
static const qint64 BYTES_PER_MEGABYTES = 1024 * 1024;
|
|
static const qint64 BYTES_PER_GIGABYTES = 1024 * BYTES_PER_MEGABYTES;
|
|
|
|
// Windows can have troubles allocating that much memory in ram sometimes
|
|
// so default cache size at 100 MB on windows (1GB otherwise)
|
|
#ifdef Q_OS_WIN32
|
|
static const qint64 DEFAULT_UNUSED_MAX_SIZE = 100 * BYTES_PER_MEGABYTES;
|
|
#else
|
|
static const qint64 DEFAULT_UNUSED_MAX_SIZE = 1024 * BYTES_PER_MEGABYTES;
|
|
#endif
|
|
static const qint64 MIN_UNUSED_MAX_SIZE = 0;
|
|
static const qint64 MAX_UNUSED_MAX_SIZE = 10 * BYTES_PER_GIGABYTES;
|
|
|
|
// We need to make sure that these items are available for all instances of
|
|
// ResourceCache derived classes. Since we can't count on the ordering of
|
|
// static members destruction, we need to use this Dependency manager implemented
|
|
// object instead
|
|
class ResouceCacheSharedItems : public Dependency {
|
|
SINGLETON_DEPENDENCY
|
|
public:
|
|
QList<QPointer<Resource> > _pendingRequests;
|
|
QList<Resource*> _loadingRequests;
|
|
private:
|
|
ResouceCacheSharedItems() { }
|
|
virtual ~ResouceCacheSharedItems() { }
|
|
};
|
|
|
|
|
|
/// Base class for resource caches.
|
|
class ResourceCache : public QObject {
|
|
Q_OBJECT
|
|
|
|
public:
|
|
static void setRequestLimit(int limit) { _requestLimit = limit; }
|
|
static int getRequestLimit() { return _requestLimit; }
|
|
|
|
void setUnusedResourceCacheSize(qint64 unusedResourcesMaxSize);
|
|
qint64 getUnusedResourceCacheSize() const { return _unusedResourcesMaxSize; }
|
|
|
|
static const QList<Resource*>& getLoadingRequests()
|
|
{ return DependencyManager::get<ResouceCacheSharedItems>()->_loadingRequests; }
|
|
|
|
static int getPendingRequestCount()
|
|
{ return DependencyManager::get<ResouceCacheSharedItems>()->_pendingRequests.size(); }
|
|
|
|
ResourceCache(QObject* parent = NULL);
|
|
virtual ~ResourceCache();
|
|
|
|
void refresh(const QUrl& url);
|
|
|
|
protected:
|
|
qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE;
|
|
qint64 _unusedResourcesSize = 0;
|
|
QMap<int, QSharedPointer<Resource> > _unusedResources;
|
|
|
|
/// Loads a resource from the specified URL.
|
|
/// \param fallback a fallback URL to load if the desired one is unavailable
|
|
/// \param delayLoad if true, don't load the resource immediately; wait until load is first requested
|
|
/// \param extra extra data to pass to the creator, if appropriate
|
|
Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(),
|
|
bool delayLoad = false, void* extra = NULL, bool block = true);
|
|
|
|
/// Creates a new resource.
|
|
virtual QSharedPointer<Resource> createResource(const QUrl& url,
|
|
const QSharedPointer<Resource>& fallback, bool delayLoad, const void* extra) = 0;
|
|
|
|
void addUnusedResource(const QSharedPointer<Resource>& resource);
|
|
void removeUnusedResource(const QSharedPointer<Resource>& resource);
|
|
void reserveUnusedResource(qint64 resourceSize);
|
|
|
|
static void attemptRequest(Resource* resource);
|
|
static void requestCompleted(Resource* resource);
|
|
|
|
private:
|
|
friend class Resource;
|
|
|
|
QHash<QUrl, QWeakPointer<Resource> > _resources;
|
|
int _lastLRUKey = 0;
|
|
|
|
static int _requestLimit;
|
|
};
|
|
|
|
/// Base class for resources.
|
|
class Resource : public QObject {
|
|
Q_OBJECT
|
|
|
|
public:
|
|
|
|
Resource(const QUrl& url, bool delayLoad = false);
|
|
~Resource();
|
|
|
|
/// Returns the key last used to identify this resource in the unused map.
|
|
int getLRUKey() const { return _lruKey; }
|
|
|
|
/// Makes sure that the resource has started loading.
|
|
void ensureLoading();
|
|
|
|
/// Sets the load priority for one owner.
|
|
virtual void setLoadPriority(const QPointer<QObject>& owner, float priority);
|
|
|
|
/// Sets a set of priorities at once.
|
|
virtual void setLoadPriorities(const QHash<QPointer<QObject>, float>& priorities);
|
|
|
|
/// Clears the load priority for one owner.
|
|
virtual void clearLoadPriority(const QPointer<QObject>& owner);
|
|
|
|
/// Returns the highest load priority across all owners.
|
|
float getLoadPriority();
|
|
|
|
/// Checks whether the resource has loaded.
|
|
bool isLoaded() const { return _loaded; }
|
|
|
|
/// For loading resources, returns the number of bytes received.
|
|
qint64 getBytesReceived() const { return _bytesReceived; }
|
|
|
|
/// For loading resources, returns the number of total bytes (<= zero if unknown).
|
|
qint64 getBytesTotal() const { return _bytesTotal; }
|
|
|
|
/// For loading resources, returns the load progress.
|
|
float getProgress() const { return (_bytesTotal <= 0) ? 0.0f : (float)_bytesReceived / _bytesTotal; }
|
|
|
|
/// Refreshes the resource.
|
|
void refresh();
|
|
|
|
void setSelf(const QWeakPointer<Resource>& self) { _self = self; }
|
|
|
|
void setCache(ResourceCache* cache) { _cache = cache; }
|
|
|
|
Q_INVOKABLE void allReferencesCleared();
|
|
|
|
const QUrl& getURL() const { return _url; }
|
|
|
|
signals:
|
|
|
|
/// Fired when the resource has been loaded.
|
|
void loaded();
|
|
|
|
protected slots:
|
|
|
|
void attemptRequest();
|
|
|
|
/// Refreshes the resource if the last modified date on the network
|
|
/// is greater than the last modified date in the cache.
|
|
void maybeRefresh();
|
|
|
|
protected:
|
|
|
|
virtual void init();
|
|
|
|
/// Called when the download has finished. The recipient should delete the reply when done with it.
|
|
virtual void downloadFinished(QNetworkReply* reply) = 0;
|
|
|
|
/// Should be called by subclasses when all the loading that will be done has been done.
|
|
Q_INVOKABLE void finishedLoading(bool success);
|
|
|
|
/// Reinserts this resource into the cache.
|
|
virtual void reinsert();
|
|
|
|
QUrl _url;
|
|
QNetworkRequest _request;
|
|
bool _startedLoading = false;
|
|
bool _failedToLoad = false;
|
|
bool _loaded = false;
|
|
QHash<QPointer<QObject>, float> _loadPriorities;
|
|
QWeakPointer<Resource> _self;
|
|
QPointer<ResourceCache> _cache;
|
|
|
|
private slots:
|
|
|
|
void handleDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
|
void handleReplyError();
|
|
void handleReplyFinished();
|
|
void handleReplyTimeout();
|
|
|
|
private:
|
|
|
|
void setLRUKey(int lruKey) { _lruKey = lruKey; }
|
|
|
|
void makeRequest();
|
|
|
|
void handleReplyError(QNetworkReply::NetworkError error, QDebug debug);
|
|
|
|
friend class ResourceCache;
|
|
|
|
int _lruKey = 0;
|
|
QNetworkReply* _reply = nullptr;
|
|
QTimer* _replyTimer = nullptr;
|
|
qint64 _bytesReceived = 0;
|
|
qint64 _bytesTotal = 0;
|
|
int _attempts = 0;
|
|
};
|
|
|
|
uint qHash(const QPointer<QObject>& value, uint seed = 0);
|
|
|
|
#endif // hifi_ResourceCache_h
|