Teuchos Package Browser (Single Doxygen Collection) Version of the Day
Loading...
Searching...
No Matches
Teuchos_RCPNode.cpp
Go to the documentation of this file.
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"
45#include <vector>
46
47#ifdef TEUCHOS_DEBUG
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
64namespace {
65
66
67//
68// Local implementation types
69//
70
71
72struct 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
82typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t;
83
84
85typedef 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
104rcp_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
118std::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
127bool& 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
140Teuchos::RCPNodeTracer::RCPNodeStatistics& loc_rcpNodeStatistics()
141{
142 static Teuchos::RCPNodeTracer::RCPNodeStatistics s_loc_rcpNodeStatistics;
143 return s_loc_rcpNodeStatistics;
144}
145
146
147bool& loc_printRCPNodeStatisticsOnExit()
148{
149 static bool s_loc_printRCPNodeStatisticsOnExit = false;
150 return s_loc_printRCPNodeStatisticsOnExit;
151}
152
153
154bool& 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.
172const 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
184std::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
207namespace 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{
222 if(extra_data_map_==NULL) {
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
245any& 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
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
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
304
305
306#if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING)
307void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes)
308{
310}
311#endif
312
313
315{
316 // This list always exists, no matter debug or not so just access it.
318 return static_cast<int>(rcp_node_list()->size());
319}
320
321
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
347
348
353
354
359
360
365
366
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
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;
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
422void 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
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
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;
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()) {
463 break;
464 }
465 }
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.
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
502 ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations;
503 loc_rcpNodeStatistics().maxNumRCPNodes =
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
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 =
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.
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!
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())
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");
691 if (rcpNodeStatistics.maxNumRCPNodes
693 {
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();
705#endif
706 }
707}
708
709
711{
712 int dummy = count_;
713 ++dummy; // Avoid unused variable warning (bug 2664)
714}
715
716
718
719
720//
721// RCPNodeHandle
722//
723
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
735{
736 delete node_;
737 node_ = 0;
738}
739
740} // namespace Teuchos
741
742
743//
744// Non-member helpers
745//
746
747
748void 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
768void Teuchos::abort_for_exception_in_destructor(const std::exception &exception) {
769 TEUCHOS_IMPLEMENT_ABORT(exception);
770}
771void Teuchos::abort_for_exception_in_destructor(const int &code) {
772 TEUCHOS_IMPLEMENT_ABORT(code);
773}
775 TEUCHOS_IMPLEMENT_ABORT(std::logic_error(
776 "Caught unknown exception from destructor of RCPNode. Aborting."););
777}
778#endif // TEUCHOS_DEBUG
#define TEUCHOS_MAX(x, y)
#define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE)
Reference-counted pointer node classes.
int size(const Comm< Ordinal > &comm)
Get the number of processes in the communicator.
Thrown if a duplicate owning RCP is creatd the the same object.
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.
Node class to keep track of address and the reference count for a reference-counted utility class and...
Teuchos::map< std::string, extra_data_entry_t > extra_data_map_t
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)
extra_data_map_t * extra_data_map_
Concrete serial communicator subclass.
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(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.