43 #include "Teuchos_Assert.hpp"
44 #include "Teuchos_Exceptions.hpp"
48 #include "Teuchos_StandardCatchMacros.hpp"
59 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOSCORE_CXX11) && defined(HAVE_TEUCHOS_THREAD_SAFE)
61 #define USE_MUTEX_TO_PROTECT_NODE_TRACING
73 RCPNodeInfo() =
delete;
75 : info(info_in), nodePtr(nodePtr_in)
82 typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
85 typedef std::multimap<const void*, RCPNodeInfo> rcp_node_list_t;
104 rcp_node_list_t*& rcp_node_list()
106 static rcp_node_list_t *s_rcp_node_list = 0;
114 return s_rcp_node_list;
117 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
118 std::mutex *& rcp_node_list_mutex()
120 static std::mutex * s_rcp_node_list_mutex = 0;
123 return s_rcp_node_list_mutex;
127 bool& loc_isTracingActiveRCPNodes()
129 static bool s_loc_isTracingActiveRCPNodes =
130 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
136 return s_loc_isTracingActiveRCPNodes;
143 return s_loc_rcpNodeStatistics;
147 bool& loc_printRCPNodeStatisticsOnExit()
149 static bool s_loc_printRCPNodeStatisticsOnExit =
false;
150 return s_loc_printRCPNodeStatisticsOnExit;
154 bool& loc_printActiveRcpNodesOnExit()
156 static bool s_loc_printActiveRcpNodesOnExit =
true;
157 return s_loc_printActiveRcpNodesOnExit;
176 const void* base_obj_map_key_void_ptr = rcp_node->get_base_obj_map_key_void_ptr();
177 if (base_obj_map_key_void_ptr)
178 return base_obj_map_key_void_ptr;
186 std::ostringstream oss;
188 <<
"RCPNode {address="
191 <<
", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr()
194 <<
", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node)
197 <<
", insertionNumber="<< rcp_node->insertion_number()
216 const any &extra_data,
const std::string& name
221 if(extra_data_map_==NULL) {
222 extra_data_map_ =
new extra_data_map_t;
224 const std::string type_and_name( extra_data.
typeName() + std::string(
":") + name );
225 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
228 (itr != extra_data_map_->end() && force_unique), std::invalid_argument
229 ,
"Error, the type:name pair \'" << type_and_name
230 <<
"\' already exists and force_unique==true!" );
232 if (itr != extra_data_map_->end()) {
234 itr->second = extra_data_entry_t(extra_data,destroy_when);
238 (*extra_data_map_)[type_and_name] =
239 extra_data_entry_t(extra_data,destroy_when);
248 extra_data_map_==NULL, std::invalid_argument
249 ,
"Error, no extra data has been set yet!" );
254 const std::string type_and_name( type_name + std::string(
":") + name );
256 extra_data == NULL, std::invalid_argument
257 ,
"Error, the type:name pair \'" << type_and_name <<
"\' is not found!" );
265 const std::string& name )
267 if( extra_data_map_ == NULL )
return NULL;
268 const std::string type_and_name( type_name + std::string(
":") + name );
269 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
270 if(itr != extra_data_map_->end())
271 return &(*itr).second.extra_data;
276 void RCPNode::impl_pre_delete_extra_data()
279 extra_data_map_t::iterator itr = extra_data_map_->begin();
280 itr != extra_data_map_->end();
284 extra_data_map_t::value_type &entry = *itr;
285 if(entry.second.destroy_when == PRE_DESTROY)
286 entry.second.extra_data =
any();
301 return loc_isTracingActiveRCPNodes();
305 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
306 void RCPNodeTracer::setTracingActiveRCPNodes(
bool tracingActiveNodes)
308 loc_isTracingActiveRCPNodes() = tracingActiveNodes;
317 return static_cast<int>(rcp_node_list()->size());
324 return loc_rcpNodeStatistics();
332 <<
"\n*** RCPNode Tracing statistics:"
334 <<
"\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
335 <<
"\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
336 <<
"\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
342 bool printRCPNodeStatisticsOnExit)
344 loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
350 return loc_printRCPNodeStatisticsOnExit();
356 loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
362 return loc_printActiveRcpNodesOnExit();
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) {
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(),
384 [] (
const rcp_node_list_t::value_type &v1,
const rcp_node_list_t::value_type &v2)
387 return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
389 return v1.first < v2.first;
394 typedef rcp_node_vec_t::const_iterator itr_t;
396 for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
397 const rcp_node_list_t::value_type &entry = *itr;
401 << std::setw(3) << std::right << i << std::left
402 <<
": RCPNode (map_key_void_ptr=" << entry.first <<
")\n"
403 <<
" Information = " << entry.second.info <<
"\n"
404 <<
" RCPNode address = " << entry.second.nodePtr <<
"\n"
406 <<
" insertionNumber = " << entry.second.nodePtr->insertion_number()
423 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
425 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
426 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
429 static int insertionNumber = 0;
434 rcp_node->set_insertion_number(insertionNumber);
437 if (loc_isTracingActiveRCPNodes()) {
441 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
443 <<
"RCPNodeTracer::addNewRCPNode(...): Adding "
444 << convertRCPNodeToString(rcp_node) <<
" ...\n";
449 const void *
const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
452 typedef rcp_node_list_t::iterator itr_t;
453 typedef std::pair<itr_t, itr_t> itr_itr_t;
454 const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
455 const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
456 RCPNode *previous_rcp_node = 0;
457 bool previous_rcp_node_has_ownership =
false;
458 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
459 previous_rcp_node = itr->second.nodePtr;
461 previous_rcp_node_has_ownership =
true;
466 rcp_node_already_exists && rcp_node->
has_ownership() && previous_rcp_node_has_ownership,
468 "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
469 "RCPNode object to an existing managed object in another RCPNode:\n"
471 " New " << convertRCPNodeToString(rcp_node) <<
"\n"
473 " Existing " << convertRCPNodeToString(previous_rcp_node) <<
"\n"
475 " Number current nodes = " << rcp_node_list()->size() <<
"\n"
477 "This may indicate that the user might be trying to create a weak RCP to an existing\n"
478 "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n"
479 "or an equivalent function?\n"
490 (*rcp_node_list()).emplace_hint(
492 std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
501 ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
502 loc_rcpNodeStatistics().maxNumRCPNodes =
508 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
509 TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
511 "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
512 << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
513 " active RCP nodes being traced even though all nodes should be traced." \
514 " This should not be possible and can only be an internal programming error!")
529 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
531 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
532 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
536 typedef rcp_node_list_t::iterator itr_t;
537 typedef std::pair<itr_t, itr_t> itr_itr_t;
539 const itr_itr_t itr_itr =
540 rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
541 const bool rcp_node_exists = itr_itr.first != itr_itr.second;
543 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
547 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
556 if (rcp_node_exists) {
557 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
559 <<
"RCPNodeTracer::removeRCPNode(...): Removing "
560 << convertRCPNodeToString(rcp_node) <<
" ...\n";
562 bool foundRCPNode =
false;
563 for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
564 if (itr->second.nodePtr == rcp_node) {
565 rcp_node_list()->erase(itr);
566 ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
572 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
580 typedef rcp_node_list_t::iterator itr_t;
581 typedef std::pair<itr_t, itr_t> itr_itr_t;
585 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
587 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
588 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
590 const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
591 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
592 RCPNode* rcpNode = itr->second.nodePtr;
607 "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
608 "\n*** not been destroyed yet. A memory checking tool may complain that these"
609 "\n*** objects are not destroyed correctly."
611 "\n*** There can be many possible reasons that this might occur including:"
613 "\n*** a) The program called abort() or exit() before main() was finished."
614 "\n*** All of the objects that would have been freed through destructors"
615 "\n*** are not freed but some compilers (e.g. GCC) will still call the"
616 "\n*** destructors on static objects (which is what causes this message"
617 "\n*** to be printed)."
619 "\n*** b) The program is using raw new/delete to manage some objects and"
620 "\n*** delete was not called correctly and the objects not deleted hold"
621 "\n*** other objects through reference-counted pointers."
623 "\n*** c) This may be an indication that these objects may be involved in"
624 "\n*** a circular dependency of reference-counted managed objects."
633 "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
634 "the RCPNode object is first created to determine the context where the object first\n"
635 "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n"
636 "breakpoints in the code. For example, in GDB one can perform:\n"
638 "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
640 "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
641 "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
643 " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
644 " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
646 "3) Run the program in the debugger. In GDB, do:\n"
648 " (gdb) run [ENTER]\n"
650 "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
662 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
663 std::cerr <<
"\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ <<
"\n";
664 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
665 if (!rcp_node_list())
666 rcp_node_list() =
new rcp_node_list_t;
668 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
669 if (!rcp_node_list_mutex()) {
670 rcp_node_list_mutex() =
new std::mutex;
679 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
680 std::cerr <<
"\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ <<
"\n";
681 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
682 if( --count_ == 0 ) {
683 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
684 std::cerr <<
"\nPrint active nodes!\n";
685 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
686 std::cout << std::flush;
690 if (rcpNodeStatistics.maxNumRCPNodes
698 delete rcp_node_list();
701 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
702 delete rcp_node_list_mutex();
703 rcp_node_list_mutex() = 0;
716 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
723 void RCPNodeHandle::unbindOneStrong()
733 void RCPNodeHandle::unbindOneTotal()
747 void Teuchos::throw_null_ptr_error(
const std::string &type_name )
750 true, NullReferenceError,
751 type_name <<
" : You can not call operator->() or operator*()"
752 <<
" if getRawPtr()==0!" );
760 #define TEUCHOS_IMPLEMENT_ABORT(excpt) \
761 bool success = false; \
762 try { throw excpt; } \
763 TEUCHOS_STANDARD_CATCH_STATEMENTS(true,std::cerr,success); \
764 if(!success) std::cerr << "PROGRAM ABORTING\n"; \
765 GlobalMPISession::abort();
767 void Teuchos::abort_for_exception_in_destructor(
const std::exception &exception) {
768 TEUCHOS_IMPLEMENT_ABORT(exception);
770 void Teuchos::abort_for_exception_in_destructor(
const int &code) {
771 TEUCHOS_IMPLEMENT_ABORT(code);
773 void Teuchos::abort_for_exception_in_destructor() {
774 TEUCHOS_IMPLEMENT_ABORT(std::logic_error(
775 "Caught unknown exception from destructor of RCPNode. Aborting."););
777 #endif // TEUCHOS_DEBUG