#include "orbsvcs/Notify/Refcountable.h" #include "tao/debug.h" #include "orbsvcs/Log_Macros.h" #include "ace/Guard_T.h" #if (TAO_NOTIFY_REFCOUNT_DIAGNOSTICS != 0) #include #include #include TAO_BEGIN_VERSIONED_NAMESPACE_DECL /** * @class TAO_Notify_Tracker * * @brief A debugging tool to track the creation of TAO_Notify_Refcountable objects. * * Usage: * Set USE_TAO_NOTIFY_TRACKER defined above to 1 * At any significant point to check object usage * TAO_Notify_Tracker::get_instance().dump(); */ class TAO_Notify_Tracker { public: struct Entry { TAO_Notify_Refcountable* obj; std::string class_name; }; static TAO_Notify_Tracker& get_instance(); void add( TAO_Notify_Refcountable* p); void remove( const TAO_Notify_Refcountable* p); Entry find( const TAO_Notify_Refcountable* p) const; void dump( const char* title = 0 ); private: TAO_Notify_Tracker(); ~TAO_Notify_Tracker(); friend class std::auto_ptr< TAO_Notify_Tracker >; static std::auto_ptr< TAO_Notify_Tracker > s_instance; mutable TAO_SYNCH_MUTEX lock_; typedef std::map EntityMap; EntityMap map_; int id_counter_; int last_dump_count_; }; void TAO_Notify_Refcountable::diagnostic_dump( const char* title ) { TAO_Notify_Tracker::get_instance().dump( title ); } #endif /* TAO_NOTIFY_REFCOUNT_DIAGNOSTICS */ TAO_Notify_Refcountable::TAO_Notify_Refcountable () { } TAO_Notify_Refcountable::~TAO_Notify_Refcountable () { #if (TAO_NOTIFY_REFCOUNT_DIAGNOSTICS != 0) TAO_Notify_Tracker::Entry e = TAO_Notify_Tracker::get_instance().find( this ); if ( e.obj != 0 ) { ORBSVCS_DEBUG ((LM_DEBUG,"object:%x %s(%d) with refcount:%d destroyed incorrectly.\n", e.obj, e.class_name, e.obj->ref_id_, e.obj->refcount_.value() )); if ( e.obj != this || e.obj->ref_id_ != this->ref_id_ ) { ORBSVCS_DEBUG ((LM_DEBUG, " with an ID mismatch %x->%d != %x->%d!\n", this, ref_id_, e.obj, e.obj->ref_id_)); } TAO_Notify_Tracker::get_instance().remove( this ); } #endif CORBA::ULong refcount = this->refcount_.value(); ACE_ASSERT( refcount == 0 ); ACE_UNUSED_ARG(refcount); } CORBA::ULong TAO_Notify_Refcountable::_incr_refcnt () { CORBA::Long refcount = ++this->refcount_; if (TAO_debug_level > 1 ) { ORBSVCS_DEBUG ((LM_DEBUG,"object:%x incr refcount = %d\n", this, refcount )); } #if (TAO_NOTIFY_REFCOUNT_DIAGNOSTICS != 0) // Stack-instantiated-non-servants should never have _incr_refcnt called. // We do not care about stack-instances. Stack-instantiated servants break // the tracker. if ( refcount == 1 ) { TAO_Notify_Tracker::get_instance().add( this ); } #endif return refcount; } CORBA::ULong TAO_Notify_Refcountable::_decr_refcnt () { CORBA::Long refcount = --this->refcount_; if (TAO_debug_level > 1 ) { ORBSVCS_DEBUG ((LM_DEBUG,"object:%x decr refcount = %d\n", this, refcount )); } ACE_ASSERT(refcount >= 0); if (refcount == 0) { #if ( USE_TAO_NOTIFY_TRACKER != 0 ) TAO_Notify_Tracker::get_instance().remove( this ); #endif this->release (); } return refcount; } #if (TAO_NOTIFY_REFCOUNT_DIAGNOSTICS != 0) std::auto_ptr< TAO_Notify_Tracker > TAO_Notify_Tracker::s_instance; TAO_Notify_Tracker::TAO_Notify_Tracker() : id_counter_(0) , last_dump_count_(0) { } TAO_Notify_Tracker::~TAO_Notify_Tracker() { dump( "destruction" ); } void TAO_Notify_Tracker::dump( const char* title ) { ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->lock_); ORBSVCS_DEBUG ((LM_DEBUG,"\nTAO_Notify_Tracker: %s\n", (title ? title : "dump"))); EntityMap::const_iterator iter( map_.begin() ); while ( iter != map_.end() ) { ORBSVCS_DEBUG ((LM_DEBUG,"object:%x %s(%d) with refcount:%d.\n", iter->second.obj, iter->second.class_name, iter->first, iter->second.obj->refcount_.value() )); iter++; } EntityMap::size_type current_count = map_.size(); int diff = ( current_count - last_dump_count_ ); ORBSVCS_DEBUG ((LM_DEBUG,"Count: %u\nDifference: %+d\n", current_count, diff )); last_dump_count_ = current_count; } TAO_Notify_Tracker& TAO_Notify_Tracker::get_instance() { if ( s_instance.get() == 0 ) { s_instance.reset( new TAO_Notify_Tracker ); } return *s_instance; } void TAO_Notify_Tracker::add( TAO_Notify_Refcountable* p ) { if ( p == 0 ) return; ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->lock_); int id = ++id_counter_; Entry e = { p, typeid(*p).name() }; std::pair< EntityMap::iterator, bool > result = map_.insert( std::make_pair( id, e ) ); EntityMap::iterator& it = result.first; if ( result.second == false ) { ORBSVCS_DEBUG ((LM_DEBUG,"object:%x %s(%d) added twice.\n", it->second.obj, it->second.class_name.c_str(), it->first )); } else { p->ref_id_ = id; } } void TAO_Notify_Tracker::remove( const TAO_Notify_Refcountable* p ) { if ( p == 0 ) return; ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->lock_); int ref_id = p->ref_id_; EntityMap::iterator iter( map_.find( ref_id ) ); if ( iter == map_.end() ) { const char* class_name = typeid(*iter->second.obj).name(); ORBSVCS_DEBUG ((LM_DEBUG,"object:%x %s(%d) not found.\n", p, class_name, ref_id )); } else { map_.erase( iter ); } } TAO_Notify_Tracker::Entry TAO_Notify_Tracker::find( const TAO_Notify_Refcountable* p) const { Entry e = { 0, "" }; if ( p == 0 ) return e; ACE_GUARD (TAO_SYNCH_MUTEX, ace_mon, this->lock_); int ref_id = p->ref_id_; EntityMap::const_iterator iter( map_.find( ref_id ) ); if ( iter != map_.end() ) { return iter->second; } return e; } TAO_END_VERSIONED_NAMESPACE_DECL #endif /* TAO_NOTIFY_REFCOUNT_DIAGNOSTICS */