43 #include "Teuchos_Assert.hpp" 44 #include "Teuchos_Exceptions.hpp" 65 RCPNodeInfo() : nodePtr(0) {}
67 : info(info_in), nodePtr(nodePtr_in)
74 typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
77 typedef std::multimap<const void*, RCPNodeInfo> rcp_node_list_t;
80 class RCPNodeInfoListPred {
82 bool operator()(
const rcp_node_list_t::value_type &v1,
83 const rcp_node_list_t::value_type &v2
87 return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
89 return v1.first < v2.first;
112 rcp_node_list_t*& rcp_node_list()
114 static rcp_node_list_t *s_rcp_node_list = 0;
122 return s_rcp_node_list;
126 bool& loc_isTracingActiveRCPNodes()
128 static bool s_loc_isTracingActiveRCPNodes =
129 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 135 return s_loc_isTracingActiveRCPNodes;
142 return s_loc_rcpNodeStatistics;
146 bool& loc_printRCPNodeStatisticsOnExit()
148 static bool s_loc_printRCPNodeStatisticsOnExit =
false;
149 return s_loc_printRCPNodeStatisticsOnExit;
153 bool& loc_printActiveRcpNodesOnExit()
155 static bool s_loc_printActiveRcpNodesOnExit =
true;
156 return s_loc_printActiveRcpNodesOnExit;
175 const void* base_obj_map_key_void_ptr = rcp_node->get_base_obj_map_key_void_ptr();
176 if (base_obj_map_key_void_ptr)
177 return base_obj_map_key_void_ptr;
185 std::ostringstream oss;
187 <<
"RCPNode {address=" 190 <<
", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr()
193 <<
", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node)
196 <<
", insertionNumber="<< rcp_node->insertion_number()
214 void RCPNode::set_extra_data(
215 const any &extra_data,
const std::string& name
220 if(extra_data_map_==NULL) {
221 extra_data_map_ =
new extra_data_map_t;
223 const std::string type_and_name( extra_data.
typeName() + std::string(
":") + name );
224 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
227 (itr != extra_data_map_->end() && force_unique), std::invalid_argument
228 ,
"Error, the type:name pair \'" << type_and_name
229 <<
"\' already exists and force_unique==true!" );
231 if (itr != extra_data_map_->end()) {
233 itr->second = extra_data_entry_t(extra_data,destroy_when);
237 (*extra_data_map_)[type_and_name] =
238 extra_data_entry_t(extra_data,destroy_when);
243 any& RCPNode::get_extra_data(
const std::string& type_name,
const std::string& name )
247 extra_data_map_==NULL, std::invalid_argument
248 ,
"Error, no extra data has been set yet!" );
250 any *extra_data = get_optional_extra_data(type_name,name);
253 const std::string type_and_name( type_name + std::string(
":") + name );
255 extra_data == NULL, std::invalid_argument
256 ,
"Error, the type:name pair \'" << type_and_name <<
"\' is not found!" );
263 any* RCPNode::get_optional_extra_data(
const std::string& type_name,
264 const std::string& name )
266 if( extra_data_map_ == NULL )
return NULL;
267 const std::string type_and_name( type_name + std::string(
":") + name );
268 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
269 if(itr != extra_data_map_->end())
270 return &(*itr).second.extra_data;
275 void RCPNode::impl_pre_delete_extra_data()
278 extra_data_map_t::iterator itr = extra_data_map_->begin();
279 itr != extra_data_map_->end();
283 extra_data_map_t::value_type &entry = *itr;
284 if(entry.second.destroy_when == PRE_DESTROY)
285 entry.second.extra_data =
any();
298 bool RCPNodeTracer::isTracingActiveRCPNodes()
300 return loc_isTracingActiveRCPNodes();
304 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 305 void RCPNodeTracer::setTracingActiveRCPNodes(
bool tracingActiveNodes)
307 loc_isTracingActiveRCPNodes() = tracingActiveNodes;
312 int RCPNodeTracer::numActiveRCPNodes()
316 return rcp_node_list()->size();
322 RCPNodeTracer::getRCPNodeStatistics()
324 return loc_rcpNodeStatistics();
327 void RCPNodeTracer::printRCPNodeStatistics(
332 <<
"\n*** RCPNode Tracing statistics:" 334 <<
"\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
335 <<
"\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
336 <<
"\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
341 void RCPNodeTracer::setPrintRCPNodeStatisticsOnExit(
342 bool printRCPNodeStatisticsOnExit)
344 loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
348 bool RCPNodeTracer::getPrintRCPNodeStatisticsOnExit()
350 return loc_printRCPNodeStatisticsOnExit();
354 void RCPNodeTracer::setPrintActiveRcpNodesOnExit(
bool printActiveRcpNodesOnExit)
356 loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
360 bool RCPNodeTracer::getPrintActiveRcpNodesOnExit()
362 return loc_printActiveRcpNodesOnExit();
366 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
368 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 370 <<
"\nCalled printActiveRCPNodes() :" 371 <<
" rcp_node_list.size() = " << rcp_node_list().size() <<
"\n";
372 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 373 if (loc_isTracingActiveRCPNodes()) {
375 if (rcp_node_list()->size() > 0) {
376 out << getActiveRCPNodeHeaderString();
381 typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
382 rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
383 std::sort(rcp_node_vec.begin(), rcp_node_vec.end(), RCPNodeInfoListPred());
385 typedef rcp_node_vec_t::const_iterator itr_t;
387 for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
388 const rcp_node_list_t::value_type &entry = *itr;
392 << std::setw(3) << std::right << i << std::left
393 <<
": RCPNode (map_key_void_ptr=" << entry.first <<
")\n" 394 <<
" Information = " << entry.second.info <<
"\n" 395 <<
" RCPNode address = " << entry.second.nodePtr <<
"\n" 397 <<
" insertionNumber = " << entry.second.nodePtr->insertion_number()
403 << getCommonDebugNotesString();
412 void RCPNodeTracer::addNewRCPNode(
RCPNode* rcp_node,
const std::string &info )
416 static int insertionNumber = 0;
421 rcp_node->set_insertion_number(insertionNumber);
424 if (loc_isTracingActiveRCPNodes()) {
428 #ifdef RCP_NODE_DEBUG_TRACE_PRINT 430 <<
"RCPNodeTracer::addNewRCPNode(...): Adding " 431 << convertRCPNodeToString(rcp_node) <<
" ...\n";
436 const void *
const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
439 typedef rcp_node_list_t::iterator itr_t;
440 typedef std::pair<itr_t, itr_t> itr_itr_t;
441 const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
442 const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
443 RCPNode *previous_rcp_node = 0;
444 bool previous_rcp_node_has_ownership =
false;
445 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
446 previous_rcp_node = itr->second.nodePtr;
448 previous_rcp_node_has_ownership =
true;
453 rcp_node_already_exists && rcp_node->
has_ownership() && previous_rcp_node_has_ownership,
455 "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n" 456 "RCPNode object to an existing managed object in another RCPNode:\n" 458 " New " << convertRCPNodeToString(rcp_node) <<
"\n" 460 " Existing " << convertRCPNodeToString(previous_rcp_node) <<
"\n" 462 " Number current nodes = " << rcp_node_list()->size() <<
"\n" 464 "This may indicate that the user might be trying to create a weak RCP to an existing\n" 465 "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n" 466 "or an equivalent function?\n" 468 << getCommonDebugNotesString();
477 (*rcp_node_list()).insert(
479 std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
488 ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
489 loc_rcpNodeStatistics().maxNumRCPNodes =
490 TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
495 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \ 496 TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \ 498 "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \ 499 << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \ 500 " active RCP nodes being traced even though all nodes should be traced." \ 501 " This should not be possible and can only be an internal programming error!") 504 void RCPNodeTracer::removeRCPNode(
RCPNode* rcp_node )
517 typedef rcp_node_list_t::iterator itr_t;
518 typedef std::pair<itr_t, itr_t> itr_itr_t;
520 const itr_itr_t itr_itr =
521 rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
522 const bool rcp_node_exists = itr_itr.first != itr_itr.second;
524 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING 528 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
537 if (rcp_node_exists) {
538 #ifdef RCP_NODE_DEBUG_TRACE_PRINT 540 <<
"RCPNodeTracer::removeRCPNode(...): Removing " 541 << convertRCPNodeToString(rcp_node) <<
" ...\n";
543 bool foundRCPNode =
false;
544 for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
545 if (itr->second.nodePtr == rcp_node) {
546 rcp_node_list()->erase(itr);
547 ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
553 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
559 RCPNode* RCPNodeTracer::getExistingRCPNodeGivenLookupKey(
const void* p)
561 typedef rcp_node_list_t::iterator itr_t;
562 typedef std::pair<itr_t, itr_t> itr_itr_t;
565 const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
566 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
567 RCPNode* rcpNode = itr->second.nodePtr;
578 std::string RCPNodeTracer::getActiveRCPNodeHeaderString()
582 "\n*** Warning! The following Teuchos::RCPNode objects were created but have" 583 "\n*** not been destroyed yet. A memory checking tool may complain that these" 584 "\n*** objects are not destroyed correctly." 586 "\n*** There can be many possible reasons that this might occur including:" 588 "\n*** a) The program called abort() or exit() before main() was finished." 589 "\n*** All of the objects that would have been freed through destructors" 590 "\n*** are not freed but some compilers (e.g. GCC) will still call the" 591 "\n*** destructors on static objects (which is what causes this message" 592 "\n*** to be printed)." 594 "\n*** b) The program is using raw new/delete to manage some objects and" 595 "\n*** delete was not called correctly and the objects not deleted hold" 596 "\n*** other objects through reference-counted pointers." 598 "\n*** c) This may be an indication that these objects may be involved in" 599 "\n*** a circular dependency of reference-counted managed objects." 605 std::string RCPNodeTracer::getCommonDebugNotesString()
608 "NOTE: To debug issues, open a debugger, and set a break point in the function where\n" 609 "the RCPNode object is first created to determine the context where the object first\n" 610 "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n" 611 "breakpoints in the code. For example, in GDB one can perform:\n" 613 "1) Open the debugger (GDB) and run the program again to get updated object addresses\n" 615 "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n" 616 "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n" 618 " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n" 619 " (gdb) cond 1 insertionNumber==3 [ENTER]\n" 621 "3) Run the program in the debugger. In GDB, do:\n" 623 " (gdb) run [ENTER]\n" 625 "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n" 635 ActiveRCPNodesSetup::ActiveRCPNodesSetup()
637 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 638 std::cerr <<
"\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ <<
"\n";
639 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 640 if (!rcp_node_list())
641 rcp_node_list() =
new rcp_node_list_t;
646 ActiveRCPNodesSetup::~ActiveRCPNodesSetup()
648 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 649 std::cerr <<
"\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ <<
"\n";
650 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 651 if( --count_ == 0 ) {
652 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 653 std::cerr <<
"\nPrint active nodes!\n";
654 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 655 std::cout << std::flush;
658 RCPNodeTracer::getRCPNodeStatistics();
659 if (rcpNodeStatistics.maxNumRCPNodes
660 && RCPNodeTracer::getPrintRCPNodeStatisticsOnExit())
662 RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
664 if (RCPNodeTracer::getPrintActiveRcpNodesOnExit()) {
665 RCPNodeTracer::printActiveRCPNodes(std::cerr);
667 delete rcp_node_list();
680 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
688 void RCPNodeHandle::unbindOne()
694 if (node_->strong_count()==1 && strength()==RCP_STRONG) {
706 local_activeRCPNodesSetup.foo();
707 RCPNodeTracer::removeRCPNode(node_);
711 if ( (node_->strong_count() + node_->weak_count()) == 1 ) {
722 node_->deincr_count(strength());
736 void Teuchos::throw_null_ptr_error(
const std::string &type_name )
740 type_name <<
" : You can not call operator->() or operator*()" 741 <<
" if getRawPtr()==0!" );
Null reference error exception class.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Modified boost::any class, which is a container for a templated value.
void has_ownership(bool has_ownership_in)
Node class to keep track of address and the reference count for a reference-counted utility class and...
virtual const std::string get_base_obj_type_name() const =0
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos, as well as a number of utility routines.
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
std::string typeName() const
Return the name of the type.
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
Reference-counted pointer node classes.
Thrown if a duplicate owning RCP is creatd the the same object.
#define TEUCHOS_TEST_FOR_EXCEPT(throw_exception_test)
This macro is designed to be a short version of TEUCHOS_TEST_FOR_EXCEPTION() that is easier to call...