root/OpenSceneGraph/trunk/src/osg/Referenced.cpp @ 9893

Revision 9893, 9.5 kB (checked in by robert, 5 years ago)

From Mathias Froehlich, "an other topic pointed out by some Microsoft verification tool:
On destruction of some static variables, the global referenced mutex is used
to lock access to the parent lists of state attributes, nodes and so on.
This even happens past the mutex is already destroyed.

This change to Referenced.cpp revision 9851 uses the same technique like the
DeleteHandlerPointer? already in Referenced.cpp to return an zero pointer for
the global referenced lock if it is already destroyed."

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
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#include <stdlib.h>
14
15#include <osg/Referenced>
16#include <osg/Notify>
17#include <osg/ApplicationUsage>
18#include <osg/observer_ptr>
19
20#include <typeinfo>
21#include <memory>
22#include <set>
23
24#include <OpenThreads/ScopedLock>
25#include <OpenThreads/Mutex>
26
27#include <osg/DeleteHandler>
28
29namespace osg
30{
31
32//#define ENFORCE_THREADSAFE
33//#define DEBUG_OBJECT_ALLOCATION_DESTRUCTION
34
35// specialized smart pointer, used to get round auto_ptr<>'s lack of the destructor reseting itself to 0.
36template<typename T>
37struct ResetPointer
38{
39    ResetPointer():
40        _ptr(0) {}
41
42    ResetPointer(T* ptr):
43        _ptr(ptr) {}
44
45    ~ResetPointer()
46    {
47        delete _ptr;
48        _ptr = 0;
49    }
50
51    inline ResetPointer& operator = (T* ptr)
52    {
53        if (_ptr==ptr) return *this;
54        delete _ptr;
55        _ptr = ptr;
56        return *this;
57    }
58
59    void reset(T* ptr)
60    {
61        if (_ptr==ptr) return;
62        delete _ptr;
63        _ptr = ptr;
64    }
65
66    inline T& operator*()  { return *_ptr; }
67
68    inline const T& operator*() const { return *_ptr; }
69
70    inline T* operator->() { return _ptr; }
71
72    inline const T* operator->() const   { return _ptr; }
73
74    T* get() { return _ptr; }
75
76    const T* get() const { return _ptr; }
77
78    T* _ptr;
79};
80
81typedef ResetPointer<DeleteHandler> DeleteHandlerPointer;
82typedef ResetPointer<OpenThreads::Mutex> GlobalMutexPointer;
83
84OpenThreads::Mutex* Referenced::getGlobalReferencedMutex()
85{
86    static GlobalMutexPointer s_ReferencedGlobalMutext = new OpenThreads::Mutex;
87    return s_ReferencedGlobalMutext.get();
88}
89
90typedef std::set<Observer*> ObserverSet;
91
92#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
93struct Referenced::ObserverSetData {
94   OpenThreads::Mutex _mutex;
95   ObserverSet _observers;
96};
97#endif
98
99#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
100static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0;
101#endif
102// static std::auto_ptr<DeleteHandler> s_deleteHandler(0);
103static DeleteHandlerPointer s_deleteHandler(0);
104
105static ApplicationUsageProxy Referenced_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREAD_SAFE_REF_UNREF","");
106
107void Referenced::setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting)
108{
109#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
110    s_useThreadSafeReferenceCounting = enableThreadSafeReferenceCounting;
111#endif
112}
113
114bool Referenced::getThreadSafeReferenceCounting()
115{
116#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
117    return true;
118#else
119    return s_useThreadSafeReferenceCounting;
120#endif
121}
122
123
124void Referenced::setDeleteHandler(DeleteHandler* handler)
125{
126    s_deleteHandler.reset(handler);
127}
128
129DeleteHandler* Referenced::getDeleteHandler()
130{
131    return s_deleteHandler.get();
132}
133
134#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
135OpenThreads::Mutex& getNumObjectMutex()
136{
137    static OpenThreads::Mutex s_numObjectMutex;
138    return s_numObjectMutex;
139}
140static int s_numObjects = 0;
141#endif
142
143Referenced::Referenced():
144#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
145    _observerSetDataPtr(0),
146    _refCount(0)
147#else
148    _refMutex(0),
149    _refCount(0),
150    _observers(0)
151#endif
152{
153#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
154#ifndef ENFORCE_THREADSAFE
155    if (s_useThreadSafeReferenceCounting)
156#endif
157        _refMutex = new OpenThreads::Mutex;
158#endif
159       
160#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
161    {
162        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
163        ++s_numObjects;
164        osg::notify(osg::NOTICE)<<"Object created, total num="<<s_numObjects<<std::endl;
165    }
166#endif
167
168}
169
170Referenced::Referenced(bool threadSafeRefUnref):
171#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
172    _observerSetDataPtr(0),
173    _refCount(0)
174#else
175    _refMutex(0),
176    _refCount(0),
177    _observers(0)
178#endif
179{
180#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
181#ifndef ENFORCE_THREADSAFE
182    if (threadSafeRefUnref)
183#endif
184        _refMutex = new OpenThreads::Mutex;
185#endif
186
187#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
188    {
189        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
190        ++s_numObjects;
191        osg::notify(osg::NOTICE)<<"Object created, total num="<<s_numObjects<<std::endl;
192    }
193#endif
194}
195
196Referenced::Referenced(const Referenced&):
197#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
198    _observerSetDataPtr(0),
199    _refCount(0)
200#else
201    _refMutex(0),
202    _refCount(0),
203    _observers(0)
204#endif
205{
206#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
207#ifndef ENFORCE_THREADSAFE
208    if (s_useThreadSafeReferenceCounting)
209#endif
210        _refMutex = new OpenThreads::Mutex;
211#endif
212
213#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
214    {
215        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
216        ++s_numObjects;
217        osg::notify(osg::NOTICE)<<"Object created, total num="<<s_numObjects<<std::endl;
218    }
219#endif
220}
221
222Referenced::~Referenced()
223{
224#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
225    {
226        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
227        --s_numObjects;
228        osg::notify(osg::NOTICE)<<"Object deleted, total num="<<s_numObjects<<std::endl;
229    }
230#endif
231
232    if (_refCount>0)
233    {
234        notify(WARN)<<"Warning: deleting still referenced object "<<this<<" of type '"<<typeid(this).name()<<"'"<<std::endl;
235        notify(WARN)<<"         the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl;
236    }
237
238#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
239    if (_observers)
240    {
241        ObserverSet* os = static_cast<ObserverSet*>(_observers);
242        for(ObserverSet::iterator itr = os->begin();
243            itr != os->end();
244            ++itr)
245        {
246            (*itr)->objectDeleted(this);
247        }
248        delete os;
249        _observers = 0;
250    }
251
252    if (_refMutex)
253    {
254        OpenThreads::Mutex* tmpMutexPtr = _refMutex;
255        _refMutex = 0;
256        delete tmpMutexPtr;
257    }
258#else
259    ObserverSetData* observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
260    if (observerSetData)
261    {
262        for(ObserverSet::iterator itr = observerSetData->_observers.begin();
263            itr != observerSetData->_observers.end();
264            ++itr)
265        {
266            (*itr)->objectDeleted(this);
267        }
268        _observerSetDataPtr.assign(0, observerSetData);
269        delete observerSetData;
270    }
271#endif
272}
273
274void Referenced::setThreadSafeRefUnref(bool threadSafe)
275{
276#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
277    if (threadSafe)
278    {
279        if (!_refMutex)
280        {
281            // we want thread safe ref()/unref() so assign a mutex
282            _refMutex = new OpenThreads::Mutex;
283        }
284    }
285    else
286    {
287        if (_refMutex)
288        {
289            // we don't want thread safe ref()/unref() so remove any assigned mutex
290            OpenThreads::Mutex* tmpMutexPtr = _refMutex;
291            _refMutex = 0;
292            delete tmpMutexPtr;
293        }
294    }
295#endif
296}
297
298
299void Referenced::unref_nodelete() const
300{
301#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
302    if (_refMutex)
303    {
304        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
305        --_refCount;
306    }
307    else
308    {
309        --_refCount;
310    }
311#else
312    --_refCount;
313#endif
314}
315
316void Referenced::addObserver(Observer* observer) const
317{
318#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
319    ObserverSetData* observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
320    while (0 == observerSetData) {
321        ObserverSetData* newObserverSetData = new ObserverSetData;
322        if (!_observerSetDataPtr.assign(newObserverSetData, 0))
323            delete newObserverSetData;
324        observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
325    }
326    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(observerSetData->_mutex);
327    observerSetData->_observers.insert(observer);
328#else
329    if (_refMutex)
330    {
331        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
332
333        if (!_observers) _observers = new ObserverSet;
334        if (_observers) static_cast<ObserverSet*>(_observers)->insert(observer);
335    }
336    else
337    {
338        if (!_observers) _observers = new ObserverSet;
339        if (_observers) static_cast<ObserverSet*>(_observers)->insert(observer);
340    }
341#endif
342}
343
344void Referenced::removeObserver(Observer* observer) const
345{
346#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
347    ObserverSetData* observerSetData = static_cast<ObserverSetData*>(_observerSetDataPtr.get());
348    if (observerSetData)
349    {
350       OpenThreads::ScopedLock<OpenThreads::Mutex> lock(observerSetData->_mutex);
351       observerSetData->_observers.erase(observer);
352    }
353#else
354    if (_refMutex)
355    {
356        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
357
358        if (_observers) static_cast<ObserverSet*>(_observers)->erase(observer);
359    }
360    else
361    {
362        if (_observers) static_cast<ObserverSet*>(_observers)->erase(observer);
363    }
364#endif
365}
366
367void Referenced::deleteUsingDeleteHandler() const
368{
369    getDeleteHandler()->requestDelete(this);
370}
371
372} // end of namespace osg
Note: See TracBrowser for help on using the browser.