Lunchbox  1.8.0
referenced.h
1 
2 /* Copyright (c) 2005-2013, Stefan Eilemann <eile@equalizergraphics.com>
3  *
4  * This library is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU Lesser General Public License version 2.1 as published
6  * by the Free Software Foundation.
7  *
8  * This library is distributed in the hope that it will be useful, but WITHOUT
9  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11  * details.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this library; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 #ifndef LUNCHBOX_REFERENCED_H
19 #define LUNCHBOX_REFERENCED_H
20 
21 #include <lunchbox/api.h> // for LUNCHBOX_API
22 #include <lunchbox/atomic.h> // member
23 #include <lunchbox/debug.h> // for LBERROR
24 
25 //#define LUNCHBOX_REFERENCED_DEBUG
26 #ifdef LUNCHBOX_REFERENCED_DEBUG
27 # include <lunchbox/clock.h>
28 # include <lunchbox/hash.h>
29 # include <lunchbox/lockable.h>
30 # include <lunchbox/scopedMutex.h>
31 # include <lunchbox/spinLock.h>
32 #endif
33 
34 namespace lunchbox
35 {
46 {
47 public:
49 #ifdef LUNCHBOX_REFERENCED_DEBUG
50  void ref( const void* holder = 0 ) const
51 #else
52  void ref ( const void* = 0 ) const
53 #endif
54  {
55 #ifndef NDEBUG
56  LBASSERT( !_hasBeenDeleted );
57 #endif
58  ++_refCount;
59 
60 #ifdef LUNCHBOX_REFERENCED_DEBUG
61  if( holder )
62  {
63  std::stringstream cs;
64  cs << "Thread " << Log::instance().getThreadName() << " @ "
65  << Log::instance().getClock().getTime64() << " rc " << _refCount
66  << " from " << backtrace;
67  ScopedFastWrite mutex( _holders );
68  HolderHash::iterator i = _holders->find( holder );
69  LBASSERTINFO( i == _holders->end(), i->second );
70  _holders.data[ holder ] = cs.str();
71  }
72 #endif
73  }
74 
82 #ifdef LUNCHBOX_REFERENCED_DEBUG
83  bool unref( const void* holder = 0 ) const
84 #else
85  bool unref ( const void* = 0 ) const
86 #endif
87  {
88 #ifndef NDEBUG
89  LBASSERT( !_hasBeenDeleted );
90 #endif
91  LBASSERT( _refCount > 0 );
92  const bool last = (--_refCount==0);
93 
94 #ifdef LUNCHBOX_REFERENCED_DEBUG
95  if( holder )
96  {
97  ScopedFastWrite mutex( _holders );
98  HolderHash::iterator i = _holders->find( holder );
99  LBASSERT( i != _holders->end( ));
100  _holders->erase( i );
101  LBASSERT( _holders->find( holder ) == _holders->end( ));
102  }
103 #endif
104 
105  if( last )
106  const_cast< Referenced* >( this )->notifyFree();
107  return last;
108  }
109 
111  int32_t getRefCount() const { return _refCount; }
112 
114 #ifdef LUNCHBOX_REFERENCED_DEBUG
115  void printHolders( std::ostream& os ) const
116  {
117  os << disableFlush << disableHeader << std::endl;
118  {
119  ScopedFastRead mutex( _holders );
120  for( HolderHash::const_iterator i = _holders->begin();
121  i != _holders->end(); ++i )
122  {
123  os << "Holder " << i->first << ": " << i->second
124  << std::endl;
125  }
126  }
127  os << enableHeader << enableFlush;
128  }
129 #else
130  void printHolders( std::ostream& ) const {}
131 #endif
132 
133 protected:
136  : _refCount( 0 )
137  , _hasBeenDeleted( false )
138  {}
139 
142  : _refCount( 0 )
143  , _hasBeenDeleted( false )
144  {}
145 
147  virtual ~Referenced()
148  {
149  LBASSERT( !_hasBeenDeleted );
150  _hasBeenDeleted = true;
151  LBASSERTINFO( _refCount == 0,
152  "Deleting object with ref count " << _refCount );
153  }
154 
156  Referenced& operator = ( const Referenced& /*rhs*/ ) { return *this; }
157 
158  LUNCHBOX_API virtual void notifyFree();
159 
160 private:
161  mutable a_int32_t _refCount;
162  bool _hasBeenDeleted;
163 
164 #ifdef LUNCHBOX_REFERENCED_DEBUG
165  typedef PtrHash< const void*, std::string > HolderHash;
166  mutable Lockable< HolderHash, SpinLock > _holders;
167 #endif
168 };
169 }
170 
171 namespace boost
172 {
174 inline void intrusive_ptr_add_ref( lunchbox::Referenced* referenced )
175 {
176  referenced->ref();
177 }
178 
180 inline void intrusive_ptr_release( lunchbox::Referenced* referenced )
181 {
182  referenced->unref();
183 }
184 }
185 
186 #endif //LUNCHBOX_REFERENCED_H