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

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

Ran script to remove trailing spaces and tabs

  • 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>
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
90// helper class for forcing the global mutex to be constructed when the library is loaded.
91struct InitGlobalMutexes
92{
93    InitGlobalMutexes()
94    {
95        Referenced::getGlobalReferencedMutex();
96    }
97};
98static InitGlobalMutexes s_initGlobalMutexes;
99
100
101#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
102static bool s_useThreadSafeReferenceCounting = getenv("OSG_THREAD_SAFE_REF_UNREF")!=0;
103#endif
104// static std::auto_ptr<DeleteHandler> s_deleteHandler(0);
105static DeleteHandlerPointer s_deleteHandler(0);
106
107static ApplicationUsageProxy Referenced_e0(ApplicationUsage::ENVIRONMENTAL_VARIABLE,"OSG_THREAD_SAFE_REF_UNREF","");
108
109void Referenced::setThreadSafeReferenceCounting(bool enableThreadSafeReferenceCounting)
110{
111#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
112    s_useThreadSafeReferenceCounting = enableThreadSafeReferenceCounting;
113#endif
114}
115
116bool Referenced::getThreadSafeReferenceCounting()
117{
118#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
119    return true;
120#else
121    return s_useThreadSafeReferenceCounting;
122#endif
123}
124
125
126void Referenced::setDeleteHandler(DeleteHandler* handler)
127{
128    s_deleteHandler.reset(handler);
129}
130
131DeleteHandler* Referenced::getDeleteHandler()
132{
133    return s_deleteHandler.get();
134}
135
136#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
137OpenThreads::Mutex& getNumObjectMutex()
138{
139    static OpenThreads::Mutex s_numObjectMutex;
140    return s_numObjectMutex;
141}
142static int s_numObjects = 0;
143#endif
144
145Referenced::Referenced():
146#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
147    _observerSet(0),
148    _refCount(0)
149#else
150    _refMutex(0),
151    _refCount(0),
152    _observerSet(0)
153#endif
154{
155#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
156#ifndef ENFORCE_THREADSAFE
157    if (s_useThreadSafeReferenceCounting)
158#endif
159        _refMutex = new OpenThreads::Mutex;
160#endif
161
162#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
163    {
164        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
165        ++s_numObjects;
166        printf("Object created, total num=%d\n",s_numObjects);
167    }
168#endif
169
170}
171
172Referenced::Referenced(bool threadSafeRefUnref):
173#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
174    _observerSet(0),
175    _refCount(0)
176#else
177    _refMutex(0),
178    _refCount(0),
179    _observerSet(0)
180#endif
181{
182#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
183#ifndef ENFORCE_THREADSAFE
184    if (threadSafeRefUnref)
185#endif
186        _refMutex = new OpenThreads::Mutex;
187#endif
188
189#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
190    {
191        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
192        ++s_numObjects;
193        printf("Object created, total num=%d\n",s_numObjects);
194    }
195#endif
196}
197
198Referenced::Referenced(const Referenced&):
199#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
200    _observerSet(0),
201    _refCount(0)
202#else
203    _refMutex(0),
204    _refCount(0),
205    _observerSet(0)
206#endif
207{
208#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
209#ifndef ENFORCE_THREADSAFE
210    if (s_useThreadSafeReferenceCounting)
211#endif
212        _refMutex = new OpenThreads::Mutex;
213#endif
214
215#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
216    {
217        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
218        ++s_numObjects;
219        printf("Object created, total num=%d\n",s_numObjects);
220    }
221#endif
222}
223
224Referenced::~Referenced()
225{
226#ifdef DEBUG_OBJECT_ALLOCATION_DESTRUCTION
227    {
228        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(getNumObjectMutex());
229        --s_numObjects;
230        printf("Object created, total num=%d\n",s_numObjects);
231    }
232#endif
233
234    if (_refCount>0)
235    {
236        OSG_WARN<<"Warning: deleting still referenced object "<<this<<" of type '"<<typeid(this).name()<<"'"<<std::endl;
237        OSG_WARN<<"         the final reference count was "<<_refCount<<", memory corruption possible."<<std::endl;
238    }
239
240    // signal observers that we are being deleted.
241    signalObserversAndDelete(true, false);
242
243    // delete the ObserverSet
244#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
245    if (_observerSet.get()) static_cast<ObserverSet*>(_observerSet.get())->unref();
246#else
247    if (_observerSet) static_cast<ObserverSet*>(_observerSet)->unref();
248#endif
249
250#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
251    if (_refMutex) delete _refMutex;
252#endif
253}
254
255ObserverSet* Referenced::getOrCreateObserverSet() const
256{
257#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
258    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
259    while (0 == observerSet)
260    {
261        ObserverSet* newObserverSet = new ObserverSet(this);
262        newObserverSet->ref();
263
264        if (!_observerSet.assign(newObserverSet, 0))
265        {
266            newObserverSet->unref();
267        }
268
269        observerSet = static_cast<ObserverSet*>(_observerSet.get());
270    }
271    return observerSet;
272#else
273    if (_refMutex)
274    {
275        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
276        if (!_observerSet)
277        {
278            _observerSet = new ObserverSet(this);
279            static_cast<ObserverSet*>(_observerSet)->ref();
280        }
281        return static_cast<ObserverSet*>(_observerSet);
282    }
283    else
284    {
285        if (!_observerSet)
286        {
287            _observerSet = new ObserverSet(this);
288            static_cast<ObserverSet*>(_observerSet)->ref();
289        }
290        return static_cast<ObserverSet*>(_observerSet);
291    }
292#endif
293}
294
295void Referenced::addObserver(Observer* observer) const
296{
297    getOrCreateObserverSet()->addObserver(observer);
298}
299
300void Referenced::removeObserver(Observer* observer) const
301{
302    getOrCreateObserverSet()->removeObserver(observer);
303}
304
305void Referenced::signalObserversAndDelete(bool signalDelete, bool doDelete) const
306{
307#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
308    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet.get());
309#else
310    ObserverSet* observerSet = static_cast<ObserverSet*>(_observerSet);
311#endif
312
313    if (observerSet && signalDelete)
314    {
315        observerSet->signalObjectDeleted(const_cast<Referenced*>(this));
316    }
317
318    if (doDelete)
319    {
320        if (_refCount!=0) OSG_NOTICE<<"Warning Referenced::signalObserversAndDelete(,,) doing delete with _refCount="<<_refCount<<std::endl;
321
322        if (getDeleteHandler()) deleteUsingDeleteHandler();
323        else delete this;
324    }
325}
326
327
328void Referenced::setThreadSafeRefUnref(bool threadSafe)
329{
330#if !defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
331    if (threadSafe)
332    {
333        if (!_refMutex)
334        {
335            // we want thread safe ref()/unref() so assign a mutex
336            _refMutex = new OpenThreads::Mutex;
337        }
338    }
339    else
340    {
341        if (_refMutex)
342        {
343            // we don't want thread safe ref()/unref() so remove any assigned mutex
344            OpenThreads::Mutex* tmpMutexPtr = _refMutex;
345            _refMutex = 0;
346            delete tmpMutexPtr;
347        }
348    }
349#endif
350}
351
352int Referenced::unref_nodelete() const
353{
354#if defined(_OSG_REFERENCED_USE_ATOMIC_OPERATIONS)
355    return --_refCount;
356#else
357    if (_refMutex)
358    {
359        OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*_refMutex);
360        return --_refCount;
361    }
362    else
363    {
364        return --_refCount;
365    }
366#endif
367}
368
369void Referenced::deleteUsingDeleteHandler() const
370{
371    getDeleteHandler()->requestDelete(this);
372}
373
374} // end of namespace osg
Note: See TracBrowser for help on using the browser.