Lunchbox  1.6.0
referenced.h
00001 
00002 /* Copyright (c) 2005-2012, Stefan Eilemann <eile@equalizergraphics.com>
00003  *
00004  * This library is free software; you can redistribute it and/or modify it under
00005  * the terms of the GNU Lesser General Public License version 2.1 as published
00006  * by the Free Software Foundation.
00007  *
00008  * This library is distributed in the hope that it will be useful, but WITHOUT
00009  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00010  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00011  * details.
00012  *
00013  * You should have received a copy of the GNU Lesser General Public License
00014  * along with this library; if not, write to the Free Software Foundation, Inc.,
00015  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00016  */
00017 
00018 #ifndef LUNCHBOX_REFERENCED_H
00019 #define LUNCHBOX_REFERENCED_H
00020 
00021 #include <lunchbox/api.h>      // for LUNCHBOX_API
00022 #include <lunchbox/atomic.h>   // member
00023 #include <lunchbox/debug.h>    // for LBERROR
00024 
00025 //#define LUNCHBOX_REFERENCED_DEBUG
00026 #ifdef LUNCHBOX_REFERENCED_DEBUG
00027 #  include <lunchbox/clock.h>
00028 #  include <lunchbox/hash.h>
00029 #  include <lunchbox/lockable.h>
00030 #  include <lunchbox/scopedMutex.h>
00031 #  include <lunchbox/spinLock.h>
00032 #endif
00033 
00034 namespace lunchbox
00035 {
00045     class Referenced
00046     {
00047     public:
00049         void ref( const void* holder = 0 ) const
00050         {
00051 #ifndef NDEBUG
00052             LBASSERT( !_hasBeenDeleted );
00053 #endif
00054             ++_refCount;
00055 
00056 #ifdef LUNCHBOX_REFERENCED_DEBUG
00057             if( holder )
00058             {
00059                 std::stringstream cs;
00060                 cs << "Thread " << Log::instance().getThreadName() << " @ "
00061                    << Log::instance().getClock().getTime64() << " rc "
00062                    << _refCount << " from " << backtrace;
00063                 ScopedFastWrite mutex( _holders );
00064                 HolderHash::iterator i = _holders->find( holder );
00065                 LBASSERTINFO( i == _holders->end(), i->second );
00066                 _holders.data[ holder ] = cs.str();
00067             }
00068 #endif
00069         }
00070 
00078         bool unref( const void* holder = 0 ) const
00079             {
00080 #ifndef NDEBUG
00081                 LBASSERT( !_hasBeenDeleted );
00082 #endif
00083                 LBASSERT( _refCount > 0 );
00084                 const bool deleteMe = (--_refCount==0);
00085 
00086 #ifdef LUNCHBOX_REFERENCED_DEBUG
00087                 if( holder )
00088                 {
00089                     ScopedFastWrite mutex( _holders );
00090                     HolderHash::iterator i = _holders->find( holder );
00091                     LBASSERT( i != _holders->end( ));
00092                     _holders->erase( i );
00093                     LBASSERT( _holders->find( holder ) == _holders->end( ));
00094                 }
00095 #endif
00096 
00097                 if( deleteMe )
00098                     deleteReferenced( this );
00099                 return deleteMe;
00100             }
00101 
00103         int  getRefCount() const { return _refCount; }
00104 
00106         void printHolders( std::ostream& os ) const
00107             {
00108 #ifdef LUNCHBOX_REFERENCED_DEBUG
00109                 os << disableFlush << disableHeader << std::endl;
00110                 {
00111                     ScopedFastRead mutex( _holders );
00112                     for( HolderHash::const_iterator i = _holders->begin();
00113                          i != _holders->end(); ++i )
00114                     {
00115                         os << "Holder " << i->first << ": " << i->second
00116                            << std::endl;
00117                     }
00118                 }
00119                 os << enableHeader << enableFlush;
00120 #endif
00121             }
00122 
00123     protected:
00125         Referenced()
00126                 : _refCount( 0 )
00127                 , _hasBeenDeleted( false )
00128             {}
00129 
00131         Referenced( const Referenced& )
00132                 : _refCount( 0 )
00133                 , _hasBeenDeleted( false )
00134             {}
00135 
00137         virtual ~Referenced()
00138             {
00139 #ifndef NDEBUG
00140                 LBASSERT( !_hasBeenDeleted );
00141                 _hasBeenDeleted = true;
00142 #endif
00143                 LBASSERTINFO( _refCount == 0,
00144                               "Deleting object with ref count " << _refCount );
00145             }
00146 
00148         Referenced& operator = ( const Referenced& rhs ) { return *this; }
00149 
00150         LUNCHBOX_API virtual void deleteReferenced( const Referenced* ) const;
00151 
00152     private:
00153         mutable a_int32_t _refCount;
00154         bool _hasBeenDeleted;
00155 
00156 #ifdef LUNCHBOX_REFERENCED_DEBUG
00157         typedef PtrHash< const void*, std::string > HolderHash;
00158         mutable Lockable< HolderHash, SpinLock > _holders;
00159 #endif
00160     };
00161 }
00162 
00163 namespace boost
00164 {
00166     inline void intrusive_ptr_add_ref( lunchbox::Referenced* referenced )
00167     {
00168         referenced->ref();
00169     }
00170 
00172     inline void intrusive_ptr_release( lunchbox::Referenced* referenced )
00173     {
00174         referenced->unref();
00175     }
00176 }
00177 
00178 #endif //LUNCHBOX_REFERENCED_H