root/OpenSceneGraph/trunk/src/osg/OperationThread.cpp @ 13041

Revision 13041, 11.7 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14
15#include <osg/OperationThread>
16#include <osg/GraphicsContext>
17#include <osg/Notify>
18
19using namespace osg;
20using namespace OpenThreads;
21
22struct BlockOperation : public Operation, public Block
23{
24    BlockOperation():
25        Operation("Block",false)
26    {
27        reset();
28    }
29
30    virtual void release()
31    {
32        Block::release();
33    }
34
35    virtual void operator () (Object*)
36    {
37        glFlush();
38        Block::release();
39    }
40};
41
42/////////////////////////////////////////////////////////////////////////////
43//
44//  OperationsQueue
45//
46
47OperationQueue::OperationQueue():
48    osg::Referenced(true)
49{
50    _currentOperationIterator = _operations.begin();
51    _operationsBlock = new RefBlock;
52}
53
54OperationQueue::~OperationQueue()
55{
56}
57
58bool OperationQueue::empty()
59{
60
61  OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
62  return _operations.empty();
63}
64
65unsigned int OperationQueue::getNumOperationsInQueue()
66{
67  OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
68  return static_cast<unsigned int>(_operations.size());
69}
70
71ref_ptr<Operation> OperationQueue::getNextOperation(bool blockIfEmpty)
72{
73    if (blockIfEmpty && _operations.empty())
74    {
75        _operationsBlock->block();
76    }
77
78    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
79
80    if (_operations.empty()) return osg::ref_ptr<Operation>();
81
82    if (_currentOperationIterator == _operations.end())
83    {
84        // iterator at end of operations so reset to beginning.
85        _currentOperationIterator = _operations.begin();
86    }
87
88    ref_ptr<Operation> currentOperation = *_currentOperationIterator;
89
90    if (!currentOperation->getKeep())
91    {
92        // OSG_INFO<<"removing "<<currentOperation->getName()<<std::endl;
93
94        // remove it from the operations queue
95        _currentOperationIterator = _operations.erase(_currentOperationIterator);
96
97        // OSG_INFO<<"size "<<_operations.size()<<std::endl;
98
99        if (_operations.empty())
100        {
101           // OSG_INFO<<"setting block "<<_operations.size()<<std::endl;
102           _operationsBlock->set(false);
103        }
104    }
105    else
106    {
107        // OSG_INFO<<"increment "<<_currentOperation->getName()<<std::endl;
108
109        // move on to the next operation in the list.
110        ++_currentOperationIterator;
111    }
112
113    return currentOperation;
114}
115
116void OperationQueue::add(Operation* operation)
117{
118    OSG_INFO<<"Doing add"<<std::endl;
119
120    // acquire the lock on the operations queue to prevent anyone else for modifying it at the same time
121    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
122
123    // add the operation to the end of the list
124    _operations.push_back(operation);
125
126    _operationsBlock->set(true);
127}
128
129void OperationQueue::remove(Operation* operation)
130{
131    OSG_INFO<<"Doing remove operation"<<std::endl;
132
133    // acquire the lock on the operations queue to prevent anyone else for modifying it at the same time
134    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
135
136    for(Operations::iterator itr = _operations.begin();
137        itr!=_operations.end();)
138    {
139        if ((*itr)==operation)
140        {
141            bool needToResetCurrentIterator = (_currentOperationIterator == itr);
142
143            itr = _operations.erase(itr);
144
145            if (needToResetCurrentIterator) _currentOperationIterator = itr;
146
147        }
148        else ++itr;
149    }
150}
151
152void OperationQueue::remove(const std::string& name)
153{
154    OSG_INFO<<"Doing remove named operation"<<std::endl;
155
156    // acquire the lock on the operations queue to prevent anyone else for modifying it at the same time
157    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
158
159    // find the remove all operations with specified name
160    for(Operations::iterator itr = _operations.begin();
161        itr!=_operations.end();)
162    {
163        if ((*itr)->getName()==name)
164        {
165            bool needToResetCurrentIterator = (_currentOperationIterator == itr);
166
167            itr = _operations.erase(itr);
168
169            if (needToResetCurrentIterator) _currentOperationIterator = itr;
170        }
171        else ++itr;
172    }
173
174    if (_operations.empty())
175    {
176        _operationsBlock->set(false);
177    }
178}
179
180void OperationQueue::removeAllOperations()
181{
182    OSG_INFO<<"Doing remove all operations"<<std::endl;
183
184    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
185
186    _operations.clear();
187
188    // reset current operator.
189    _currentOperationIterator = _operations.begin();
190
191    if (_operations.empty())
192    {
193        _operationsBlock->set(false);
194    }
195}
196
197void OperationQueue::runOperations(Object* callingObject)
198{
199    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
200
201    // reset current operation iterator to beginning if at end.
202    if (_currentOperationIterator==_operations.end()) _currentOperationIterator = _operations.begin();
203
204    for(;
205        _currentOperationIterator != _operations.end();
206        )
207    {
208        ref_ptr<Operation> operation = *_currentOperationIterator;
209
210        if (!operation->getKeep())
211        {
212            _currentOperationIterator = _operations.erase(_currentOperationIterator);
213        }
214        else
215        {
216            ++_currentOperationIterator;
217        }
218
219        // OSG_INFO<<"Doing op "<<_currentOperation->getName()<<" "<<this<<std::endl;
220
221        // call the graphics operation.
222        (*operation)(callingObject);
223    }
224
225    if (_operations.empty())
226    {
227        _operationsBlock->set(false);
228    }
229}
230
231void OperationQueue::releaseOperationsBlock()
232{
233    _operationsBlock->release();
234}
235
236 void OperationQueue::releaseAllOperations()
237{
238    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_operationsMutex);
239
240    for(Operations::iterator itr = _operations.begin();
241        itr!=_operations.end();
242        ++itr)
243    {
244        (*itr)->release();
245    }
246}
247
248
249void OperationQueue::addOperationThread(OperationThread* thread)
250{
251    _operationThreads.insert(thread);
252}
253
254void OperationQueue::removeOperationThread(OperationThread* thread)
255{
256    _operationThreads.erase(thread);
257}
258
259/////////////////////////////////////////////////////////////////////////////
260//
261//  OperationThread
262//
263
264OperationThread::OperationThread():
265    osg::Referenced(true),
266    _parent(0),
267    _done(false)
268{
269    setOperationQueue(new OperationQueue);
270}
271
272OperationThread::~OperationThread()
273{
274    //OSG_NOTICE<<"Destructing graphics thread "<<this<<std::endl;
275
276    cancel();
277
278    //OSG_NOTICE<<"Done Destructing graphics thread "<<this<<std::endl;
279}
280
281void OperationThread::setOperationQueue(OperationQueue* opq)
282{
283    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
284
285    if (_operationQueue == opq) return;
286
287    if (_operationQueue.valid()) _operationQueue->removeOperationThread(this);
288
289    _operationQueue = opq;
290
291    if (_operationQueue.valid()) _operationQueue->addOperationThread(this);
292}
293
294void OperationThread::setDone(bool done)
295{
296    if (_done==done) return;
297
298    _done = true;
299
300    if (done)
301    {
302        OSG_INFO<<"set done "<<this<<std::endl;
303
304        {
305            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
306            if (_currentOperation.valid())
307            {
308                OSG_INFO<<"releasing "<<_currentOperation.get()<<std::endl;
309                _currentOperation->release();
310            }
311        }
312
313        if (_operationQueue.valid()) _operationQueue->releaseOperationsBlock();
314    }
315}
316
317int OperationThread::cancel()
318{
319    OSG_INFO<<"Cancelling OperationThread "<<this<<" isRunning()="<<isRunning()<<std::endl;
320
321    int result = 0;
322    if( isRunning() )
323    {
324
325        _done = true;
326
327        OSG_INFO<<"   Doing cancel "<<this<<std::endl;
328
329        {
330            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
331
332            if (_operationQueue.valid())
333            {
334                 _operationQueue->releaseOperationsBlock();
335                //_operationQueue->releaseAllOperations();
336            }
337
338            if (_currentOperation.valid()) _currentOperation->release();
339        }
340
341        // then wait for the the thread to stop running.
342        while(isRunning())
343        {
344
345#if 1
346            {
347                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
348
349                if (_operationQueue.valid())
350                {
351                    _operationQueue->releaseOperationsBlock();
352                    // _operationQueue->releaseAllOperations();
353                }
354
355                if (_currentOperation.valid()) _currentOperation->release();
356            }
357#endif
358            // commenting out debug info as it was cashing crash on exit, presumable
359            // due to OSG_NOTIFY or std::cout destructing earlier than this destructor.
360            OSG_DEBUG<<"   Waiting for OperationThread to cancel "<<this<<std::endl;
361            OpenThreads::Thread::YieldCurrentThread();
362        }
363    }
364
365    OSG_INFO<<"  OperationThread::cancel() thread cancelled "<<this<<" isRunning()="<<isRunning()<<std::endl;
366
367    return result;
368}
369
370void OperationThread::add(Operation* operation)
371{
372    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
373    if (!_operationQueue) _operationQueue = new OperationQueue;
374    _operationQueue->add(operation);
375}
376
377void OperationThread::remove(Operation* operation)
378{
379    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
380    if (_operationQueue.valid()) _operationQueue->remove(operation);
381}
382
383void OperationThread::remove(const std::string& name)
384{
385    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
386    if (_operationQueue.valid()) _operationQueue->remove(name);
387}
388
389void OperationThread::removeAllOperations()
390{
391    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
392    if (_operationQueue.valid()) _operationQueue->removeAllOperations();
393}
394
395void OperationThread::run()
396{
397    OSG_INFO<<"Doing run "<<this<<" isRunning()="<<isRunning()<<std::endl;
398
399    bool firstTime = true;
400
401    do
402    {
403        // OSG_NOTICE<<"In thread loop "<<this<<std::endl;
404        ref_ptr<Operation> operation;
405        ref_ptr<OperationQueue> operationQueue;
406
407        {
408            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
409            operationQueue = _operationQueue;
410        }
411
412        operation = operationQueue->getNextOperation(true);
413
414        if (_done) break;
415
416        if (operation.valid())
417        {
418            {
419                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
420                _currentOperation = operation;
421            }
422
423            // OSG_INFO<<"Doing op "<<_currentOperation->getName()<<" "<<this<<std::endl;
424
425            // call the graphics operation.
426            (*operation)(_parent.get());
427
428            {
429                OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_threadMutex);
430                _currentOperation = 0;
431            }
432        }
433
434        if (firstTime)
435        {
436            // do a yield to get round a peculiar thread hang when testCancel() is called
437            // in certain circumstances - of which there is no particular pattern.
438            YieldCurrentThread();
439            firstTime = false;
440        }
441
442        // OSG_NOTICE<<"operations.size()="<<_operations.size()<<" done="<<_done<<" testCancel()"<<testCancel()<<std::endl;
443
444    } while (!testCancel() && !_done);
445
446    OSG_INFO<<"exit loop "<<this<<" isRunning()="<<isRunning()<<std::endl;
447
448}
Note: See TracBrowser for help on using the browser.