Add PreloadItem::abort() to avoid no longer required cells from blocking the work thread

coverity_scan^2
scrawl 8 years ago
parent d62c4259bd
commit a46593fa74

@ -55,6 +55,7 @@ namespace MWWorld
, mKeyframeManager(keyframeManager) , mKeyframeManager(keyframeManager)
, mTerrain(terrain) , mTerrain(terrain)
, mPreloadInstances(preloadInstances) , mPreloadInstances(preloadInstances)
, mAbort(false)
{ {
ListModelsVisitor visitor (mMeshes); ListModelsVisitor visitor (mMeshes);
if (cell->getState() == MWWorld::CellStore::State_Loaded) if (cell->getState() == MWWorld::CellStore::State_Loaded)
@ -76,6 +77,11 @@ namespace MWWorld
} }
} }
virtual void abort()
{
mAbort = true;
}
/// Preload work to be called from the worker thread. /// Preload work to be called from the worker thread.
virtual void doWork() virtual void doWork()
{ {
@ -92,6 +98,9 @@ namespace MWWorld
for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it) for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it)
{ {
if (mAbort)
break;
try try
{ {
std::string mesh = *it; std::string mesh = *it;
@ -144,6 +153,8 @@ namespace MWWorld
Terrain::World* mTerrain; Terrain::World* mTerrain;
bool mPreloadInstances; bool mPreloadInstances;
volatile bool mAbort;
// keep a ref to the loaded objects to make sure it stays loaded as long as this cell is in the preloaded state // keep a ref to the loaded objects to make sure it stays loaded as long as this cell is in the preloaded state
std::vector<osg::ref_ptr<const osg::Object> > mPreloadedObjects; std::vector<osg::ref_ptr<const osg::Object> > mPreloadedObjects;
}; };
@ -187,7 +198,10 @@ namespace MWWorld
CellPreloader::~CellPreloader() CellPreloader::~CellPreloader()
{ {
for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();++it) for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();++it)
{
it->second.mWorkItem->abort();
it->second.mWorkItem->waitTillDone(); it->second.mWorkItem->waitTillDone();
}
mPreloadCells.clear(); mPreloadCells.clear();
} }
@ -228,7 +242,10 @@ namespace MWWorld
} }
if (oldestTimestamp + threshold < timestamp) if (oldestTimestamp + threshold < timestamp)
{
oldestCell->second.mWorkItem->abort();
mPreloadCells.erase(oldestCell); mPreloadCells.erase(oldestCell);
}
else else
return; return;
} }
@ -246,7 +263,10 @@ namespace MWWorld
{ {
// do the deletion in the background thread // do the deletion in the background thread
if (found->second.mWorkItem) if (found->second.mWorkItem)
{
found->second.mWorkItem->abort();
mUnrefQueue->push(mPreloadCells[cell].mWorkItem); mUnrefQueue->push(mPreloadCells[cell].mWorkItem);
}
mPreloadCells.erase(found); mPreloadCells.erase(found);
} }
@ -257,7 +277,10 @@ namespace MWWorld
for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();) for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();)
{ {
if (mPreloadCells.size() >= mMinCacheSize && it->second.mTimeStamp < timestamp - mExpiryDelay) if (mPreloadCells.size() >= mMinCacheSize && it->second.mTimeStamp < timestamp - mExpiryDelay)
{
it->second.mWorkItem->abort();
mPreloadCells.erase(it++); mPreloadCells.erase(it++);
}
else else
++it; ++it;
} }

@ -31,6 +31,9 @@ namespace SceneUtil
/// Internal use by the WorkQueue. /// Internal use by the WorkQueue.
void signalDone(); void signalDone();
/// Set abort flag in order to return from doWork() as soon as possible. May not be respected by all WorkItems.
virtual void abort() {}
protected: protected:
OpenThreads::Atomic mDone; OpenThreads::Atomic mDone;
OpenThreads::Mutex mMutex; OpenThreads::Mutex mMutex;

Loading…
Cancel
Save