2007-07-10 03:04:36 +08:00
|
|
|
/* -*-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/OperationsThread>
|
|
|
|
#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
|
|
|
|
//
|
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
OperationQueue::OperationQueue():
|
|
|
|
osg::Referenced(true)
|
2007-07-10 03:04:36 +08:00
|
|
|
{
|
|
|
|
_currentOperationIterator = _operations.begin();
|
|
|
|
_operationsBlock = new RefBlock;
|
|
|
|
}
|
|
|
|
|
|
|
|
OperationQueue::~OperationQueue()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
ref_ptr<Operation> OperationQueue::getNextOperation(bool blockIfEmpty)
|
2007-07-10 03:04:36 +08:00
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
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;
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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();)
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
if ((*itr)==operation)
|
|
|
|
{
|
|
|
|
bool needToResetCurrentIterator = (_currentOperationIterator == itr);
|
|
|
|
|
|
|
|
itr = _operations.erase(itr);
|
|
|
|
|
|
|
|
if (needToResetCurrentIterator) _currentOperationIterator = itr;
|
|
|
|
|
|
|
|
}
|
2007-07-10 03:04:36 +08:00
|
|
|
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();)
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
if ((*itr)->getName()==name)
|
|
|
|
{
|
|
|
|
bool needToResetCurrentIterator = (_currentOperationIterator == itr);
|
|
|
|
|
|
|
|
itr = _operations.erase(itr);
|
|
|
|
|
|
|
|
if (needToResetCurrentIterator) _currentOperationIterator = itr;
|
|
|
|
}
|
2007-07-10 03:04:36 +08:00
|
|
|
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);
|
2007-07-11 01:36:01 +08:00
|
|
|
|
2007-07-10 03:04:36 +08:00
|
|
|
_operations.clear();
|
2007-07-11 01:36:01 +08:00
|
|
|
|
|
|
|
// reset current operator.
|
|
|
|
_currentOperationIterator = _operations.begin();
|
2007-07-10 03:04:36 +08:00
|
|
|
|
|
|
|
if (_operations.empty())
|
|
|
|
{
|
|
|
|
_operationsBlock->set(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
void OperationQueue::releaseOperationsBlock()
|
|
|
|
{
|
|
|
|
_operationsBlock->release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void OperationQueue::releaseAllOperations()
|
2007-07-10 03:04:36 +08:00
|
|
|
{
|
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
|
2007-07-11 01:36:01 +08:00
|
|
|
|
2007-07-10 03:04:36 +08:00
|
|
|
for(Operations::iterator itr = _operations.begin();
|
|
|
|
itr!=_operations.end();
|
|
|
|
++itr)
|
|
|
|
{
|
|
|
|
(*itr)->release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
|
|
// OperationsThread
|
|
|
|
//
|
|
|
|
|
|
|
|
OperationsThread::OperationsThread():
|
2007-07-11 01:36:01 +08:00
|
|
|
osg::Referenced(true),
|
2007-07-10 03:04:36 +08:00
|
|
|
_parent(0),
|
|
|
|
_done(false)
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
_operationQueue = new OperationQueue;
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
OperationsThread::~OperationsThread()
|
|
|
|
{
|
|
|
|
//osg::notify(osg::NOTICE)<<"Destructing graphics thread "<<this<<std::endl;
|
|
|
|
|
|
|
|
cancel();
|
|
|
|
|
|
|
|
//osg::notify(osg::NOTICE)<<"Done Destructing graphics thread "<<this<<std::endl;
|
|
|
|
}
|
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
void OperationsThread::setOperationQueue(OperationQueue* opq)
|
|
|
|
{
|
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
|
|
|
_operationQueue = opq;
|
|
|
|
}
|
|
|
|
|
2007-07-10 03:04:36 +08:00
|
|
|
void OperationsThread::setDone(bool done)
|
|
|
|
{
|
|
|
|
if (_done==done) return;
|
|
|
|
|
|
|
|
_done = true;
|
|
|
|
|
|
|
|
if (done)
|
|
|
|
{
|
|
|
|
osg::notify(osg::INFO)<<"set done "<<this<<std::endl;
|
|
|
|
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
2007-07-10 03:04:36 +08:00
|
|
|
if (_currentOperation.valid())
|
|
|
|
{
|
|
|
|
osg::notify(osg::INFO)<<"releasing "<<_currentOperation.get()<<std::endl;
|
|
|
|
_currentOperation->release();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
if (_operationQueue.valid()) _operationQueue->releaseOperationsBlock();
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int OperationsThread::cancel()
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
osg::notify(osg::INFO)<<"Cancelling OperationsThread "<<this<<" isRunning()="<<isRunning()<<std::endl;
|
2007-07-10 03:04:36 +08:00
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
if( isRunning() )
|
|
|
|
{
|
|
|
|
|
|
|
|
_done = true;
|
|
|
|
|
|
|
|
osg::notify(osg::INFO)<<" Doing cancel "<<this<<std::endl;
|
|
|
|
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
|
|
|
|
|
|
|
if (_operationQueue.valid())
|
|
|
|
{
|
|
|
|
_operationQueue->releaseOperationsBlock();
|
|
|
|
//_operationQueue->releaseAllOperations();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_currentOperation.valid()) _currentOperation->release();
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// then wait for the the thread to stop running.
|
|
|
|
while(isRunning())
|
|
|
|
{
|
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
#if 1
|
2007-07-10 03:04:36 +08:00
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
2007-07-10 03:04:36 +08:00
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
if (_operationQueue.valid())
|
2007-07-10 03:04:36 +08:00
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
_operationQueue->releaseOperationsBlock();
|
|
|
|
// _operationQueue->releaseAllOperations();
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (_currentOperation.valid()) _currentOperation->release();
|
|
|
|
}
|
2007-07-11 01:36:01 +08:00
|
|
|
#endif
|
2007-07-10 03:04:36 +08:00
|
|
|
// 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 OperationsThread to cancel "<<this<<std::endl;
|
|
|
|
OpenThreads::Thread::YieldCurrentThread();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::notify(osg::INFO)<<" OperationsThread::cancel() thread cancelled "<<this<<" isRunning()="<<isRunning()<<std::endl;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OperationsThread::add(Operation* operation)
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
|
|
|
if (!_operationQueue) _operationQueue = new OperationQueue;
|
|
|
|
_operationQueue->add(operation);
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OperationsThread::remove(Operation* operation)
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
|
|
|
if (_operationQueue.valid()) _operationQueue->remove(operation);
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OperationsThread::remove(const std::string& name)
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
|
|
|
if (_operationQueue.valid()) _operationQueue->remove(name);
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OperationsThread::removeAllOperations()
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
|
|
|
if (_operationQueue.valid()) _operationQueue->removeAllOperations();
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void OperationsThread::run()
|
|
|
|
{
|
|
|
|
// make the graphics context current.
|
|
|
|
GraphicsContext* graphicsContext = dynamic_cast<GraphicsContext*>(_parent.get());
|
|
|
|
if (graphicsContext)
|
|
|
|
{
|
|
|
|
graphicsContext->makeCurrent();
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::notify(osg::INFO)<<"Doing run "<<this<<" isRunning()="<<isRunning()<<std::endl;
|
|
|
|
|
|
|
|
bool firstTime = true;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
// osg::notify(osg::NOTICE)<<"In thread loop "<<this<<std::endl;
|
|
|
|
ref_ptr<Operation> operation;
|
|
|
|
ref_ptr<OperationQueue> operationQueue;
|
|
|
|
|
2007-07-10 03:04:36 +08:00
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
|
|
|
operationQueue = _operationQueue;
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
operation = operationQueue->getNextOperation(true);
|
|
|
|
|
|
|
|
if (_done) break;
|
2007-07-10 03:04:36 +08:00
|
|
|
|
2007-07-11 01:36:01 +08:00
|
|
|
if (operation.valid())
|
2007-07-10 03:04:36 +08:00
|
|
|
{
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
|
|
|
_currentOperation = operation;
|
2007-07-10 03:04:36 +08:00
|
|
|
}
|
2007-07-11 01:36:01 +08:00
|
|
|
|
2007-07-10 03:04:36 +08:00
|
|
|
// osg::notify(osg::INFO)<<"Doing op "<<_currentOperation->getName()<<" "<<this<<std::endl;
|
|
|
|
|
|
|
|
// call the graphics operation.
|
2007-07-11 01:36:01 +08:00
|
|
|
(*operation)(_parent.get());
|
2007-07-10 03:04:36 +08:00
|
|
|
|
|
|
|
{
|
2007-07-11 01:36:01 +08:00
|
|
|
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
|
2007-07-10 03:04:36 +08:00
|
|
|
_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);
|
|
|
|
|
|
|
|
if (graphicsContext)
|
|
|
|
{
|
|
|
|
graphicsContext->releaseContext();
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::notify(osg::INFO)<<"exit loop "<<this<<" isRunning()="<<isRunning()<<std::endl;
|
|
|
|
|
|
|
|
}
|