/* -*-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 #include #include 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(); } }; OperationsThread::OperationsThread(): _parent(0), _done(false) { _operationsBlock = new Block; } OperationsThread::~OperationsThread() { //osg::notify(osg::NOTICE)<<"Destructing graphics thread "< lock(_operationsMutex); if (_currentOperation.valid()) { osg::notify(osg::INFO)<<"releasing "<<_currentOperation.get()<release(); } } _operationsBlock->release(); } } int OperationsThread::cancel() { osg::notify(osg::INFO)<<"Cancelling OperationsThred "<release(); } // release the frameBlock and _databasePagerThreadBlock incase its holding up thread cancelation. _operationsBlock->release(); // then wait for the the thread to stop running. while(isRunning()) { _operationsBlock->release(); { OpenThreads::ScopedLock lock(_operationsMutex); for(OperationQueue::iterator itr = _operations.begin(); itr != _operations.end(); ++itr) { (*itr)->release(); } if (_currentOperation.valid()) _currentOperation->release(); } // 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 "< block = 0; { // aquire the lock on the operations queue to prevent anyone else for modifying it at the same time OpenThreads::ScopedLock lock(_operationsMutex); // add the operation to the end of the list _operations.push_back(operation); if (waitForCompletion) { block = new BlockOperation; _operations.push_back(block.get()); } _operationsBlock->set(true); } if (block.valid()) { // now we wait till the barrier is joined by the graphics thread. block->block(); } } void OperationsThread::remove(Operation* operation) { osg::notify(osg::INFO)<<"Doing remove operation"< lock(_operationsMutex); for(OperationQueue::iterator itr = _operations.begin(); itr!=_operations.end();) { if ((*itr)==operation) itr = _operations.erase(itr); else ++itr; } } void OperationsThread::remove(const std::string& name) { osg::notify(osg::INFO)<<"Doing remove named operation"< lock(_operationsMutex); // find the remove all operations with specificed name for(OperationQueue::iterator itr = _operations.begin(); itr!=_operations.end();) { if ((*itr)->getName()==name) itr = _operations.erase(itr); else ++itr; } if (_operations.empty()) { _operationsBlock->set(false); } } void OperationsThread::removeAllOperations() { osg::notify(osg::INFO)<<"Doing remove all operations"< lock(_operationsMutex); _operations.clear(); if (_operations.empty()) { _operationsBlock->set(false); } } void OperationsThread::run() { // make the graphics context current. GraphicsContext* graphicsContext = dynamic_cast(_parent.get()); if (graphicsContext) { graphicsContext->makeCurrent(); } osg::notify(osg::INFO)<<"Doing run "<block(); // exit from loop if _done is set. if (_done) break; itr = _operations.begin(); } else { if (itr == _operations.end()) itr = _operations.begin(); } osg::notify(osg::INFO)<<"get op "<<_done<<" "< lock(_operationsMutex); if (!_operations.empty()) { // get the next item _currentOperation = *itr; if (!_currentOperation->getKeep()) { osg::notify(osg::INFO)<<"removing "<<_currentOperation->getName()<set(false); } } else { osg::notify(osg::INFO)<<"increment "<<_currentOperation->getName()<getName()<<" "< lock(_operationsMutex); _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()"<releaseContext(); } osg::notify(osg::INFO)<<"exit loop "<