Teuchos - Trilinos Tools Package  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Teuchos_RCPNode.cpp
1 // @HEADER
2 // *****************************************************************************
3 // Teuchos: Common Tools Package
4 //
5 // Copyright 2004 NTESS and the Teuchos contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #include "Teuchos_RCPNode.hpp"
11 #include "Teuchos_Assert.hpp"
12 #include "Teuchos_Exceptions.hpp"
13 #include <vector>
14 
15 #ifdef TEUCHOS_DEBUG
16 #include "Teuchos_StandardCatchMacros.hpp"
17 #endif
18 
19 // Defined this to see tracing of RCPNodes created and destroyed
20 //#define RCP_NODE_DEBUG_TRACE_PRINT
21 
22 
23 //
24 // Internal implementatation stuff
25 //
26 
27 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOSCORE_CXX11) && defined(HAVE_TEUCHOS_THREAD_SAFE)
28 #include <mutex>
29 #define USE_MUTEX_TO_PROTECT_NODE_TRACING
30 #endif
31 
32 namespace {
33 
34 
35 //
36 // Local implementation types
37 //
38 
39 
40 struct RCPNodeInfo {
41  RCPNodeInfo() = delete;
42  RCPNodeInfo(const std::string &info_in, Teuchos::RCPNode* nodePtr_in)
43  : info(info_in), nodePtr(nodePtr_in)
44  {}
45  std::string info;
46  Teuchos::RCPNode* nodePtr;
47 };
48 
49 
50 typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
51 
52 
53 typedef std::multimap<const void*, RCPNodeInfo> rcp_node_list_t;
54 
55 //
56 // Local static functions returning references to local static objects to
57 // ensure objects are initilaized.
58 //
59 // Technically speaking, the static functions on RCPNodeTracer that use this
60 // data might be called from other translation units in pre-main code before
61 // this translation unit gets initialized. By using functions returning
62 // references to local static variable trick, we ensure that these objects are
63 // always initialized before they are used, no matter what.
64 //
65 // These could have been static functions on RCPNodeTracer but the advantage
66 // of defining these functions this way is that you can add and remove
67 // functions without affecting the *.hpp file and therefore avoid
68 // recompilation (and even relinking with shared libraries).
69 //
70 
71 
72 rcp_node_list_t*& rcp_node_list()
73 {
74  static rcp_node_list_t *s_rcp_node_list = 0;
75  // Here we must let the ActiveRCPNodesSetup constructor and destructor handle
76  // the creation and destruction of this map object. This will ensure that
77  // this map object will be valid when any global/static RCP objects are
78  // destroyed! Note that this object will get created and destroyed
79  // reguardless if whether we are tracing RCPNodes or not. This just makes our
80  // life simpler. NOTE: This list will always get allocated no mater if
81  // TEUCHOS_DEBUG is defined or node traceing is enabled or not.
82  return s_rcp_node_list;
83 }
84 
85 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
86 std::mutex *& rcp_node_list_mutex()
87 {
88  static std::mutex * s_rcp_node_list_mutex = 0;
89  // This construct exists for the same reason as above (rcp_node_list)
90  // We must keep this mutex in place until all static RCP objects have deleted.
91  return s_rcp_node_list_mutex;
92 }
93 #endif
94 
95 bool& loc_isTracingActiveRCPNodes()
96 {
97  static bool s_loc_isTracingActiveRCPNodes =
98 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
99  true
100 #else
101  false
102 #endif
103  ;
104  return s_loc_isTracingActiveRCPNodes;
105 }
106 
107 
108 Teuchos::RCPNodeTracer::RCPNodeStatistics& loc_rcpNodeStatistics()
109 {
110  static Teuchos::RCPNodeTracer::RCPNodeStatistics s_loc_rcpNodeStatistics;
111  return s_loc_rcpNodeStatistics;
112 }
113 
114 
115 bool& loc_printRCPNodeStatisticsOnExit()
116 {
117  static bool s_loc_printRCPNodeStatisticsOnExit = false;
118  return s_loc_printRCPNodeStatisticsOnExit;
119 }
120 
121 
122 bool& loc_printActiveRcpNodesOnExit()
123 {
124  static bool s_loc_printActiveRcpNodesOnExit = true;
125  return s_loc_printActiveRcpNodesOnExit;
126 }
127 
128 
129 //
130 // Other helper functions
131 //
132 
133 // This function returns the const void* value that is used as the key to look
134 // up an RCPNode object that has been stored. If the RCPNode is holding a
135 // non-null reference, then we use that object address as the key. That way,
136 // we can detect if a user trys to create a new owning RCPNode to the same
137 // object. If the RCPNode has an null internal object pointer, then we will
138 // use the RCPNode's address itself. In this case, we want to check and see
139 // that all RCPNodes that get created get destroyed correctly.
140 const void* get_map_key_void_ptr(const Teuchos::RCPNode* rcp_node)
141 {
142  TEUCHOS_ASSERT(rcp_node);
143 #ifdef TEUCHOS_DEBUG
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;
147 #endif
148  return rcp_node;
149 }
150 
151 
152 std::string convertRCPNodeToString(const Teuchos::RCPNode* rcp_node)
153 {
154  std::ostringstream oss;
155  oss
156  << "RCPNode {address="
157  << rcp_node
158 #ifdef TEUCHOS_DEBUG
159  << ", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr()
160 #endif
161  << ", base_obj_type_name=" << rcp_node->get_base_obj_type_name()
162  << ", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node)
163  << ", has_ownership=" << rcp_node->has_ownership()
164 #ifdef TEUCHOS_DEBUG
165  << ", insertionNumber="<< rcp_node->insertion_number()
166 #endif
167  << "}";
168  return oss.str();
169 }
170 
171 
172 } // namespace
173 
174 
175 namespace Teuchos {
176 
177 
178 //
179 // RCPNode
180 //
181 
182 
184  const any &extra_data, const std::string& name
185  ,EPrePostDestruction destroy_when
186  ,bool force_unique
187  )
188 {
189  (void)force_unique;
190  if(extra_data_map_==NULL) {
191  extra_data_map_ = new extra_data_map_t;
192  }
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);
195 #ifdef TEUCHOS_DEBUG
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!" );
200 #endif
201  if (itr != extra_data_map_->end()) {
202  // Change existing extra data
203  itr->second = extra_data_entry_t(extra_data,destroy_when);
204  }
205  else {
206  // Insert new extra data
207  (*extra_data_map_)[type_and_name] =
208  extra_data_entry_t(extra_data,destroy_when);
209  }
210 }
211 
212 
213 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name )
214 {
215 #ifdef TEUCHOS_DEBUG
217  extra_data_map_==NULL, std::invalid_argument
218  ,"Error, no extra data has been set yet!" );
219 #endif
220  any *extra_data = get_optional_extra_data(type_name,name);
221 #ifdef TEUCHOS_DEBUG
222  if (!extra_data) {
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!" );
227  }
228 #endif
229  return *extra_data;
230 }
231 
232 
233 any* RCPNode::get_optional_extra_data( const std::string& type_name,
234  const std::string& name )
235 {
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;
241  return NULL;
242 }
243 
244 
245 void RCPNode::impl_pre_delete_extra_data()
246 {
247  for(
248  extra_data_map_t::iterator itr = extra_data_map_->begin();
249  itr != extra_data_map_->end();
250  ++itr
251  )
252  {
253  extra_data_map_t::value_type &entry = *itr;
254  if(entry.second.destroy_when == PRE_DESTROY)
255  entry.second.extra_data = any();
256  }
257 }
258 
259 
260 //
261 // RCPNodeTracer
262 //
263 
264 
265 // General user functions
266 
267 
269 {
270  return loc_isTracingActiveRCPNodes();
271 }
272 
273 
274 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
275 void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
276 {
277  loc_isTracingActiveRCPNodes() = tracingActiveNodes;
278 }
279 #endif
280 
281 
283 {
284  // This list always exists, no matter debug or not so just access it.
285  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
286  return static_cast<int>(rcp_node_list()->size());
287 }
288 
289 
292 {
293  return loc_rcpNodeStatistics();
294 }
295 
297  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
298 {
299  out
300  << "\n***"
301  << "\n*** RCPNode Tracing statistics:"
302  << "\n**\n"
303  << "\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
304  << "\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
305  << "\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
306  << "\n";
307 }
308 
309 
311  bool printRCPNodeStatisticsOnExit)
312 {
313  loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
314 }
315 
316 
318 {
319  return loc_printRCPNodeStatisticsOnExit();
320 }
321 
322 
323 void RCPNodeTracer::setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
324 {
325  loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
326 }
327 
328 
330 {
331  return loc_printActiveRcpNodesOnExit();
332 }
333 
334 
335 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
336 {
337 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
338  out
339  << "\nCalled printActiveRCPNodes() :"
340  << " rcp_node_list.size() = " << rcp_node_list().size() << "\n";
341 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
342  if (loc_isTracingActiveRCPNodes()) {
343  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
344  if (rcp_node_list()->size() > 0) {
346  // Create a sorted-by-insertionNumber list
347  // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
348  // because this called at the very end and uses RCPNode itself in a
349  // debug-mode build.
350  typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
351  rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end());
352  std::sort(rcp_node_vec.begin(), rcp_node_vec.end(),
353  [] (const rcp_node_list_t::value_type &v1, const rcp_node_list_t::value_type &v2)
354  {
355 #ifdef TEUCHOS_DEBUG
356  return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
357 #else
358  return v1.first < v2.first;
359 #endif
360  }
361  );
362  // Print the RCPNode objects sorted by insertion number
363  typedef rcp_node_vec_t::const_iterator itr_t;
364  int i = 0;
365  for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) {
366  const rcp_node_list_t::value_type &entry = *itr;
367  TEUCHOS_ASSERT(entry.second.nodePtr);
368  out
369  << "\n"
370  << std::setw(3) << std::right << i << std::left
371  << ": RCPNode (map_key_void_ptr=" << entry.first << ")\n"
372  << " Information = " << entry.second.info << "\n"
373  << " RCPNode address = " << entry.second.nodePtr << "\n"
374 #ifdef TEUCHOS_DEBUG
375  << " insertionNumber = " << entry.second.nodePtr->insertion_number()
376 #endif
377  ;
378  ++i;
379  }
380  out << "\n\n"
382  }
383  }
384 }
385 
386 
387 // Internal implementation functions
388 
389 
390 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
391 {
392 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
393  // lock_guard will unlock in the event of an exception
394  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
395 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
396 
397  // Used to allow unique identification of rcp_node to allow setting breakpoints
398  static int insertionNumber = 0;
399 
400  // Set the insertion number right away in case an exception gets thrown so
401  // that you can set a break point to debug this.
402 #ifdef TEUCHOS_DEBUG
403  rcp_node->set_insertion_number(insertionNumber);
404 #endif
405 
406  if (loc_isTracingActiveRCPNodes()) {
407 
408  // Print the node we are adding if configured to do so. We have to send
409  // to std::cerr to make sure that this gets printed.
410 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
411  std::cerr
412  << "RCPNodeTracer::addNewRCPNode(...): Adding "
413  << convertRCPNodeToString(rcp_node) << " ...\n";
414 #endif
415 
416  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
417 
418  const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
419 
420  // See if the rcp_node or its object has already been added.
421  typedef rcp_node_list_t::iterator itr_t;
422  typedef std::pair<itr_t, itr_t> itr_itr_t;
423  const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr);
424  const bool rcp_node_already_exists = itr_itr.first != itr_itr.second;
425  RCPNode *previous_rcp_node = 0;
426  bool previous_rcp_node_has_ownership = false;
427  for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
428  previous_rcp_node = itr->second.nodePtr;
429  if (previous_rcp_node->has_ownership()) {
430  previous_rcp_node_has_ownership = true;
431  break;
432  }
433  }
435  rcp_node_already_exists && rcp_node->has_ownership() && previous_rcp_node_has_ownership,
437  "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n"
438  "RCPNode object to an existing managed object in another RCPNode:\n"
439  "\n"
440  " New " << convertRCPNodeToString(rcp_node) << "\n"
441  "\n"
442  " Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
443  "\n"
444  " Number current nodes = " << rcp_node_list()->size() << "\n"
445  "\n"
446  "This may indicate that the user might be trying to create a weak RCP to an existing\n"
447  "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n"
448  "or an equivalent function?\n"
449  "\n"
451  );
452 
453  // NOTE: We allow duplicate RCPNodes if the new node is non-owning. This
454  // might indicate a advanced usage of the RCP class that we want to
455  // support. The typical problem is when the programmer unknowingly
456  // creates an owning RCP to an object already owned by another RCPNode.
457 
458  // Add the new RCP node keyed as described above.
459  (*rcp_node_list()).emplace_hint(
460  itr_itr.second,
461  std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
462  );
463  // NOTE: Above, if there is already an existing RCPNode with the same key
464  // value, this iterator itr_itr.second will point to one after the found
465  // range. I suspect that this might also ensure that the elements are
466  // sorted in natural order.
467 
468  // Update the insertion number an node tracing statistics
469  ++insertionNumber;
470  ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
471  loc_rcpNodeStatistics().maxNumRCPNodes =
472  TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
473  }
474 }
475 
476 
477 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
478  TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
479  std::logic_error, \
480  "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \
481  << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \
482  " active RCP nodes being traced even though all nodes should be traced." \
483  " This should not be possible and can only be an internal programming error!")
484 
485 
487 {
488 
489  // Here, we will try to remove an RCPNode reguardless if whether
490  // loc_isTracingActiveRCPNodes==true or not. This will not be a performance
491  // problem and it will ensure that any RCPNode objects that are added to
492  // this list will be removed and will not look like a memory leak. In
493  // non-debug mode, this function will never be called. In debug mode, with
494  // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
495  // therefore this find(...) operation should be pretty cheap (even for a bad
496  // implementation of std::map).
497 
498 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
499  // lock_guard will unlock in the event of an exception
500  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
501 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
502 
503  TEUCHOS_ASSERT(rcp_node_list());
504 
505  typedef rcp_node_list_t::iterator itr_t;
506  typedef std::pair<itr_t, itr_t> itr_itr_t;
507 
508  const itr_itr_t itr_itr =
509  rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node));
510  const bool rcp_node_exists = itr_itr.first != itr_itr.second;
511 
512 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
513  // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
514  // compile time, then all RCPNode objects that get created will have been
515  // added to this list. In this case, we can asset that the node exists.
516  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
517 #else
518  // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
519  // possible that an RCP got created before the bool
520  // loc_isTracingActiveRCPNodes was turned on. In this case, we must allow
521  // for an RCP node not to have been added to this list. In this case we
522  // will just let this go!
523 #endif
524 
525  if (rcp_node_exists) {
526 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
527  std::cerr
528  << "RCPNodeTracer::removeRCPNode(...): Removing "
529  << convertRCPNodeToString(rcp_node) << " ...\n";
530 #endif
531  bool foundRCPNode = false;
532  for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
533  if (itr->second.nodePtr == rcp_node) {
534  rcp_node_list()->erase(itr);
535  ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions;
536  foundRCPNode = true;
537  break;
538  }
539  }
540  // Whoops! Did not find the node!
541  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
542  }
543 
544 }
545 
546 
548 {
549  typedef rcp_node_list_t::iterator itr_t;
550  typedef std::pair<itr_t, itr_t> itr_itr_t;
551  if (!p)
552  return 0;
553 
554 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
555  // lock_guard will unlock in the event of an exception
556  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
557 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
558 
559  const itr_itr_t itr_itr = rcp_node_list()->equal_range(p);
560  for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
561  RCPNode* rcpNode = itr->second.nodePtr;
562  if (rcpNode->has_ownership()) {
563  return rcpNode;
564  }
565  }
566  return 0;
567  // NOTE: Above, we return the first RCPNode added that has the given key
568  // value.
569 }
570 
571 
573 {
574  return std::string(
575  "\n***"
576  "\n*** Warning! The following Teuchos::RCPNode objects were created but have"
577  "\n*** not been destroyed yet. A memory checking tool may complain that these"
578  "\n*** objects are not destroyed correctly."
579  "\n***"
580  "\n*** There can be many possible reasons that this might occur including:"
581  "\n***"
582  "\n*** a) The program called abort() or exit() before main() was finished."
583  "\n*** All of the objects that would have been freed through destructors"
584  "\n*** are not freed but some compilers (e.g. GCC) will still call the"
585  "\n*** destructors on static objects (which is what causes this message"
586  "\n*** to be printed)."
587  "\n***"
588  "\n*** b) The program is using raw new/delete to manage some objects and"
589  "\n*** delete was not called correctly and the objects not deleted hold"
590  "\n*** other objects through reference-counted pointers."
591  "\n***"
592  "\n*** c) This may be an indication that these objects may be involved in"
593  "\n*** a circular dependency of reference-counted managed objects."
594  "\n***\n"
595  );
596 }
597 
598 
600 {
601  return std::string(
602  "NOTE: To debug issues, open a debugger, and set a break point in the function where\n"
603  "the RCPNode object is first created to determine the context where the object first\n"
604  "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n"
605  "breakpoints in the code. For example, in GDB one can perform:\n"
606  "\n"
607  "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
608  "\n"
609  "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n"
610  "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n"
611  "\n"
612  " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
613  " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
614  "\n"
615  "3) Run the program in the debugger. In GDB, do:\n"
616  "\n"
617  " (gdb) run [ENTER]\n"
618  "\n"
619  "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
620  );
621 }
622 
623 
624 //
625 // ActiveRCPNodesSetup
626 //
627 
628 
630 {
631 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
632  std::cerr << "\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ << "\n";
633 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
634  if (!rcp_node_list())
635  rcp_node_list() = new rcp_node_list_t;
636 
637 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
638  if (!rcp_node_list_mutex()) {
639  rcp_node_list_mutex() = new std::mutex;
640  }
641 #endif
642  ++count_;
643 }
644 
645 
647 {
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;
656  TEUCHOS_TEST_FOR_TERMINATION(nullptr==rcp_node_list(), "rcp_node_list() is null in ~ActiveRCPNodesSetup");
657  RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics =
659  if (rcpNodeStatistics.maxNumRCPNodes
661  {
662  RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
663  }
666  }
667  delete rcp_node_list();
668  rcp_node_list() = 0;
669 
670 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
671  delete rcp_node_list_mutex();
672  rcp_node_list_mutex() = 0;
673 #endif
674  }
675 }
676 
677 
679 {
680  int dummy = count_;
681  ++dummy; // Avoid unused variable warning (bug 2664)
682 }
683 
684 
685 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
686 
687 
688 //
689 // RCPNodeHandle
690 //
691 
692 void RCPNodeHandle::unbindOneStrong()
693 {
694 #ifdef TEUCHOS_DEBUG
696 #endif
697  // do this after removeRCPNode - otherwise another thread can jump in and grab
698  // the memory - then node tracing incorrectly thinks it's a double allocation
699  node_->delete_obj();
700 }
701 
702 void RCPNodeHandle::unbindOneTotal()
703 {
704  delete node_;
705  node_ = 0;
706 }
707 
708 } // namespace Teuchos
709 
710 
711 //
712 // Non-member helpers
713 //
714 
715 
716 void Teuchos::throw_null_ptr_error( const std::string &type_name )
717 {
719  true, NullReferenceError,
720  type_name << " : You can not call operator->() or operator*()"
721  <<" if getRawPtr()==0!" );
722 }
723 
724 // Implement abort and exception handling for RCPNode
725 // Note "PROGRAM ABORTING" text will be checked in a unit test and to
726 // avoid having a more complex code here to ensure no mixed output, I kept that as 1 MPI.
727 // if(!success) added to prevent DEBUG unused variable warning.
728 #ifdef TEUCHOS_DEBUG
729 #define TEUCHOS_IMPLEMENT_ABORT(excpt) \
730  bool success = false; \
731  try { throw excpt; } \
732  TEUCHOS_STANDARD_CATCH_STATEMENTS(true,std::cerr,success); \
733  if(!success) std::cerr << "PROGRAM ABORTING\n"; \
734  GlobalMPISession::abort();
735 
736 void Teuchos::abort_for_exception_in_destructor(const std::exception &exception) {
737  TEUCHOS_IMPLEMENT_ABORT(exception);
738 }
739 void Teuchos::abort_for_exception_in_destructor(const int &code) {
740  TEUCHOS_IMPLEMENT_ABORT(code);
741 }
742 void Teuchos::abort_for_exception_in_destructor() {
743  TEUCHOS_IMPLEMENT_ABORT(std::logic_error(
744  "Caught unknown exception from destructor of RCPNode. Aborting."););
745 }
746 #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.