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
222 if(extra_data_map_==NULL) {
225 const std::string type_and_name( extra_data.
typeName() + std::string(
":") + name );
226 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
229 (itr != extra_data_map_->end() && force_unique), std::invalid_argument
230 ,
"Error, the type:name pair \'" << type_and_name
231 <<
"\' already exists and force_unique==true!" );
233 if (itr != extra_data_map_->end()) {
235 itr->second = extra_data_entry_t(extra_data,destroy_when);
239 (*extra_data_map_)[type_and_name] =
240 extra_data_entry_t(extra_data,destroy_when);
249 extra_data_map_==NULL, std::invalid_argument
250 ,
"Error, no extra data has been set yet!" );
255 const std::string type_and_name( type_name + std::string(
":") + name );
257 extra_data == NULL, std::invalid_argument
258 ,
"Error, the type:name pair \'" << type_and_name <<
"\' is not found!" );
266 const std::string& name )
268 if( extra_data_map_ == NULL )
return NULL;
269 const std::string type_and_name( type_name + std::string(
":") + name );
270 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
271 if(itr != extra_data_map_->end())
272 return &(*itr).second.extra_data;
277 void RCPNode::impl_pre_delete_extra_data()
280 extra_data_map_t::iterator itr = extra_data_map_->begin();
281 itr != extra_data_map_->end();
285 extra_data_map_t::value_type &entry = *itr;
286 if(entry.second.destroy_when == PRE_DESTROY)
287 entry.second.extra_data =
any();
302 return loc_isTracingActiveRCPNodes();
306 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
307 void RCPNodeTracer::setTracingActiveRCPNodes(
bool tracingActiveNodes)
309 loc_isTracingActiveRCPNodes() = tracingActiveNodes;
318 return static_cast<int>(rcp_node_list()->size());
325 return loc_rcpNodeStatistics();
333 <<
"\n*** RCPNode Tracing statistics:"
335 <<
"\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
336 <<
"\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
337 <<
"\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
343 bool printRCPNodeStatisticsOnExit)
345 loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
351 return loc_printRCPNodeStatisticsOnExit();
357 loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
363 return loc_printActiveRcpNodesOnExit();
369 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
371 <<
"\nCalled printActiveRCPNodes() :"
372 <<
" rcp_node_list.size() = " << rcp_node_list().size() <<
"\n";
373 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
374 if (loc_isTracingActiveRCPNodes()) {
376 if (rcp_node_list()->size() > 0) {
382 typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
383 rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
384 std::sort(rcp_node_vec.begin(), rcp_node_vec.end(),
385 [] (
const rcp_node_list_t::value_type &v1,
const rcp_node_list_t::value_type &v2)
388 return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
390 return v1.first < v2.first;
395 typedef rcp_node_vec_t::const_iterator itr_t;
397 for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
398 const rcp_node_list_t::value_type &entry = *itr;
402 << std::setw(3) << std::right << i << std::left
403 <<
": RCPNode (map_key_void_ptr=" << entry.first <<
")\n"
404 <<
" Information = " << entry.second.info <<
"\n"
405 <<
" RCPNode address = " << entry.second.nodePtr <<
"\n"
407 <<
" insertionNumber = " << entry.second.nodePtr->insertion_number()
424 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
426 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
427 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
430 static int insertionNumber = 0;
435 rcp_node->set_insertion_number(insertionNumber);
438 if (loc_isTracingActiveRCPNodes()) {
442 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
444 <<
"RCPNodeTracer::addNewRCPNode(...): Adding "
445 << convertRCPNodeToString(rcp_node) <<
" ...\n";
450 const void *
const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
453 typedef rcp_node_list_t::iterator itr_t;
454 typedef std::pair<itr_t, itr_t> itr_itr_t;
455 const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
456 const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
457 RCPNode *previous_rcp_node = 0;
458 bool previous_rcp_node_has_ownership =
false;
459 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
460 previous_rcp_node = itr->second.nodePtr;
462 previous_rcp_node_has_ownership =
true;
467 rcp_node_already_exists && rcp_node->
has_ownership() && previous_rcp_node_has_ownership,
469 "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
470 "RCPNode object to an existing managed object in another RCPNode:\n"
472 " New " << convertRCPNodeToString(rcp_node) <<
"\n"
474 " Existing " << convertRCPNodeToString(previous_rcp_node) <<
"\n"
476 " Number current nodes = " << rcp_node_list()->size() <<
"\n"
478 "This may indicate that the user might be trying to create a weak RCP to an existing\n"
479 "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n"
480 "or an equivalent function?\n"
491 (*rcp_node_list()).emplace_hint(
493 std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
502 ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
503 loc_rcpNodeStatistics().maxNumRCPNodes =
509 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
510 TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
512 "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
513 << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
514 " active RCP nodes being traced even though all nodes should be traced." \
515 " This should not be possible and can only be an internal programming error!")
530 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
532 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
533 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
537 typedef rcp_node_list_t::iterator itr_t;
538 typedef std::pair<itr_t, itr_t> itr_itr_t;
540 const itr_itr_t itr_itr =
541 rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
542 const bool rcp_node_exists = itr_itr.first != itr_itr.second;
544 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
548 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
557 if (rcp_node_exists) {
558 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
560 <<
"RCPNodeTracer::removeRCPNode(...): Removing "
561 << convertRCPNodeToString(rcp_node) <<
" ...\n";
563 bool foundRCPNode =
false;
564 for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
565 if (itr->second.nodePtr == rcp_node) {
566 rcp_node_list()->erase(itr);
567 ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
573 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
581 typedef rcp_node_list_t::iterator itr_t;
582 typedef std::pair<itr_t, itr_t> itr_itr_t;
586 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
588 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
589 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
591 const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
592 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
593 RCPNode* rcpNode = itr->second.nodePtr;
608 "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
609 "\n*** not been destroyed yet. A memory checking tool may complain that these"
610 "\n*** objects are not destroyed correctly."
612 "\n*** There can be many possible reasons that this might occur including:"
614 "\n*** a) The program called abort() or exit() before main() was finished."
615 "\n*** All of the objects that would have been freed through destructors"
616 "\n*** are not freed but some compilers (e.g. GCC) will still call the"
617 "\n*** destructors on static objects (which is what causes this message"
618 "\n*** to be printed)."
620 "\n*** b) The program is using raw new/delete to manage some objects and"
621 "\n*** delete was not called correctly and the objects not deleted hold"
622 "\n*** other objects through reference-counted pointers."
624 "\n*** c) This may be an indication that these objects may be involved in"
625 "\n*** a circular dependency of reference-counted managed objects."
634 "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
635 "the RCPNode object is first created to determine the context where the object first\n"
636 "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n"
637 "breakpoints in the code. For example, in GDB one can perform:\n"
639 "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
641 "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
642 "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
644 " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
645 " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
647 "3) Run the program in the debugger. In GDB, do:\n"
649 " (gdb) run [ENTER]\n"
651 "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
663 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
664 std::cerr <<
"\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ <<
"\n";
665 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
666 if (!rcp_node_list())
667 rcp_node_list() =
new rcp_node_list_t;
669 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
670 if (!rcp_node_list_mutex()) {
671 rcp_node_list_mutex() =
new std::mutex;
680 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
681 std::cerr <<
"\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ <<
"\n";
682 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
683 if( --count_ == 0 ) {
684 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
685 std::cerr <<
"\nPrint active nodes!\n";
686 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
687 std::cout << std::flush;
691 if (rcpNodeStatistics.maxNumRCPNodes
699 delete rcp_node_list();
702 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
703 delete rcp_node_list_mutex();
704 rcp_node_list_mutex() = 0;
717 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
724 void RCPNodeHandle::unbindOneStrong()
734 void RCPNodeHandle::unbindOneTotal()
748 void Teuchos::throw_null_ptr_error(
const std::string &type_name )
751 true, NullReferenceError,
752 type_name <<
" : You can not call operator->() or operator*()"
753 <<
" if getRawPtr()==0!" );
761 #define TEUCHOS_IMPLEMENT_ABORT(excpt) \
762 bool success = false; \
763 try { throw excpt; } \
764 TEUCHOS_STANDARD_CATCH_STATEMENTS(true,std::cerr,success); \
765 if(!success) std::cerr << "PROGRAM ABORTING\n"; \
766 GlobalMPISession::abort();
768 void Teuchos::abort_for_exception_in_destructor(
const std::exception &exception) {
769 TEUCHOS_IMPLEMENT_ABORT(exception);
771 void Teuchos::abort_for_exception_in_destructor(
const int &code) {
772 TEUCHOS_IMPLEMENT_ABORT(code);
774 void Teuchos::abort_for_exception_in_destructor() {
775 TEUCHOS_IMPLEMENT_ABORT(std::logic_error(
776 "Caught unknown exception from destructor of RCPNode. Aborting."););
778 #endif // TEUCHOS_DEBUG
static void printRCPNodeStatistics(const RCPNodeStatistics &rcpNodeStatistics, std::ostream &out)
Print the RCPNode allocation statistics.
static bool isTracingActiveRCPNodes()
Return if we are tracing active nodes or not.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
static void setPrintRCPNodeStatisticsOnExit(bool printRCPNodeStatisticsOnExit)
Set if RCPNode usage statistics will be printed when the program ends or not.
void set_extra_data(const any &extra_data, const std::string &name, EPrePostDestruction destroy_when, bool force_unique)
static RCPNodeStatistics getRCPNodeStatistics()
Return the statistics on RCPNode allocations.
Modified boost::any class, which is a container for a templated value.
any & get_extra_data(const std::string &type_name, const std::string &name)
void has_ownership(bool has_ownership_in)
static std::string getCommonDebugNotesString()
Common error message string on how to debug RCPNode problems.
static bool getPrintRCPNodeStatisticsOnExit()
Return if RCPNode usage statistics will be printed when the program ends or not.
Node class to keep track of address and the reference count for a reference-counted utility class and...
static RCPNode * getExistingRCPNodeGivenLookupKey(const void *lookupKey)
Return a raw pointer to an existing owning RCPNode given its lookup key.
static bool getPrintActiveRcpNodesOnExit()
Return if printActiveRCPNodes() is called on exit from the program.
virtual const std::string get_base_obj_type_name() const =0
virtual void delete_obj()=0
#define TEUCHOS_TEST_FOR_TERMINATION(terminate_test, msg)
This macro is to be used instead of TEUCHOS_TEST_FOR_EXCEPTION() to report an error in situations whe...
any * get_optional_extra_data(const std::string &type_name, const std::string &name)
static void removeRCPNode(RCPNode *rcp_node)
Remove an RCPNode from global list.
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
std::string typeName() const
Return the name of the type.
This class creates a basic std::map object for platforms where the std::map is deficient, otherwise the std::map is injected into the Teuchos namespace.
#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.
static std::string getActiveRCPNodeHeaderString()
Header string used in printActiveRCPNodes().
static int numActiveRCPNodes()
Print the number of active RCPNode objects currently being tracked.
static void addNewRCPNode(RCPNode *rcp_node, const std::string &info)
Add new RCPNode to the global list.
#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...
static void printActiveRCPNodes(std::ostream &out)
Print the list of currently active RCP nodes.
static void setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
Set if printActiveRCPNodes() is called on exit from the program.