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  (void)force_unique;
222  if(extra_data_map_==NULL) {
223  extra_data_map_ = new extra_data_map_t;
224  }
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);
227 #ifdef TEUCHOS_DEBUG
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!" );
232 #endif
233  if (itr != extra_data_map_->end()) {
234  // Change existing extra data
235  itr->second = extra_data_entry_t(extra_data,destroy_when);
236  }
237  else {
238  // Insert new extra data
239  (*extra_data_map_)[type_and_name] =
240  extra_data_entry_t(extra_data,destroy_when);
241  }
242 }
243 
244 
245 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name )
246 {
247 #ifdef TEUCHOS_DEBUG
249  extra_data_map_==NULL, std::invalid_argument
250  ,"Error, no extra data has been set yet!" );
251 #endif
252  any *extra_data = get_optional_extra_data(type_name,name);
253 #ifdef TEUCHOS_DEBUG
254  if (!extra_data) {
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!" );
259  }
260 #endif
261  return *extra_data;
262 }
263 
264 
265 any* RCPNode::get_optional_extra_data( const std::string& type_name,
266  const std::string& name )
267 {
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;
273  return NULL;
274 }
275 
276 
277 void RCPNode::impl_pre_delete_extra_data()
278 {
279  for(
280  extra_data_map_t::iterator itr = extra_data_map_->begin();
281  itr != extra_data_map_->end();
282  ++itr
283  )
284  {
285  extra_data_map_t::value_type &entry = *itr;
286  if(entry.second.destroy_when == PRE_DESTROY)
287  entry.second.extra_data = any();
288  }
289 }
290 
291 
292 //
293 // RCPNodeTracer
294 //
295 
296 
297 // General user functions
298 
299 
301 {
302  return loc_isTracingActiveRCPNodes();
303 }
304 
305 
306 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
307 void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
308 {
309  loc_isTracingActiveRCPNodes() = tracingActiveNodes;
310 }
311 #endif
312 
313 
315 {
316  // This list always exists, no matter debug or not so just access it.
317  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
318  return static_cast<int>(rcp_node_list()->size());
319 }
320 
321 
324 {
325  return loc_rcpNodeStatistics();
326 }
327 
329  const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
330 {
331  out
332  << "\n***"
333  << "\n*** RCPNode Tracing statistics:"
334  << "\n**\n"
335  << "\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
336  << "\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
337  << "\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
338  << "\n";
339 }
340 
341 
343  bool printRCPNodeStatisticsOnExit)
344 {
345  loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit;
346 }
347 
348 
350 {
351  return loc_printRCPNodeStatisticsOnExit();
352 }
353 
354 
355 void RCPNodeTracer::setPrintActiveRcpNodesOnExit(bool printActiveRcpNodesOnExit)
356 {
357  loc_printActiveRcpNodesOnExit() = printActiveRcpNodesOnExit;
358 }
359 
360 
362 {
363  return loc_printActiveRcpNodesOnExit();
364 }
365 
366 
367 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out)
368 {
369 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
370  out
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()) {
375  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
376  if (rcp_node_list()->size() > 0) {
378  // Create a sorted-by-insertionNumber list
379  // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
380  // because this called at the very end and uses RCPNode itself in a
381  // debug-mode build.
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)
386  {
387 #ifdef TEUCHOS_DEBUG
388  return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
389 #else
390  return v1.first < v2.first;
391 #endif
392  }
393  );
394  // Print the RCPNode objects sorted by insertion number
395  typedef rcp_node_vec_t::const_iterator itr_t;
396  int i = 0;
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;
399  TEUCHOS_ASSERT(entry.second.nodePtr);
400  out
401  << "\n"
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"
406 #ifdef TEUCHOS_DEBUG
407  << " insertionNumber = " << entry.second.nodePtr->insertion_number()
408 #endif
409  ;
410  ++i;
411  }
412  out << "\n\n"
414  }
415  }
416 }
417 
418 
419 // Internal implementation functions
420 
421 
422 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
423 {
424 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
425  // lock_guard will unlock in the event of an exception
426  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
427 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
428 
429  // Used to allow unique identification of rcp_node to allow setting breakpoints
430  static int insertionNumber = 0;
431 
432  // Set the insertion number right away in case an exception gets thrown so
433  // that you can set a break point to debug this.
434 #ifdef TEUCHOS_DEBUG
435  rcp_node->set_insertion_number(insertionNumber);
436 #endif
437 
438  if (loc_isTracingActiveRCPNodes()) {
439 
440  // Print the node we are adding if configured to do so. We have to send
441  // to std::cerr to make sure that this gets printed.
442 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
443  std::cerr
444  << "RCPNodeTracer::addNewRCPNode(...): Adding "
445  << convertRCPNodeToString(rcp_node) << " ...\n";
446 #endif
447 
448  TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list());
449 
450  const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
451 
452  // See if the rcp_node or its object has already been added.
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;
461  if (previous_rcp_node->has_ownership()) {
462  previous_rcp_node_has_ownership = true;
463  break;
464  }
465  }
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"
471  "\n"
472  " New " << convertRCPNodeToString(rcp_node) << "\n"
473  "\n"
474  " Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
475  "\n"
476  " Number current nodes = " << rcp_node_list()->size() << "\n"
477  "\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"
481  "\n"
483  );
484 
485  // NOTE: We allow duplicate RCPNodes if the new node is non-owning. This
486  // might indicate a advanced usage of the RCP class that we want to
487  // support. The typical problem is when the programmer unknowingly
488  // creates an owning RCP to an object already owned by another RCPNode.
489 
490  // Add the new RCP node keyed as described above.
491  (*rcp_node_list()).emplace_hint(
492  itr_itr.second,
493  std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
494  );
495  // NOTE: Above, if there is already an existing RCPNode with the same key
496  // value, this iterator itr_itr.second will point to one after the found
497  // range. I suspect that this might also ensure that the elements are
498  // sorted in natural order.
499 
500  // Update the insertion number an node tracing statistics
501  ++insertionNumber;
502  ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
503  loc_rcpNodeStatistics().maxNumRCPNodes =
504  TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
505  }
506 }
507 
508 
509 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
510  TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
511  std::logic_error, \
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!")
516 
517 
519 {
520 
521  // Here, we will try to remove an RCPNode reguardless if whether
522  // loc_isTracingActiveRCPNodes==true or not. This will not be a performance
523  // problem and it will ensure that any RCPNode objects that are added to
524  // this list will be removed and will not look like a memory leak. In
525  // non-debug mode, this function will never be called. In debug mode, with
526  // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
527  // therefore this find(...) operation should be pretty cheap (even for a bad
528  // implementation of std::map).
529 
530 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
531  // lock_guard will unlock in the event of an exception
532  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
533 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
534 
535  TEUCHOS_ASSERT(rcp_node_list());
536 
537  typedef rcp_node_list_t::iterator itr_t;
538  typedef std::pair<itr_t, itr_t> itr_itr_t;
539 
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;
543 
544 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
545  // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
546  // compile time, then all RCPNode objects that get created will have been
547  // added to this list. In this case, we can asset that the node exists.
548  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
549 #else
550  // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
551  // possible that an RCP got created before the bool
552  // loc_isTracingActiveRCPNodes was turned on. In this case, we must allow
553  // for an RCP node not to have been added to this list. In this case we
554  // will just let this go!
555 #endif
556 
557  if (rcp_node_exists) {
558 #ifdef RCP_NODE_DEBUG_TRACE_PRINT
559  std::cerr
560  << "RCPNodeTracer::removeRCPNode(...): Removing "
561  << convertRCPNodeToString(rcp_node) << " ...\n";
562 #endif
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;
568  foundRCPNode = true;
569  break;
570  }
571  }
572  // Whoops! Did not find the node!
573  TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
574  }
575 
576 }
577 
578 
580 {
581  typedef rcp_node_list_t::iterator itr_t;
582  typedef std::pair<itr_t, itr_t> itr_itr_t;
583  if (!p)
584  return 0;
585 
586 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
587  // lock_guard will unlock in the event of an exception
588  std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
589 #endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
590 
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;
594  if (rcpNode->has_ownership()) {
595  return rcpNode;
596  }
597  }
598  return 0;
599  // NOTE: Above, we return the first RCPNode added that has the given key
600  // value.
601 }
602 
603 
605 {
606  return std::string(
607  "\n***"
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."
611  "\n***"
612  "\n*** There can be many possible reasons that this might occur including:"
613  "\n***"
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)."
619  "\n***"
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."
623  "\n***"
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."
626  "\n***\n"
627  );
628 }
629 
630 
632 {
633  return std::string(
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"
638  "\n"
639  "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
640  "\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"
643  "\n"
644  " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
645  " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
646  "\n"
647  "3) Run the program in the debugger. In GDB, do:\n"
648  "\n"
649  " (gdb) run [ENTER]\n"
650  "\n"
651  "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
652  );
653 }
654 
655 
656 //
657 // ActiveRCPNodesSetup
658 //
659 
660 
662 {
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;
668 
669 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
670  if (!rcp_node_list_mutex()) {
671  rcp_node_list_mutex() = new std::mutex;
672  }
673 #endif
674  ++count_;
675 }
676 
677 
679 {
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;
688  TEUCHOS_TEST_FOR_TERMINATION(nullptr==rcp_node_list(), "rcp_node_list() is null in ~ActiveRCPNodesSetup");
689  RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics =
691  if (rcpNodeStatistics.maxNumRCPNodes
693  {
694  RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout);
695  }
698  }
699  delete rcp_node_list();
700  rcp_node_list() = 0;
701 
702 #ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
703  delete rcp_node_list_mutex();
704  rcp_node_list_mutex() = 0;
705 #endif
706  }
707 }
708 
709 
711 {
712  int dummy = count_;
713  ++dummy; // Avoid unused variable warning (bug 2664)
714 }
715 
716 
717 int Teuchos::ActiveRCPNodesSetup::count_ = 0;
718 
719 
720 //
721 // RCPNodeHandle
722 //
723 
724 void RCPNodeHandle::unbindOneStrong()
725 {
726 #ifdef TEUCHOS_DEBUG
728 #endif
729  // do this after removeRCPNode - otherwise another thread can jump in and grab
730  // the memory - then node tracing incorrectly thinks it's a double allocation
731  node_->delete_obj();
732 }
733 
734 void RCPNodeHandle::unbindOneTotal()
735 {
736  delete node_;
737  node_ = 0;
738 }
739 
740 } // namespace Teuchos
741 
742 
743 //
744 // Non-member helpers
745 //
746 
747 
748 void Teuchos::throw_null_ptr_error( const std::string &type_name )
749 {
751  true, NullReferenceError,
752  type_name << " : You can not call operator->() or operator*()"
753  <<" if getRawPtr()==0!" );
754 }
755 
756 // Implement abort and exception handling for RCPNode
757 // Note "PROGRAM ABORTING" text will be checked in a unit test and to
758 // avoid having a more complex code here to ensure no mixed output, I kept that as 1 MPI.
759 // if(!success) added to prevent DEBUG unused variable warning.
760 #ifdef TEUCHOS_DEBUG
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();
767 
768 void Teuchos::abort_for_exception_in_destructor(const std::exception &exception) {
769  TEUCHOS_IMPLEMENT_ABORT(exception);
770 }
771 void Teuchos::abort_for_exception_in_destructor(const int &code) {
772  TEUCHOS_IMPLEMENT_ABORT(code);
773 }
774 void Teuchos::abort_for_exception_in_destructor() {
775  TEUCHOS_IMPLEMENT_ABORT(std::logic_error(
776  "Caught unknown exception from destructor of RCPNode. Aborting."););
777 }
778 #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:367
Teuchos::RCPNodeTracer::getCommonDebugNotesString
static std::string getCommonDebugNotesString()
Common error message string on how to debug RCPNode problems.
Definition: Teuchos_RCPNode.cpp:631
Teuchos::RCPNodeTracer::RCPNodeStatistics
RCP statistics struct.
Definition: Teuchos_RCPNode.hpp:375
Teuchos::ActiveRCPNodesSetup::ActiveRCPNodesSetup
ActiveRCPNodesSetup()
Definition: Teuchos_RCPNode.cpp:661
Teuchos::RCPNodeTracer::isTracingActiveRCPNodes
static bool isTracingActiveRCPNodes()
Return if we are tracing active nodes or not.
Definition: Teuchos_RCPNode.cpp:300
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:579
Teuchos::ActiveRCPNodesSetup::foo
void foo()
Definition: Teuchos_RCPNode.cpp:710
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:342
Teuchos::RCPNodeTracer::getRCPNodeStatistics
static RCPNodeStatistics getRCPNodeStatistics()
Return the statistics on RCPNode allocations.
Definition: Teuchos_RCPNode.cpp:323
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:70
Teuchos::RCPNodeTracer::getPrintActiveRcpNodesOnExit
static bool getPrintActiveRcpNodesOnExit()
Return if printActiveRCPNodes() is called on exit from the program.
Definition: Teuchos_RCPNode.cpp:361
Teuchos::RCPNodeTracer::getPrintRCPNodeStatisticsOnExit
static bool getPrintRCPNodeStatisticsOnExit()
Return if RCPNode usage statistics will be printed when the program ends or not.
Definition: Teuchos_RCPNode.cpp:349
Teuchos::RCPNodeTracer::removeRCPNode
static void removeRCPNode(RCPNode *rcp_node)
Remove an RCPNode from global list.
Definition: Teuchos_RCPNode.cpp:518
Teuchos::RCPNode
Node class to keep track of address and the reference count for a reference-counted utility class and...
Definition: Teuchos_RCPNode.hpp:153
Teuchos::ActiveRCPNodesSetup::~ActiveRCPNodesSetup
~ActiveRCPNodesSetup()
Definition: Teuchos_RCPNode.cpp:678
Teuchos::RCPNodeTracer::numActiveRCPNodes
static int numActiveRCPNodes()
Print the number of active RCPNode objects currently being tracked.
Definition: Teuchos_RCPNode.cpp:314
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:604
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:422
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:355
Teuchos::RCPNodeTracer::printRCPNodeStatistics
static void printRCPNodeStatistics(const RCPNodeStatistics &rcpNodeStatistics, std::ostream &out)
Print the RCPNode allocation statistics.
Definition: Teuchos_RCPNode.cpp:328
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:265
Teuchos::RCPNode::has_ownership
void has_ownership(bool has_ownership_in)
Definition: Teuchos_RCPNode.hpp:233
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:155
Teuchos::RCPNode::get_extra_data
any & get_extra_data(const std::string &type_name, const std::string &name)
Definition: Teuchos_RCPNode.cpp:245