11#include "Teuchos_Assert.hpp"
12#include "Teuchos_Exceptions.hpp"
16#include "Teuchos_StandardCatchMacros.hpp"
27#if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOSCORE_CXX11) && defined(HAVE_TEUCHOS_THREAD_SAFE)
29#define USE_MUTEX_TO_PROTECT_NODE_TRACING
41 RCPNodeInfo() =
delete;
42 RCPNodeInfo(
const std::string &info_in, Teuchos::RCPNode* nodePtr_in)
43 : info(info_in), nodePtr(nodePtr_in)
46 Teuchos::RCPNode* nodePtr;
50typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
53typedef std::multimap<const void*, RCPNodeInfo> rcp_node_list_t;
72rcp_node_list_t*& rcp_node_list()
74 static rcp_node_list_t *s_rcp_node_list = 0;
82 return s_rcp_node_list;
85#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
86std::mutex *& rcp_node_list_mutex()
88 static std::mutex * s_rcp_node_list_mutex = 0;
91 return s_rcp_node_list_mutex;
95bool& loc_isTracingActiveRCPNodes()
97 static bool s_loc_isTracingActiveRCPNodes =
98#if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
104 return s_loc_isTracingActiveRCPNodes;
111 return s_loc_rcpNodeStatistics;
115bool& loc_printRCPNodeStatisticsOnExit()
117 static bool s_loc_printRCPNodeStatisticsOnExit =
false;
118 return s_loc_printRCPNodeStatisticsOnExit;
122bool& loc_printActiveRcpNodesOnExit()
124 static bool s_loc_printActiveRcpNodesOnExit =
true;
125 return s_loc_printActiveRcpNodesOnExit;
144 const void* base_obj_map_key_void_ptr = rcp_node->get_base_obj_map_key_void_ptr();
145 if (base_obj_map_key_void_ptr)
146 return base_obj_map_key_void_ptr;
154 std::ostringstream oss;
156 <<
"RCPNode {address="
159 <<
", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr()
162 <<
", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node)
165 <<
", insertionNumber="<< rcp_node->insertion_number()
184 const any &extra_data,
const std::string& name
190 if(extra_data_map_==NULL) {
191 extra_data_map_ =
new extra_data_map_t;
193 const std::string type_and_name( extra_data.
typeName() + std::string(
":") + name );
194 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
197 (itr != extra_data_map_->end() && force_unique), std::invalid_argument
198 ,
"Error, the type:name pair \'" << type_and_name
199 <<
"\' already exists and force_unique==true!" );
201 if (itr != extra_data_map_->end()) {
203 itr->second = extra_data_entry_t(extra_data,destroy_when);
207 (*extra_data_map_)[type_and_name] =
208 extra_data_entry_t(extra_data,destroy_when);
217 extra_data_map_==NULL, std::invalid_argument
218 ,
"Error, no extra data has been set yet!" );
223 const std::string type_and_name( type_name + std::string(
":") + name );
225 extra_data == NULL, std::invalid_argument
226 ,
"Error, the type:name pair \'" << type_and_name <<
"\' is not found!" );
234 const std::string& name )
236 if( extra_data_map_ == NULL )
return NULL;
237 const std::string type_and_name( type_name + std::string(
":") + name );
238 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name);
239 if(itr != extra_data_map_->end())
240 return &(*itr).second.extra_data;
245void throw_invalid_obj_exception_free_fun(
const std::string& rcp_type_name,
248 const void* rcp_obj_ptr,
251 const void *deleted_ptr_,
253 const std::string& type_name)
256 const void* deleted_ptr =
265 "Error, an attempt has been made to dereference the underlying object\n"
266 "from a weak smart pointer object where the underling object has already\n"
267 "been deleted since the strong count has already gone to zero.\n"
269 "Context information:\n"
271 " RCP type: " << rcp_type_name <<
"\n"
272 " RCP address: " << rcp_ptr <<
"\n"
273 " RCPNode type: " << type_name <<
"\n"
274 " RCPNode address: " << rcp_node_ptr <<
"\n"
275 TEUCHOS_RCP_INSERION_NUMBER_STR()
276 " RCP ptr address: " << rcp_obj_ptr <<
"\n"
277 " Concrete ptr address: " << deleted_ptr <<
"\n"
291void RCPNode::impl_pre_delete_extra_data()
294 extra_data_map_t::iterator itr = extra_data_map_->begin();
295 itr != extra_data_map_->end();
299 extra_data_map_t::value_type &entry = *itr;
300 if(entry.second.destroy_when == PRE_DESTROY)
301 entry.second.extra_data = any();
316 return loc_isTracingActiveRCPNodes();
320#if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
321void RCPNodeTracer::setTracingActiveRCPNodes(
bool tracingActiveNodes)
323 loc_isTracingActiveRCPNodes() = tracingActiveNodes;
332 return static_cast<int>(rcp_node_list()->size());
339 return loc_rcpNodeStatistics();
347 <<
"\n*** RCPNode Tracing statistics:"
349 <<
"\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
350 <<
"\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
351 <<
"\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
357 bool printRCPNodeStatisticsOnExit)
359 loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
365 return loc_printRCPNodeStatisticsOnExit();
371 loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
377 return loc_printActiveRcpNodesOnExit();
383#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
385 <<
"\nCalled printActiveRCPNodes() :"
386 <<
" rcp_node_list.size() = " << rcp_node_list().size() <<
"\n";
388 if (loc_isTracingActiveRCPNodes()) {
390 if (rcp_node_list()->size() > 0) {
396 typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
397 rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
398 std::sort(rcp_node_vec.begin(), rcp_node_vec.end(),
399 [] (
const rcp_node_list_t::value_type &v1,
const rcp_node_list_t::value_type &v2)
402 return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
404 return v1.first < v2.first;
409 typedef rcp_node_vec_t::const_iterator itr_t;
411 for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
412 const rcp_node_list_t::value_type &entry = *itr;
416 << std::setw(3) << std::right << i << std::left
417 <<
": RCPNode (map_key_void_ptr=" << entry.first <<
")\n"
418 <<
" Information = " << entry.second.info <<
"\n"
419 <<
" RCPNode address = " << entry.second.nodePtr <<
"\n"
421 <<
" insertionNumber = " << entry.second.nodePtr->insertion_number()
438#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
440 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
444 static int insertionNumber = 0;
449 rcp_node->set_insertion_number(insertionNumber);
452 if (loc_isTracingActiveRCPNodes()) {
456#ifdef RCP_NODE_DEBUG_TRACE_PRINT
458 <<
"RCPNodeTracer::addNewRCPNode(...): Adding "
459 << convertRCPNodeToString(rcp_node) <<
" ...\n";
464 const void *
const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
467 typedef rcp_node_list_t::iterator itr_t;
468 typedef std::pair<itr_t, itr_t> itr_itr_t;
469 const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
470 const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
471 RCPNode *previous_rcp_node = 0;
472 bool previous_rcp_node_has_ownership =
false;
473 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
474 previous_rcp_node = itr->second.nodePtr;
476 previous_rcp_node_has_ownership =
true;
481 rcp_node_already_exists && rcp_node->
has_ownership() && previous_rcp_node_has_ownership,
483 "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
484 "RCPNode object to an existing managed object in another RCPNode:\n"
486 " New " << convertRCPNodeToString(rcp_node) <<
"\n"
488 " Existing " << convertRCPNodeToString(previous_rcp_node) <<
"\n"
490 " Number current nodes = " << rcp_node_list()->size() <<
"\n"
492 "This may indicate that the user might be trying to create a weak RCP to an existing\n"
493 "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n"
494 "or an equivalent function?\n"
505 (*rcp_node_list()).emplace_hint(
507 std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
516 ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
517 loc_rcpNodeStatistics().maxNumRCPNodes =
523#define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
524 TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
526 "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
527 << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
528 " active RCP nodes being traced even though all nodes should be traced." \
529 " This should not be possible and can only be an internal programming error!")
544#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
546 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
551 typedef rcp_node_list_t::iterator itr_t;
552 typedef std::pair<itr_t, itr_t> itr_itr_t;
554 const itr_itr_t itr_itr =
555 rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
556 const bool rcp_node_exists = itr_itr.first != itr_itr.second;
558#ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
562 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
571 if (rcp_node_exists) {
572#ifdef RCP_NODE_DEBUG_TRACE_PRINT
574 <<
"RCPNodeTracer::removeRCPNode(...): Removing "
575 << convertRCPNodeToString(rcp_node) <<
" ...\n";
577 bool foundRCPNode =
false;
578 for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
579 if (itr->second.nodePtr == rcp_node) {
580 rcp_node_list()->erase(itr);
581 ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
587 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
595 typedef rcp_node_list_t::iterator itr_t;
596 typedef std::pair<itr_t, itr_t> itr_itr_t;
600#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
602 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
605 const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
606 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
607 RCPNode* rcpNode = itr->second.nodePtr;
622 "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
623 "\n*** not been destroyed yet. A memory checking tool may complain that these"
624 "\n*** objects are not destroyed correctly."
626 "\n*** There can be many possible reasons that this might occur including:"
628 "\n*** a) The program called abort() or exit() before main() was finished."
629 "\n*** All of the objects that would have been freed through destructors"
630 "\n*** are not freed but some compilers (e.g. GCC) will still call the"
631 "\n*** destructors on static objects (which is what causes this message"
632 "\n*** to be printed)."
634 "\n*** b) The program is using raw new/delete to manage some objects and"
635 "\n*** delete was not called correctly and the objects not deleted hold"
636 "\n*** other objects through reference-counted pointers."
638 "\n*** c) This may be an indication that these objects may be involved in"
639 "\n*** a circular dependency of reference-counted managed objects."
648 "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
649 "the RCPNode object is first created to determine the context where the object first\n"
650 "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n"
651 "breakpoints in the code. For example, in GDB one can perform:\n"
653 "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
655 "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
656 "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
658 " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
659 " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
661 "3) Run the program in the debugger. In GDB, do:\n"
663 " (gdb) run [ENTER]\n"
665 "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
677#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
678 std::cerr <<
"\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ <<
"\n";
680 if (!rcp_node_list())
681 rcp_node_list() =
new rcp_node_list_t;
683#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
684 if (!rcp_node_list_mutex()) {
685 rcp_node_list_mutex() =
new std::mutex;
694#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
695 std::cerr <<
"\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ <<
"\n";
697 if( --count_ == 0 ) {
698#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
699 std::cerr <<
"\nPrint active nodes!\n";
701 std::cout << std::flush;
705 if (rcpNodeStatistics.maxNumRCPNodes
713 delete rcp_node_list();
716#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
717 delete rcp_node_list_mutex();
718 rcp_node_list_mutex() = 0;
731int Teuchos::ActiveRCPNodesSetup::count_ = 0;
738void RCPNodeHandle::unbindOneStrong()
748void RCPNodeHandle::unbindOneTotal()
765 true, NullReferenceError,
766 type_name <<
" : You can not call operator->() or operator*()"
767 <<
" if getRawPtr()==0!" );
775#define TEUCHOS_IMPLEMENT_ABORT(excpt) \
776 bool success = false; \
777 try { throw excpt; } \
778 TEUCHOS_STANDARD_CATCH_STATEMENTS(true,std::cerr,success); \
779 if(!success) std::cerr << "PROGRAM ABORTING\n"; \
780 GlobalMPISession::abort();
782void Teuchos::abort_for_exception_in_destructor(
const std::exception &exception) {
783 TEUCHOS_IMPLEMENT_ABORT(exception);
785void Teuchos::abort_for_exception_in_destructor(
const int &code) {
786 TEUCHOS_IMPLEMENT_ABORT(code);
788void Teuchos::abort_for_exception_in_destructor() {
789 TEUCHOS_IMPLEMENT_ABORT(std::logic_error(
790 "Caught unknown exception from destructor of RCPNode. Aborting."););
Reference-counted pointer node classes.
Dangling reference error exception class.
Thrown if a duplicate owning RCP is creatd the the same object.
Node class to keep track of address and the reference count for a reference-counted utility class and...
any & get_extra_data(const std::string &type_name, const std::string &name)
virtual const std::string get_base_obj_type_name() const =0
virtual void delete_obj()=0
void set_extra_data(const any &extra_data, const std::string &name, EPrePostDestruction destroy_when, bool force_unique)
any * get_optional_extra_data(const std::string &type_name, const std::string &name)
void has_ownership(bool has_ownership_in)
TEUCHOSCORE_LIB_DLL_EXPORT void throw_null_ptr_error(const std::string &type_name)
Throw that a pointer passed into an RCP object is null.
static bool getPrintRCPNodeStatisticsOnExit()
Return if RCPNode usage statistics will be printed when the program ends or not.
static std::string getCommonDebugNotesString()
Common error message string on how to debug RCPNode problems.
static void printRCPNodeStatistics(const RCPNodeStatistics &rcpNodeStatistics, std::ostream &out)
Print the RCPNode allocation statistics.
static RCPNodeStatistics getRCPNodeStatistics()
Return the statistics on RCPNode allocations.
static void setPrintRCPNodeStatisticsOnExit(bool printRCPNodeStatisticsOnExit)
Set if RCPNode usage statistics will be printed when the program ends or not.
static int numActiveRCPNodes()
Print the number of active RCPNode objects currently being tracked.
static RCPNode * getExistingRCPNodeGivenLookupKey(const void *lookupKey)
Return a raw pointer to an existing owning RCPNode given its lookup key.
static void setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
Set if printActiveRCPNodes() is called on exit from the program.
static std::string getActiveRCPNodeHeaderString()
Header string used in printActiveRCPNodes().
static bool isTracingActiveRCPNodes()
Return if we are tracing active nodes or not.
static void removeRCPNode(RCPNode *rcp_node)
Remove an RCPNode from global list.
static void printActiveRCPNodes(std::ostream &out)
Print the list of currently active RCP nodes.
static bool getPrintActiveRcpNodesOnExit()
Return if printActiveRCPNodes() is called on exit from the program.
static void addNewRCPNode(RCPNode *rcp_node, const std::string &info)
Add new RCPNode to the global list.
Modified boost::any class, which is a container for a templated value.
std::string typeName() const
Return the name of the type.
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
#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...
#define TEUCHOS_TEST_FOR_EXCEPT_MSG(throw_exception_test, msg)
This macro is designed to be a short version of TEUCHOS_TEST_FOR_EXCEPTION() that is easier to call.
#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.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...