Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
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
32namespace {
33
34
35//
36// Local implementation types
37//
38
39
40struct 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
50typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
51
52
53typedef 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
72rcp_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
86std::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
95bool& 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
108Teuchos::RCPNodeTracer::RCPNodeStatistics& loc_rcpNodeStatistics()
109{
110 static Teuchos::RCPNodeTracer::RCPNodeStatistics s_loc_rcpNodeStatistics;
111 return s_loc_rcpNodeStatistics;
112}
113
114
115bool& loc_printRCPNodeStatisticsOnExit()
116{
117 static bool s_loc_printRCPNodeStatisticsOnExit = false;
118 return s_loc_printRCPNodeStatisticsOnExit;
119}
120
121
122bool& 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.
140const 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
152std::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
175namespace 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{
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
213any& 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
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
245void throw_invalid_obj_exception_free_fun( const std::string& rcp_type_name,
246 const void* rcp_ptr,
247 const RCPNode* rcp_node_ptr,
248 const void* rcp_obj_ptr,
249 const void *ptr_,
251 const void *deleted_ptr_,
252#endif
253 const std::string& type_name)
254{
255 TEUCHOS_TEST_FOR_EXCEPT_MSG( ptr_!=0, "Internal coding error!" );
256 const void* deleted_ptr =
257#ifdef TEUCHOS_DEBUG
259#else
260 0
261#endif
262 ;
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"
268 "\n"
269 "Context information:\n"
270 "\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"
278 "\n"
280 );
281 // 2008/09/22: rabartl: Above, we do not provide the concreate object
282 // type or the concrete object address. In the case of the concrete
283 // object address, in a non-debug build, we don't want to pay a price
284 // for extra storage that we strictly don't need. In the case of the
285 // concrete object type name, we don't want to force non-debug built
286 // code to have the require that types be fully defined in order to use
287 // the memory management software. This is related to bug 4016.
288}
289
290
291void RCPNode::impl_pre_delete_extra_data()
292{
293 for(
294 extra_data_map_t::iterator itr = extra_data_map_->begin();
295 itr != extra_data_map_->end();
296 ++itr
297 )
298 {
299 extra_data_map_t::value_type &entry = *itr;
300 if(entry.second.destroy_when == PRE_DESTROY)
301 entry.second.extra_data = any();
302 }
303}
304
305
306//
307// RCPNodeTracer
308//
309
310
311// General user functions
312
313
318
319
320#if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
321void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
322{
324}
325#endif
326
327
329{
330 // This list always exists, no matter debug or not so just access it.
332 return static_cast<int>(rcp_node_list()->size());
333}
334
335
341
343 const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out)
344{
345 out
346 << "\n***"
347 << "\n*** RCPNode Tracing statistics:"
348 << "\n**\n"
349 << "\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes
350 << "\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations
351 << "\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions
352 << "\n";
353}
354
355
361
362
367
368
373
374
379
380
382{
383#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
384 out
385 << "\nCalled printActiveRCPNodes() :"
386 << " rcp_node_list.size() = " << rcp_node_list().size() << "\n";
387#endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
390 if (rcp_node_list()->size() > 0) {
392 // Create a sorted-by-insertionNumber list
393 // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here
394 // because this called at the very end and uses RCPNode itself in a
395 // debug-mode build.
396 typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t;
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)
400 {
401#ifdef TEUCHOS_DEBUG
402 return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number();
403#else
404 return v1.first < v2.first;
405#endif
406 }
407 );
408 // Print the RCPNode objects sorted by insertion number
409 typedef rcp_node_vec_t::const_iterator itr_t;
410 int i = 0;
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;
413 TEUCHOS_ASSERT(entry.second.nodePtr);
414 out
415 << "\n"
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"
420#ifdef TEUCHOS_DEBUG
421 << " insertionNumber = " << entry.second.nodePtr->insertion_number()
422#endif
423 ;
424 ++i;
425 }
426 out << "\n\n"
428 }
429 }
430}
431
432
433// Internal implementation functions
434
435
436void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info )
437{
438#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
439 // lock_guard will unlock in the event of an exception
440 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
441#endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
442
443 // Used to allow unique identification of rcp_node to allow setting breakpoints
444 static int insertionNumber = 0;
445
446 // Set the insertion number right away in case an exception gets thrown so
447 // that you can set a break point to debug this.
448#ifdef TEUCHOS_DEBUG
449 rcp_node->set_insertion_number(insertionNumber);
450#endif
451
453
454 // Print the node we are adding if configured to do so. We have to send
455 // to std::cerr to make sure that this gets printed.
456#ifdef RCP_NODE_DEBUG_TRACE_PRINT
457 std::cerr
458 << "RCPNodeTracer::addNewRCPNode(...): Adding "
459 << convertRCPNodeToString(rcp_node) << " ...\n";
460#endif
461
463
464 const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node);
465
466 // See if the rcp_node or its object has already been added.
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;
473 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) {
474 previous_rcp_node = itr->second.nodePtr;
477 break;
478 }
479 }
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"
485 "\n"
486 " New " << convertRCPNodeToString(rcp_node) << "\n"
487 "\n"
488 " Existing " << convertRCPNodeToString(previous_rcp_node) << "\n"
489 "\n"
490 " Number current nodes = " << rcp_node_list()->size() << "\n"
491 "\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"
495 "\n"
497 );
498
499 // NOTE: We allow duplicate RCPNodes if the new node is non-owning. This
500 // might indicate a advanced usage of the RCP class that we want to
501 // support. The typical problem is when the programmer unknowingly
502 // creates an owning RCP to an object already owned by another RCPNode.
503
504 // Add the new RCP node keyed as described above.
506 itr_itr.second,
507 std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node))
508 );
509 // NOTE: Above, if there is already an existing RCPNode with the same key
510 // value, this iterator itr_itr.second will point to one after the found
511 // range. I suspect that this might also ensure that the elements are
512 // sorted in natural order.
513
514 // Update the insertion number an node tracing statistics
516 ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
517 loc_rcpNodeStatistics().maxNumRCPNodes =
518 TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes());
519 }
520}
521
522
523#define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \
524 TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \
525 std::logic_error, \
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!")
530
531
533{
534
535 // Here, we will try to remove an RCPNode reguardless if whether
536 // loc_isTracingActiveRCPNodes==true or not. This will not be a performance
537 // problem and it will ensure that any RCPNode objects that are added to
538 // this list will be removed and will not look like a memory leak. In
539 // non-debug mode, this function will never be called. In debug mode, with
540 // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and
541 // therefore this find(...) operation should be pretty cheap (even for a bad
542 // implementation of std::map).
543
544#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
545 // lock_guard will unlock in the event of an exception
546 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
547#endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
548
550
551 typedef rcp_node_list_t::iterator itr_t;
552 typedef std::pair<itr_t, itr_t> itr_itr_t;
553
554 const itr_itr_t itr_itr =
556 const bool rcp_node_exists = itr_itr.first != itr_itr.second;
557
558#ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING
559 // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a
560 // compile time, then all RCPNode objects that get created will have been
561 // added to this list. In this case, we can asset that the node exists.
562 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node);
563#else
564 // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is
565 // possible that an RCP got created before the bool
566 // loc_isTracingActiveRCPNodes was turned on. In this case, we must allow
567 // for an RCP node not to have been added to this list. In this case we
568 // will just let this go!
569#endif
570
571 if (rcp_node_exists) {
572#ifdef RCP_NODE_DEBUG_TRACE_PRINT
573 std::cerr
574 << "RCPNodeTracer::removeRCPNode(...): Removing "
575 << convertRCPNodeToString(rcp_node) << " ...\n";
576#endif
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;
582 foundRCPNode = true;
583 break;
584 }
585 }
586 // Whoops! Did not find the node!
587 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node);
588 }
589
590}
591
592
594{
595 typedef rcp_node_list_t::iterator itr_t;
596 typedef std::pair<itr_t, itr_t> itr_itr_t;
597 if (!p)
598 return 0;
599
600#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
601 // lock_guard will unlock in the event of an exception
602 std::lock_guard<std::mutex> lockGuard(*rcp_node_list_mutex());
603#endif // USE_MUTEX_TO_PROTECT_NODE_TRACING
604
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;
608 if (rcpNode->has_ownership()) {
609 return rcpNode;
610 }
611 }
612 return 0;
613 // NOTE: Above, we return the first RCPNode added that has the given key
614 // value.
615}
616
617
619{
620 return std::string(
621 "\n***"
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."
625 "\n***"
626 "\n*** There can be many possible reasons that this might occur including:"
627 "\n***"
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)."
633 "\n***"
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."
637 "\n***"
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."
640 "\n***\n"
641 );
642}
643
644
646{
647 return std::string(
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"
652 "\n"
653 "1) Open the debugger (GDB) and run the program again to get updated object addresses\n"
654 "\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"
657 "\n"
658 " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n"
659 " (gdb) cond 1 insertionNumber==3 [ENTER]\n"
660 "\n"
661 "3) Run the program in the debugger. In GDB, do:\n"
662 "\n"
663 " (gdb) run [ENTER]\n"
664 "\n"
665 "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n"
666 );
667}
668
669
670//
671// ActiveRCPNodesSetup
672//
673
674
676{
677#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
678 std::cerr << "\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ << "\n";
679#endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
680 if (!rcp_node_list())
682
683#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
684 if (!rcp_node_list_mutex()) {
685 rcp_node_list_mutex() = new std::mutex;
686 }
687#endif
688 ++count_;
689}
690
691
693{
694#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
695 std::cerr << "\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ << "\n";
696#endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
697 if( --count_ == 0 ) {
698#ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
699 std::cerr << "\nPrint active nodes!\n";
700#endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE
701 std::cout << std::flush;
702 TEUCHOS_TEST_FOR_TERMINATION(nullptr==rcp_node_list(), "rcp_node_list() is null in ~ActiveRCPNodesSetup");
705 if (rcpNodeStatistics.maxNumRCPNodes
707 {
709 }
712 }
713 delete rcp_node_list();
714 rcp_node_list() = 0;
715
716#ifdef USE_MUTEX_TO_PROTECT_NODE_TRACING
717 delete rcp_node_list_mutex();
719#endif
720 }
721}
722
723
725{
726 int dummy = count_;
727 ++dummy; // Avoid unused variable warning (bug 2664)
728}
729
730
731int Teuchos::ActiveRCPNodesSetup::count_ = 0;
732
733
734//
735// RCPNodeHandle
736//
737
738void RCPNodeHandle::unbindOneStrong()
739{
740#ifdef TEUCHOS_DEBUG
742#endif
743 // do this after removeRCPNode - otherwise another thread can jump in and grab
744 // the memory - then node tracing incorrectly thinks it's a double allocation
745 node_->delete_obj();
746}
747
748void RCPNodeHandle::unbindOneTotal()
749{
750 delete node_;
751 node_ = 0;
752}
753
754} // namespace Teuchos
755
756
757//
758// Non-member helpers
759//
760
761
762void Teuchos::throw_null_ptr_error( const std::string &type_name )
763{
765 true, NullReferenceError,
766 type_name << " : You can not call operator->() or operator*()"
767 <<" if getRawPtr()==0!" );
768}
769
770// Implement abort and exception handling for RCPNode
771// Note "PROGRAM ABORTING" text will be checked in a unit test and to
772// avoid having a more complex code here to ensure no mixed output, I kept that as 1 MPI.
773// if(!success) added to prevent DEBUG unused variable warning.
774#ifdef TEUCHOS_DEBUG
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();
781
782void Teuchos::abort_for_exception_in_destructor(const std::exception &exception) {
783 TEUCHOS_IMPLEMENT_ABORT(exception);
784}
785void Teuchos::abort_for_exception_in_destructor(const int &code) {
786 TEUCHOS_IMPLEMENT_ABORT(code);
787}
789 TEUCHOS_IMPLEMENT_ABORT(std::logic_error(
790 "Caught unknown exception from destructor of RCPNode. Aborting."););
791}
792#endif // TEUCHOS_DEBUG
Reference-counted pointer node classes.
Dangling reference error exception class.
Thrown if a duplicate owning RCP is creatd the the same object.
Smart reference counting pointer class for automatic garbage collection.
bool has_ownership() const
Returns true if this has ownership of object pointed to by this->get() in order to delete it.
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)
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,...