Teuchos - Trilinos Tools Package  Version of the Day
Teuchos_RCPNode.cpp
1 // @HEADER
2 // ***********************************************************************
3 //
4 // Teuchos: Common Tools Package
5 // Copyright (2004) Sandia Corporation
6 //
7 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
8 // license for use of this work by or on behalf of the U.S. Government.
9 //
10 // Redistribution and use in source and binary forms, with or without
11 // modification, are permitted provided that the following conditions are
12 // met:
13 //
14 // 1. Redistributions of source code must retain the above copyright
15 // notice, this list of conditions and the following disclaimer.
16 //
17 // 2. Redistributions in binary form must reproduce the above copyright
18 // notice, this list of conditions and the following disclaimer in the
19 // documentation and/or other materials provided with the distribution.
20 //
21 // 3. Neither the name of the Corporation nor the names of the
22 // contributors may be used to endorse or promote products derived from
23 // this software without specific prior written permission.
24 //
25 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
26 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 //
37 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
38 //
39 // ***********************************************************************
40 // @HEADER
41 
42 #include "Teuchos_RCPNode.hpp"
43 #include "Teuchos_Assert.hpp"
44 #include "Teuchos_Exceptions.hpp"
45 #include <vector>
46 
47 #ifdef TEUCHOS_DEBUG
48 #include "Teuchos_StandardCatchMacros.hpp"
49 #endif
50 
51 // Defined this to see tracing of RCPNodes created and destroyed
52 //#define RCP_NODE_DEBUG_TRACE_PRINT
53 
54 
55 //
56 // Internal implementatation stuff
57 //
58 
59 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOSCORE_CXX11) && defined(HAVE_TEUCHOS_THREAD_SAFE)
60 #include <mutex>
61 #define USE_MUTEX_TO_PROTECT_NODE_TRACING
62 #endif
63 
64 namespace {
65 
66 
67 //
68 // Local implementation types
69 //
70 
71 
72 struct RCPNodeInfo {
73  RCPNodeInfo() = delete;
74  RCPNodeInfo(const std::string &info_in, Teuchos::RCPNode* nodePtr_in)
75  : info(info_in), nodePtr(nodePtr_in)
76  {}
77  std::string info;
78  Teuchos::RCPNode* nodePtr;
79 };
80 
81 
82 typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
83 
84 
85 typedef std::multimap<const void*, RCPNodeInfo> rcp_node_list_t;
86 
87 //
88 // Local static functions returning references to local static objects to
89 // ensure objects are initilaized.
90 //
91 // Technically speaking, the static functions on RCPNodeTracer that use this
92 // data might be called from other translation units in pre-main code before
93 // this translation unit gets initialized. By using functions returning
94 // references to local static variable trick, we ensure that these objects are
95 // always initialized before they are used, no matter what.
96 //
97 // These could have been static functions on RCPNodeTracer but the advantage
98 // of defining these functions this way is that you can add and remove
99 // functions without affecting the *.hpp file and therefore avoid
100 // recompilation (and even relinking with shared libraries).
101 //
102 
103 
104 rcp_node_list_t*& rcp_node_list()
105 {
106  static rcp_node_list_t *s_rcp_node_list = 0;
107  // Here we must let the ActiveRCPNodesSetup constructor and destructor handle
108  // the creation and destruction of this map object. This will ensure that
109  // this map object will be valid when any global/static RCP objects are
110  // destroyed! Note that this object will get created and destroyed
111  // reguardless if whether we are tracing RCPNodes or not. This just makes our
112  // life simpler. NOTE: This list will always get allocated no mater if
113  // TEUCHOS_DEBUG is defined or node traceing is enabled or not.
114  return s_rcp_node_list;
115 }
116 
117 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
118 std::mutex *& rcp_node_list_mutex()
119 {
120  static std::mutex * s_rcp_node_list_mutex = 0;
121  // This construct exists for the same reason as above (rcp_node_list)
122  // We must keep this mutex in place until all static RCP objects have deleted.
123  return s_rcp_node_list_mutex;
124 }
125 #endif
126 
127 bool& loc_isTracingActiveRCPNodes()
128 {
129  static bool s_loc_isTracingActiveRCPNodes =
130 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
131  true
132 #else
133  false
134 #endif
135  ;
136  return s_loc_isTracingActiveRCPNodes;
137 }
138 
139 
140 Teuchos::RCPNodeTracer::RCPNodeStatistics& loc_rcpNodeStatistics()
141 {
142  static Teuchos::RCPNodeTracer::RCPNodeStatistics s_loc_rcpNodeStatistics;
143  return s_loc_rcpNodeStatistics;
144 }
145 
146 
147 bool& loc_printRCPNodeStatisticsOnExit()
148 {
149  static bool s_loc_printRCPNodeStatisticsOnExit = false;
150  return s_loc_printRCPNodeStatisticsOnExit;
151 }
152 
153 
154 bool& loc_printActiveRcpNodesOnExit()
155 {
156  static bool s_loc_printActiveRcpNodesOnExit = true;
157  return s_loc_printActiveRcpNodesOnExit;
158 }
159 
160 
161 //
162 // Other helper functions
163 //
164 
165 // This function returns the const void* value that is used as the key to look
166 // up an RCPNode object that has been stored. If the RCPNode is holding a
167 // non-null reference, then we use that object address as the key. That way,
168 // we can detect if a user trys to create a new owning RCPNode to the same
169 // object. If the RCPNode has an null internal object pointer, then we will
170 // use the RCPNode's address itself. In this case, we want to check and see
171 // that all RCPNodes that get created get destroyed correctly.
172 const void* get_map_key_void_ptr(const Teuchos::RCPNode* rcp_node)
173 {
174  TEUCHOS_ASSERT(rcp_node);
175 #ifdef TEUCHOS_DEBUG
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;
179 #endif
180  return rcp_node;
181 }
182 
183 
184 std::string convertRCPNodeToString(const Teuchos::RCPNode* rcp_node)
185 {
186  std::ostringstream oss;
187  oss
188  << "RCPNode {address="
189  << rcp_node
190 #ifdef TEUCHOS_DEBUG
191  << ", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr()
192 #endif
193  << ", base_obj_type_name=" << rcp_node->get_base_obj_type_name()
194  << ", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node)
195  << ", has_ownership=" << rcp_node->has_ownership()
196 #ifdef TEUCHOS_DEBUG
197  << ", insertionNumber="<< rcp_node->insertion_number()
198 #endif
199  << "}";
200  return oss.str();
201 }
202 
203 
204 } // namespace
205 
206 
207 namespace Teuchos {
208 
209 
210 //
211 // RCPNode
212 //
213 
214 
216  const any &extra_data, const std::string& name
217  ,EPrePostDestruction destroy_when
218  ,bool force_unique
219  )
220 {
221  if(extra_data_map_==NULL) {
222  extra_data_map_ = new extra_data_map_t;
223  }
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);
226 #ifdef TEUCHOS_DEBUG
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!" );
231 #endif
232  if (itr != extra_data_map_->end()) {
233  // Change existing extra data
234  itr->second = extra_data_entry_t(extra_data,destroy_when);
235  }
236  else {
237  // Insert new extra data
238  (*extra_data_map_)[type_and_name] =
239  extra_data_entry_t(extra_data,destroy_when);
240  }
241 }
242 
243 
244 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name )
245 {
246 #ifdef TEUCHOS_DEBUG
248  extra_data_map_==NULL, std::invalid_argument
249  ,"Error, no extra data has been set yet!" );
250 #endif
251  any *extra_data = get_optional_extra_data(type_name,name);
252 #ifdef TEUCHOS_DEBUG
253  if (!extra_data) {
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!" );
258  }
259 #endif
260  return *extra_data;
261 }
262 
263 
264 any* RCPNode::get_optional_extra_data( const std::string& type_name,
265  const std::string& name )
266 {
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;
272  return NULL;
273 }
274 
275 
276 void RCPNode::impl_pre_delete_extra_data()
277 {
278  for(
279  extra_data_map_t::iterator itr = extra_data_map_->begin();
280  itr != extra_data_map_->end();
281  ++itr
282  )
283  {
284  extra_data_map_t::value_type &entry = *itr;
285  if(entry.second.destroy_when == PRE_DESTROY)
286  entry.second.extra_data = any();
287  }
288 }
289 
290 
291 //
292 // RCPNodeTracer
293 //
294 
295 
296 // General user functions
297 
298 
300 {
301  return loc_isTracingActiveRCPNodes();
302 }
303 
304 
305 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
306 void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
307 {
308  loc_isTracingActiveRCPNodes() = tracingActiveNodes;
309 }
310 #endif
311 
312 
314 {
315  // This list always exists, no matter debug or not so just access it.
316  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
317  return static_cast<int>(rcp_node_list()->size());
318 }
319 
320 
323 {
324  return loc_rcpNodeStatistics();
325 }
326 
328  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
329 {
330  out
331  << "\n***"
332  << "\n*** RCPNode Tracing statistics:"
333  << "\n**\n"
334  << "\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
335  << "\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
336  << "\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
337  << "\n";
338 }
339 
340 
342  bool printRCPNodeStatisticsOnExit)
343 {
344  loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
345 }
346 
347 
349 {
350  return loc_printRCPNodeStatisticsOnExit();
351 }
352 
353 
354 void RCPNodeTracer::setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
355 {
356  loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
357 }
358 
359 
361 {
362  return loc_printActiveRcpNodesOnExit();
363 }
364 
365 
366 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
367 {
368 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
369  out
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()) {
374  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
375  if (rcp_node_list()->size() > 0) {
377  // Create a sorted-by-insertionNumber list
378  // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
379  // because this called at the very end and uses RCPNode itself in a
380  // debug-mode build.
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)
385  {
386 #ifdef TEUCHOS_DEBUG
387  return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
388 #else
389  return v1.first < v2.first;
390 #endif
391  }
392  );
393  // Print the RCPNode objects sorted by insertion number
394  typedef rcp_node_vec_t::const_iterator itr_t;
395  int i = 0;
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;
398  TEUCHOS_ASSERT(entry.second.nodePtr);
399  out
400  << "\n"
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"
405 #ifdef TEUCHOS_DEBUG
406  << " insertionNumber = " << entry.second.nodePtr->insertion_number()
407 #endif
408  ;
409  ++i;
410  }
411  out << "\n\n"
413  }
414  }
415 }
416 
417 
418 // Internal implementation functions
419 
420 
421 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
422 {
423 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
424  // lock_guard will unlock in the event of an exception
425  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
426 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
427 
428  // Used to allow unique identification of rcp_node to allow setting breakpoints
429  static int insertionNumber = 0;
430 
431  // Set the insertion number right away in case an exception gets thrown so
432  // that you can set a break point to debug this.
433 #ifdef TEUCHOS_DEBUG
434  rcp_node->set_insertion_number(insertionNumber);
435 #endif
436 
437  if (loc_isTracingActiveRCPNodes()) {
438 
439  // Print the node we are adding if configured to do so. We have to send
440  // to std::cerr to make sure that this gets printed.
441 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
442  std::cerr
443  << "RCPNodeTracer::addNewRCPNode(...): Adding "
444  << convertRCPNodeToString(rcp_node) << " ...\n";
445 #endif
446 
447  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
448 
449  const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
450 
451  // See if the rcp_node or its object has already been added.
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;
460  if (previous_rcp_node->has_ownership()) {
461  previous_rcp_node_has_ownership = true;
462  break;
463  }
464  }
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"
470  "\n"
471  " New " << convertRCPNodeToString(rcp_node) << "\n"
472  "\n"
473  " Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
474  "\n"
475  " Number current nodes = " << rcp_node_list()->size() << "\n"
476  "\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"
480  "\n"
482  );
483 
484  // NOTE: We allow duplicate RCPNodes if the new node is non-owning. This
485  // might indicate a advanced usage of the RCP class that we want to
486  // support. The typical problem is when the programmer unknowingly
487  // creates an owning RCP to an object already owned by another RCPNode.
488 
489  // Add the new RCP node keyed as described above.
490  (*rcp_node_list()).emplace_hint(
491  itr_itr.second,
492  std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
493  );
494  // NOTE: Above, if there is already an existing RCPNode with the same key
495  // value, this iterator itr_itr.second will point to one after the found
496  // range. I suspect that this might also ensure that the elements are
497  // sorted in natural order.
498 
499  // Update the insertion number an node tracing statistics
500  ++insertionNumber;
501  ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
502  loc_rcpNodeStatistics().maxNumRCPNodes =
503  TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
504  }
505 }
506 
507 
508 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
509  TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
510  std::logic_error, \
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!")
515 
516 
518 {
519 
520  // Here, we will try to remove an RCPNode reguardless if whether
521  // loc_isTracingActiveRCPNodes==true or not. This will not be a performance
522  // problem and it will ensure that any RCPNode objects that are added to
523  // this list will be removed and will not look like a memory leak. In
524  // non-debug mode, this function will never be called. In debug mode, with
525  // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
526  // therefore this find(...) operation should be pretty cheap (even for a bad
527  // implementation of std::map).
528 
529 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
530  // lock_guard will unlock in the event of an exception
531  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
532 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
533 
534  TEUCHOS_ASSERT(rcp_node_list());
535 
536  typedef rcp_node_list_t::iterator itr_t;
537  typedef std::pair<itr_t, itr_t> itr_itr_t;
538 
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;
542 
543 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
544  // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
545  // compile time, then all RCPNode objects that get created will have been
546  // added to this list. In this case, we can asset that the node exists.
547  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
548 #else
549  // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
550  // possible that an RCP got created before the bool
551  // loc_isTracingActiveRCPNodes was turned on. In this case, we must allow
552  // for an RCP node not to have been added to this list. In this case we
553  // will just let this go!
554 #endif
555 
556  if (rcp_node_exists) {
557 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
558  std::cerr
559  << "RCPNodeTracer::removeRCPNode(...): Removing "
560  << convertRCPNodeToString(rcp_node) << " ...\n";
561 #endif
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;
567  foundRCPNode = true;
568  break;
569  }
570  }
571  // Whoops! Did not find the node!
572  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
573  }
574 
575 }
576 
577 
579 {
580  typedef rcp_node_list_t::iterator itr_t;
581  typedef std::pair<itr_t, itr_t> itr_itr_t;
582  if (!p)
583  return 0;
584 
585 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
586  // lock_guard will unlock in the event of an exception
587  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
588 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
589 
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;
593  if (rcpNode->has_ownership()) {
594  return rcpNode;
595  }
596  }
597  return 0;
598  // NOTE: Above, we return the first RCPNode added that has the given key
599  // value.
600 }
601 
602 
604 {
605  return std::string(
606  "\n***"
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."
610  "\n***"
611  "\n*** There can be many possible reasons that this might occur including:"
612  "\n***"
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)."
618  "\n***"
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."
622  "\n***"
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."
625  "\n***\n"
626  );
627 }
628 
629 
631 {
632  return std::string(
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"
637  "\n"
638  "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
639  "\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"
642  "\n"
643  " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
644  " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
645  "\n"
646  "3) Run the program in the debugger. In GDB, do:\n"
647  "\n"
648  " (gdb) run [ENTER]\n"
649  "\n"
650  "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
651  );
652 }
653 
654 
655 //
656 // ActiveRCPNodesSetup
657 //
658 
659 
661 {
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;
667 
668 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
669  if (!rcp_node_list_mutex()) {
670  rcp_node_list_mutex() = new std::mutex;
671  }
672 #endif
673  ++count_;
674 }
675 
676 
678 {
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;
687  TEUCHOS_TEST_FOR_TERMINATION(nullptr==rcp_node_list(), "rcp_node_list() is null in ~ActiveRCPNodesSetup");
688  RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics =
690  if (rcpNodeStatistics.maxNumRCPNodes
692  {
693  RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
694  }
697  }
698  delete rcp_node_list();
699  rcp_node_list() = 0;
700 
701 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
702  delete rcp_node_list_mutex();
703  rcp_node_list_mutex() = 0;
704 #endif
705  }
706 }
707 
708 
710 {
711  int dummy = count_;
712  ++dummy; // Avoid unused variable warning (bug 2664)
713 }
714 
715 
716 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
717 
718 
719 //
720 // RCPNodeHandle
721 //
722 
723 void RCPNodeHandle::unbindOneStrong()
724 {
725 #ifdef TEUCHOS_DEBUG
727 #endif
728  // do this after removeRCPNode - otherwise another thread can jump in and grab
729  // the memory - then node tracing incorrectly thinks it's a double allocation
730  node_->delete_obj();
731 }
732 
733 void RCPNodeHandle::unbindOneTotal()
734 {
735  delete node_;
736  node_ = 0;
737 }
738 
739 } // namespace Teuchos
740 
741 
742 //
743 // Non-member helpers
744 //
745 
746 
747 void Teuchos::throw_null_ptr_error( const std::string &type_name )
748 {
750  true, NullReferenceError,
751  type_name << " : You can not call operator->() or operator*()"
752  <<" if getRawPtr()==0!" );
753 }
754 
755 // Implement abort and exception handling for RCPNode
756 // Note "PROGRAM ABORTING" text will be checked in a unit test and to
757 // avoid having a more complex code here to ensure no mixed output, I kept that as 1 MPI.
758 // if(!success) added to prevent DEBUG unused variable warning.
759 #ifdef TEUCHOS_DEBUG
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();
766 
767 void Teuchos::abort_for_exception_in_destructor(const std::exception &exception) {
768  TEUCHOS_IMPLEMENT_ABORT(exception);
769 }
770 void Teuchos::abort_for_exception_in_destructor(const int &code) {
771  TEUCHOS_IMPLEMENT_ABORT(code);
772 }
773 void Teuchos::abort_for_exception_in_destructor() {
774  TEUCHOS_IMPLEMENT_ABORT(std::logic_error(
775  "Caught unknown exception from destructor of RCPNode. Aborting."););
776 }
777 #endif // TEUCHOS_DEBUG
TEUCHOS_TEST_FOR_EXCEPT
#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.
Definition: Teuchos_TestForException.hpp:307
Teuchos::RCPNode::get_base_obj_type_name
virtual const std::string get_base_obj_type_name() const =0
Teuchos::RCPNodeTracer::printActiveRCPNodes
static void printActiveRCPNodes(std::ostream &out)
Print the list of currently active RCP nodes.
Definition: Teuchos_RCPNode.cpp:366
Teuchos::RCPNodeTracer::getCommonDebugNotesString
static std::string getCommonDebugNotesString()
Common error message string on how to debug RCPNode problems.
Definition: Teuchos_RCPNode.cpp:630
Teuchos::RCPNodeTracer::RCPNodeStatistics
RCP statistics struct.
Definition: Teuchos_RCPNode.hpp:376
Teuchos::ActiveRCPNodesSetup::ActiveRCPNodesSetup
ActiveRCPNodesSetup()
Definition: Teuchos_RCPNode.cpp:660
Teuchos::RCPNodeTracer::isTracingActiveRCPNodes
static bool isTracingActiveRCPNodes()
Return if we are tracing active nodes or not.
Definition: Teuchos_RCPNode.cpp:299
Teuchos::RCPNodeTracer::getExistingRCPNodeGivenLookupKey
static RCPNode * getExistingRCPNodeGivenLookupKey(const void *lookupKey)
Return a raw pointer to an existing owning RCPNode given its lookup key.
Definition: Teuchos_RCPNode.cpp:578
Teuchos::ActiveRCPNodesSetup::foo
void foo()
Definition: Teuchos_RCPNode.cpp:709
TEUCHOS_ASSERT
#define TEUCHOS_ASSERT(assertion_test)
This macro is throws when an assert fails.
Definition: Teuchos_Assert.hpp:55
TEUCHOS_TEST_FOR_TERMINATION
#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...
Definition: Teuchos_TestForException.hpp:379
Teuchos::RCPNodeTracer::setPrintRCPNodeStatisticsOnExit
static void setPrintRCPNodeStatisticsOnExit(bool printRCPNodeStatisticsOnExit)
Set if RCPNode usage statistics will be printed when the program ends or not.
Definition: Teuchos_RCPNode.cpp:341
Teuchos::RCPNodeTracer::getRCPNodeStatistics
static RCPNodeStatistics getRCPNodeStatistics()
Return the statistics on RCPNode allocations.
Definition: Teuchos_RCPNode.cpp:322
Teuchos_RCPNode.hpp
Reference-counted pointer node classes.
Teuchos::DuplicateOwningRCPError
Thrown if a duplicate owning RCP is creatd the the same object.
Definition: Teuchos_Exceptions.hpp:69
Teuchos::RCPNodeTracer::getPrintActiveRcpNodesOnExit
static bool getPrintActiveRcpNodesOnExit()
Return if printActiveRCPNodes() is called on exit from the program.
Definition: Teuchos_RCPNode.cpp:360
Teuchos::RCPNodeTracer::getPrintRCPNodeStatisticsOnExit
static bool getPrintRCPNodeStatisticsOnExit()
Return if RCPNode usage statistics will be printed when the program ends or not.
Definition: Teuchos_RCPNode.cpp:348
Teuchos::RCPNodeTracer::removeRCPNode
static void removeRCPNode(RCPNode *rcp_node)
Remove an RCPNode from global list.
Definition: Teuchos_RCPNode.cpp:517
Teuchos::RCPNode
Node class to keep track of address and the reference count for a reference-counted utility class and...
Definition: Teuchos_RCPNode.hpp:154
Teuchos::ActiveRCPNodesSetup::~ActiveRCPNodesSetup
~ActiveRCPNodesSetup()
Definition: Teuchos_RCPNode.cpp:677
Teuchos::RCPNodeTracer::numActiveRCPNodes
static int numActiveRCPNodes()
Print the number of active RCPNode objects currently being tracked.
Definition: Teuchos_RCPNode.cpp:313
Teuchos::RCPNode::set_extra_data
void set_extra_data(const any &extra_data, const std::string &name, EPrePostDestruction destroy_when, bool force_unique)
Definition: Teuchos_RCPNode.cpp:215
Teuchos::RCPNodeTracer::getActiveRCPNodeHeaderString
static std::string getActiveRCPNodeHeaderString()
Header string used in printActiveRCPNodes().
Definition: Teuchos_RCPNode.cpp:603
Teuchos::any::typeName
std::string typeName() const
Return the name of the type.
Definition: Teuchos_any.hpp:214
Teuchos::RCPNodeTracer::addNewRCPNode
static void addNewRCPNode(RCPNode *rcp_node, const std::string &info)
Add new RCPNode to the global list.
Definition: Teuchos_RCPNode.cpp:421
Teuchos::RCPNode::delete_obj
virtual void delete_obj()=0
Teuchos::EPrePostDestruction
EPrePostDestruction
Used to specify a pre or post destruction of extra data.
Definition: Teuchos_RCPNode.hpp:79
Teuchos::RCPNodeTracer::setPrintActiveRcpNodesOnExit
static void setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
Set if printActiveRCPNodes() is called on exit from the program.
Definition: Teuchos_RCPNode.cpp:354
Teuchos::RCPNodeTracer::printRCPNodeStatistics
static void printRCPNodeStatistics(const RCPNodeStatistics &rcpNodeStatistics, std::ostream &out)
Print the RCPNode allocation statistics.
Definition: Teuchos_RCPNode.cpp:327
Teuchos
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...
Teuchos::RCPNode::get_optional_extra_data
any * get_optional_extra_data(const std::string &type_name, const std::string &name)
Definition: Teuchos_RCPNode.cpp:264
Teuchos::RCPNode::has_ownership
void has_ownership(bool has_ownership_in)
Definition: Teuchos_RCPNode.hpp:234
TEUCHOS_TEST_FOR_EXCEPTION
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
Definition: Teuchos_TestForException.hpp:170
Teuchos::any
Modified boost::any class, which is a container for a templated value.
Definition: Teuchos_any.hpp:154
Teuchos::RCPNode::get_extra_data
any & get_extra_data(const std::string &type_name, const std::string &name)
Definition: Teuchos_RCPNode.cpp:244