Renamed include/osg/OperationsThread to OperationThread.

Created a new GraphicsThread subclass from OperationThread which allows the
GraphicsContext specific calls to be moved out of the base OperationThread class.

Updated the rest of the OSG to respect these changes.
This commit is contained in:
Robert Osfield
2007-07-12 15:54:45 +00:00
parent 4d7e8b12ae
commit ecf0b58a19
24 changed files with 212 additions and 145 deletions

401
src/osg/OperationThread.cpp Normal file
View File

@@ -0,0 +1,401 @@
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
*
* This library is open source and may be redistributed and/or modified under
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
* (at your option) any later version. The full license is in LICENSE file
* included with this distribution, and on the openscenegraph.org website.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* OpenSceneGraph Public License for more details.
*/
#include <osg/OperationThread>
#include <osg/GraphicsContext>
#include <osg/Notify>
using namespace osg;
using namespace OpenThreads;
struct BlockOperation : public Operation, public Block
{
BlockOperation():
Operation("Block",false)
{
reset();
}
virtual void release()
{
Block::release();
}
virtual void operator () (Object*)
{
glFlush();
Block::release();
}
};
/////////////////////////////////////////////////////////////////////////////
//
// OperationsQueue
//
OperationQueue::OperationQueue():
osg::Referenced(true)
{
_currentOperationIterator = _operations.begin();
_operationsBlock = new RefBlock;
}
OperationQueue::~OperationQueue()
{
}
ref_ptr<Operation> OperationQueue::getNextOperation(bool blockIfEmpty)
{
if (blockIfEmpty && _operations.empty())
{
_operationsBlock->block();
}
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
if (_operations.empty()) return osg::ref_ptr<Operation>();
if (_currentOperationIterator == _operations.end())
{
// iterator at end of operations so reset to begining.
_currentOperationIterator = _operations.begin();
}
ref_ptr<Operation> currentOperation = *_currentOperationIterator;
if (!currentOperation->getKeep())
{
// osg::notify(osg::INFO)<<"removing "<<currentOperation->getName()<<std::endl;
// remove it from the operations queue
_currentOperationIterator = _operations.erase(_currentOperationIterator);
// osg::notify(osg::INFO)<<"size "<<_operations.size()<<std::endl;
if (_operations.empty())
{
// osg::notify(osg::INFO)<<"setting block "<<_operations.size()<<std::endl;
_operationsBlock->set(false);
}
}
else
{
// osg::notify(osg::INFO)<<"increment "<<_currentOperation->getName()<<std::endl;
// move on to the next operation in the list.
++_currentOperationIterator;
}
return currentOperation;
}
void OperationQueue::add(Operation* operation)
{
osg::notify(osg::INFO)<<"Doing add"<<std::endl;
// aquire the lock on the operations queue to prevent anyone else for modifying it at the same time
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
// add the operation to the end of the list
_operations.push_back(operation);
_operationsBlock->set(true);
}
void OperationQueue::remove(Operation* operation)
{
osg::notify(osg::INFO)<<"Doing remove operation"<<std::endl;
// aquire the lock on the operations queue to prevent anyone else for modifying it at the same time
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
for(Operations::iterator itr = _operations.begin();
itr!=_operations.end();)
{
if ((*itr)==operation)
{
bool needToResetCurrentIterator = (_currentOperationIterator == itr);
itr = _operations.erase(itr);
if (needToResetCurrentIterator) _currentOperationIterator = itr;
}
else ++itr;
}
}
void OperationQueue::remove(const std::string& name)
{
osg::notify(osg::INFO)<<"Doing remove named operation"<<std::endl;
// aquire the lock on the operations queue to prevent anyone else for modifying it at the same time
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
// find the remove all operations with specificed name
for(Operations::iterator itr = _operations.begin();
itr!=_operations.end();)
{
if ((*itr)->getName()==name)
{
bool needToResetCurrentIterator = (_currentOperationIterator == itr);
itr = _operations.erase(itr);
if (needToResetCurrentIterator) _currentOperationIterator = itr;
}
else ++itr;
}
if (_operations.empty())
{
_operationsBlock->set(false);
}
}
void OperationQueue::removeAllOperations()
{
osg::notify(osg::INFO)<<"Doing remove all operations"<<std::endl;
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
_operations.clear();
// reset current operator.
_currentOperationIterator = _operations.begin();
if (_operations.empty())
{
_operationsBlock->set(false);
}
}
void OperationQueue::releaseOperationsBlock()
{
_operationsBlock->release();
}
void OperationQueue::releaseAllOperations()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
for(Operations::iterator itr = _operations.begin();
itr!=_operations.end();
++itr)
{
(*itr)->release();
}
}
void OperationQueue::addOperationThread(OperationThread* thread)
{
_operationThreads.insert(thread);
}
void OperationQueue::removeOperationThread(OperationThread* thread)
{
_operationThreads.erase(thread);
}
/////////////////////////////////////////////////////////////////////////////
//
// OperationThread
//
OperationThread::OperationThread():
osg::Referenced(true),
_parent(0),
_done(false)
{
setOperationQueue(new OperationQueue);
}
OperationThread::~OperationThread()
{
//osg::notify(osg::NOTICE)<<"Destructing graphics thread "<<this<<std::endl;
cancel();
//osg::notify(osg::NOTICE)<<"Done Destructing graphics thread "<<this<<std::endl;
}
void OperationThread::setOperationQueue(OperationQueue* opq)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
if (_operationQueue == opq) return;
if (_operationQueue.valid()) _operationQueue->removeOperationThread(this);
_operationQueue = opq;
if (_operationQueue.valid()) _operationQueue->addOperationThread(this);
}
void OperationThread::setDone(bool done)
{
if (_done==done) return;
_done = true;
if (done)
{
osg::notify(osg::INFO)<<"set done "<<this<<std::endl;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
if (_currentOperation.valid())
{
osg::notify(osg::INFO)<<"releasing "<<_currentOperation.get()<<std::endl;
_currentOperation->release();
}
}
if (_operationQueue.valid()) _operationQueue->releaseOperationsBlock();
}
}
int OperationThread::cancel()
{
osg::notify(osg::INFO)<<"Cancelling OperationThread "<<this<<" isRunning()="<<isRunning()<<std::endl;
int result = 0;
if( isRunning() )
{
_done = true;
osg::notify(osg::INFO)<<" Doing cancel "<<this<<std::endl;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
if (_operationQueue.valid())
{
_operationQueue->releaseOperationsBlock();
//_operationQueue->releaseAllOperations();
}
if (_currentOperation.valid()) _currentOperation->release();
}
// then wait for the the thread to stop running.
while(isRunning())
{
#if 1
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
if (_operationQueue.valid())
{
_operationQueue->releaseOperationsBlock();
// _operationQueue->releaseAllOperations();
}
if (_currentOperation.valid()) _currentOperation->release();
}
#endif
// commenting out debug info as it was cashing crash on exit, presumable
// due to osg::notify or std::cout destructing earlier than this destructor.
osg::notify(osg::INFO)<<" Waiting for OperationThread to cancel "<<this<<std::endl;
OpenThreads::Thread::YieldCurrentThread();
}
}
osg::notify(osg::INFO)<<" OperationThread::cancel() thread cancelled "<<this<<" isRunning()="<<isRunning()<<std::endl;
return result;
}
void OperationThread::add(Operation* operation)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
if (!_operationQueue) _operationQueue = new OperationQueue;
_operationQueue->add(operation);
}
void OperationThread::remove(Operation* operation)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
if (_operationQueue.valid()) _operationQueue->remove(operation);
}
void OperationThread::remove(const std::string& name)
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
if (_operationQueue.valid()) _operationQueue->remove(name);
}
void OperationThread::removeAllOperations()
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
if (_operationQueue.valid()) _operationQueue->removeAllOperations();
}
void OperationThread::run()
{
osg::notify(osg::INFO)<<"Doing run "<<this<<" isRunning()="<<isRunning()<<std::endl;
bool firstTime = true;
do
{
// osg::notify(osg::NOTICE)<<"In thread loop "<<this<<std::endl;
ref_ptr<Operation> operation;
ref_ptr<OperationQueue> operationQueue;
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
operationQueue = _operationQueue;
}
operation = operationQueue->getNextOperation(true);
if (_done) break;
if (operation.valid())
{
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
_currentOperation = operation;
}
// osg::notify(osg::INFO)<<"Doing op "<<_currentOperation->getName()<<" "<<this<<std::endl;
// call the graphics operation.
(*operation)(_parent.get());
{
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
_currentOperation = 0;
}
}
if (firstTime)
{
// do a yield to get round a peculiar thread hang when testCancel() is called
// in certain cirumstances - of which there is no particular pattern.
YieldCurrentThread();
firstTime = false;
}
// osg::notify(osg::NOTICE)<<"operations.size()="<<_operations.size()<<" done="<<_done<<" testCancel()"<<testCancel()<<std::endl;
} while (!testCancel() && !_done);
osg::notify(osg::INFO)<<"exit loop "<<this<<" isRunning()="<<isRunning()<<std::endl;
}