|
Teuchos - Trilinos Tools Package
Version of the Day
|
00001 // @HEADER 00002 // *********************************************************************** 00003 // 00004 // Teuchos: Common Tools Package 00005 // Copyright (2004) Sandia Corporation 00006 // 00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive 00008 // license for use of this work by or on behalf of the U.S. Government. 00009 // 00010 // Redistribution and use in source and binary forms, with or without 00011 // modification, are permitted provided that the following conditions are 00012 // met: 00013 // 00014 // 1. Redistributions of source code must retain the above copyright 00015 // notice, this list of conditions and the following disclaimer. 00016 // 00017 // 2. Redistributions in binary form must reproduce the above copyright 00018 // notice, this list of conditions and the following disclaimer in the 00019 // documentation and/or other materials provided with the distribution. 00020 // 00021 // 3. Neither the name of the Corporation nor the names of the 00022 // contributors may be used to endorse or promote products derived from 00023 // this software without specific prior written permission. 00024 // 00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY 00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE 00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00036 // 00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov) 00038 // 00039 // *********************************************************************** 00040 // @HEADER 00041 00042 #include "Teuchos_RCPNode.hpp" 00043 #include "Teuchos_Assert.hpp" 00044 #include "Teuchos_Exceptions.hpp" 00045 00046 00047 // Defined this to see tracing of RCPNodes created and destroyed 00048 //#define RCP_NODE_DEBUG_TRACE_PRINT 00049 00050 00051 // 00052 // Internal implementatation stuff 00053 // 00054 00055 00056 namespace { 00057 00058 00059 // 00060 // Local implementation types 00061 // 00062 00063 00064 struct RCPNodeInfo { 00065 RCPNodeInfo() : nodePtr(0) {} 00066 RCPNodeInfo(const std::string &info_in, Teuchos::RCPNode* nodePtr_in) 00067 : info(info_in), nodePtr(nodePtr_in) 00068 {} 00069 std::string info; 00070 Teuchos::RCPNode* nodePtr; 00071 }; 00072 00073 00074 typedef std::pair<const void*, RCPNodeInfo> VoidPtrNodeRCPInfoPair_t; 00075 00076 00077 typedef std::multimap<const void*, RCPNodeInfo> rcp_node_list_t; 00078 00079 00080 class RCPNodeInfoListPred { 00081 public: 00082 bool operator()(const rcp_node_list_t::value_type &v1, 00083 const rcp_node_list_t::value_type &v2 00084 ) const 00085 { 00086 #ifdef TEUCHOS_DEBUG 00087 return v1.second.nodePtr->insertion_number() < v2.second.nodePtr->insertion_number(); 00088 #else 00089 return v1.first < v2.first; 00090 #endif 00091 } 00092 }; 00093 00094 00095 // 00096 // Local static functions returning references to local static objects to 00097 // ensure objects are initilaized. 00098 // 00099 // Technically speaking, the static functions on RCPNodeTracer that use this 00100 // data might be called from other translation units in pre-main code before 00101 // this translation unit gets initialized. By using functions returning 00102 // references to local static variable trick, we ensure that these objects are 00103 // always initialized before they are used, no matter what. 00104 // 00105 // These could have been static functions on RCPNodeTracer but the advantage 00106 // of defining these functions this way is that you can add and remove 00107 // functions without affecting the *.hpp file and therefore avoid 00108 // recompilation (and even relinking with shared libraries). 00109 // 00110 00111 00112 rcp_node_list_t*& rcp_node_list() 00113 { 00114 static rcp_node_list_t *s_rcp_node_list = 0; 00115 // Here we must let the ActiveRCPNodesSetup constructor and destructor handle 00116 // the creation and destruction of this map object. This will ensure that 00117 // this map object will be valid when any global/static RCP objects are 00118 // destroyed! Note that this object will get created and destroyed 00119 // reguardless if whether we are tracing RCPNodes or not. This just makes our 00120 // life simpler. NOTE: This list will always get allocated no mater if 00121 // TEUCHOS_DEBUG is defined or node traceing is enabled or not. 00122 return s_rcp_node_list; 00123 } 00124 00125 00126 bool& loc_isTracingActiveRCPNodes() 00127 { 00128 static bool s_loc_isTracingActiveRCPNodes = 00129 #if defined(TEUCHOS_DEBUG) && defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 00130 true 00131 #else 00132 false 00133 #endif 00134 ; 00135 return s_loc_isTracingActiveRCPNodes; 00136 } 00137 00138 00139 Teuchos::RCPNodeTracer::RCPNodeStatistics& loc_rcpNodeStatistics() 00140 { 00141 static Teuchos::RCPNodeTracer::RCPNodeStatistics s_loc_rcpNodeStatistics; 00142 return s_loc_rcpNodeStatistics; 00143 } 00144 00145 00146 bool& loc_printRCPNodeStatisticsOnExit() 00147 { 00148 static bool s_loc_printRCPNodeStatisticsOnExit = false; 00149 return s_loc_printRCPNodeStatisticsOnExit; 00150 } 00151 00152 00153 // 00154 // Other helper functions 00155 // 00156 00157 // This function returns the const void* value that is used as the key to look 00158 // up an RCPNode object that has been stored. If the RCPNode is holding a 00159 // non-null reference, then we use that object address as the key. That way, 00160 // we can detect if a user trys to create a new owning RCPNode to the same 00161 // object. If the RCPNode has an null internal object pointer, then we will 00162 // use the RCPNode's address itself. In this case, we want to check and see 00163 // that all RCPNodes that get created get destroyed correctly. 00164 const void* get_map_key_void_ptr(const Teuchos::RCPNode* rcp_node) 00165 { 00166 TEUCHOS_ASSERT(rcp_node); 00167 #ifdef TEUCHOS_DEBUG 00168 const void* base_obj_map_key_void_ptr = rcp_node->get_base_obj_map_key_void_ptr(); 00169 if (base_obj_map_key_void_ptr) 00170 return base_obj_map_key_void_ptr; 00171 #endif 00172 return rcp_node; 00173 } 00174 00175 00176 std::string convertRCPNodeToString(const Teuchos::RCPNode* rcp_node) 00177 { 00178 std::ostringstream oss; 00179 oss 00180 << "RCPNode {address=" 00181 << rcp_node 00182 #ifdef TEUCHOS_DEBUG 00183 << ", base_obj_map_key_void_ptr=" << rcp_node->get_base_obj_map_key_void_ptr() 00184 #endif 00185 << ", base_obj_type_name=" << rcp_node->get_base_obj_type_name() 00186 << ", map_key_void_ptr=" << get_map_key_void_ptr(rcp_node) 00187 << ", has_ownership=" << rcp_node->has_ownership() 00188 #ifdef TEUCHOS_DEBUG 00189 << ", insertionNumber="<< rcp_node->insertion_number() 00190 #endif 00191 << "}"; 00192 return oss.str(); 00193 } 00194 00195 00196 } // namespace 00197 00198 00199 namespace Teuchos { 00200 00201 00202 // 00203 // RCPNode 00204 // 00205 00206 00207 void RCPNode::set_extra_data( 00208 const any &extra_data, const std::string& name 00209 ,EPrePostDestruction destroy_when 00210 ,bool force_unique 00211 ) 00212 { 00213 if(extra_data_map_==NULL) { 00214 extra_data_map_ = new extra_data_map_t; 00215 } 00216 const std::string type_and_name( extra_data.typeName() + std::string(":") + name ); 00217 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name); 00218 #ifdef TEUCHOS_DEBUG 00219 TEUCHOS_TEST_FOR_EXCEPTION( 00220 (itr != extra_data_map_->end() && force_unique), std::invalid_argument 00221 ,"Error, the type:name pair \'" << type_and_name 00222 << "\' already exists and force_unique==true!" ); 00223 #endif 00224 if (itr != extra_data_map_->end()) { 00225 // Change existing extra data 00226 itr->second = extra_data_entry_t(extra_data,destroy_when); 00227 } 00228 else { 00229 // Insert new extra data 00230 (*extra_data_map_)[type_and_name] = 00231 extra_data_entry_t(extra_data,destroy_when); 00232 } 00233 } 00234 00235 00236 any& RCPNode::get_extra_data( const std::string& type_name, const std::string& name ) 00237 { 00238 #ifdef TEUCHOS_DEBUG 00239 TEUCHOS_TEST_FOR_EXCEPTION( 00240 extra_data_map_==NULL, std::invalid_argument 00241 ,"Error, no extra data has been set yet!" ); 00242 #endif 00243 any *extra_data = get_optional_extra_data(type_name,name); 00244 #ifdef TEUCHOS_DEBUG 00245 if (!extra_data) { 00246 const std::string type_and_name( type_name + std::string(":") + name ); 00247 TEUCHOS_TEST_FOR_EXCEPTION( 00248 extra_data == NULL, std::invalid_argument 00249 ,"Error, the type:name pair \'" << type_and_name << "\' is not found!" ); 00250 } 00251 #endif 00252 return *extra_data; 00253 } 00254 00255 00256 any* RCPNode::get_optional_extra_data( const std::string& type_name, 00257 const std::string& name ) 00258 { 00259 if( extra_data_map_ == NULL ) return NULL; 00260 const std::string type_and_name( type_name + std::string(":") + name ); 00261 extra_data_map_t::iterator itr = extra_data_map_->find(type_and_name); 00262 if(itr != extra_data_map_->end()) 00263 return &(*itr).second.extra_data; 00264 return NULL; 00265 } 00266 00267 00268 void RCPNode::impl_pre_delete_extra_data() 00269 { 00270 for( 00271 extra_data_map_t::iterator itr = extra_data_map_->begin(); 00272 itr != extra_data_map_->end(); 00273 ++itr 00274 ) 00275 { 00276 extra_data_map_t::value_type &entry = *itr; 00277 if(entry.second.destroy_when == PRE_DESTROY) 00278 entry.second.extra_data = any(); 00279 } 00280 } 00281 00282 00283 // 00284 // RCPNodeTracer 00285 // 00286 00287 00288 // General user functions 00289 00290 00291 bool RCPNodeTracer::isTracingActiveRCPNodes() 00292 { 00293 return loc_isTracingActiveRCPNodes(); 00294 } 00295 00296 00297 #if defined(TEUCHOS_DEBUG) && !defined(HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING) 00298 void RCPNodeTracer::setTracingActiveRCPNodes(bool tracingActiveNodes) 00299 { 00300 loc_isTracingActiveRCPNodes() = tracingActiveNodes; 00301 } 00302 #endif 00303 00304 00305 int RCPNodeTracer::numActiveRCPNodes() 00306 { 00307 // This list always exists, no matter debug or not so just access it. 00308 TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list()); 00309 return rcp_node_list()->size(); 00310 return 0; 00311 } 00312 00313 00314 RCPNodeTracer::RCPNodeStatistics 00315 RCPNodeTracer::getRCPNodeStatistics() 00316 { 00317 return loc_rcpNodeStatistics(); 00318 } 00319 00320 void RCPNodeTracer::printRCPNodeStatistics( 00321 const RCPNodeStatistics& rcpNodeStatistics, std::ostream &out) 00322 { 00323 out 00324 << "\n***" 00325 << "\n*** RCPNode Tracing statistics:" 00326 << "\n**\n" 00327 << "\n maxNumRCPNodes = "<<rcpNodeStatistics.maxNumRCPNodes 00328 << "\n totalNumRCPNodeAllocations = "<<rcpNodeStatistics.totalNumRCPNodeAllocations 00329 << "\n totalNumRCPNodeDeletions = "<<rcpNodeStatistics.totalNumRCPNodeDeletions 00330 << "\n"; 00331 } 00332 00333 00334 void RCPNodeTracer::setPrintRCPNodeStatisticsOnExit( 00335 bool printRCPNodeStatisticsOnExit) 00336 { 00337 loc_printRCPNodeStatisticsOnExit() = printRCPNodeStatisticsOnExit; 00338 } 00339 00340 00341 bool RCPNodeTracer::getPrintRCPNodeStatisticsOnExit() 00342 { 00343 return loc_printRCPNodeStatisticsOnExit(); 00344 } 00345 00346 00347 void RCPNodeTracer::printActiveRCPNodes(std::ostream &out) 00348 { 00349 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 00350 out 00351 << "\nCalled printActiveRCPNodes() :" 00352 << " rcp_node_list.size() = " << rcp_node_list().size() << "\n"; 00353 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 00354 if (loc_isTracingActiveRCPNodes()) { 00355 TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list()); 00356 if (rcp_node_list()->size() > 0) { 00357 out << getActiveRCPNodeHeaderString(); 00358 // Create a sorted-by-insertionNumber list 00359 // NOTE: You have to use std::vector and *not* Teuchos::Array rcp here 00360 // because this called at the very end and uses RCPNode itself in a 00361 // debug-mode build. 00362 typedef std::vector<VoidPtrNodeRCPInfoPair_t> rcp_node_vec_t; 00363 rcp_node_vec_t rcp_node_vec(rcp_node_list()->begin(), rcp_node_list()->end()); 00364 std::sort(rcp_node_vec.begin(), rcp_node_vec.end(), RCPNodeInfoListPred()); 00365 // Print the RCPNode objects sorted by insertion number 00366 typedef rcp_node_vec_t::const_iterator itr_t; 00367 int i = 0; 00368 for ( itr_t itr = rcp_node_vec.begin(); itr != rcp_node_vec.end(); ++itr ) { 00369 const rcp_node_list_t::value_type &entry = *itr; 00370 TEUCHOS_ASSERT(entry.second.nodePtr); 00371 out 00372 << "\n" 00373 << std::setw(3) << std::right << i << std::left 00374 << ": RCPNode (map_key_void_ptr=" << entry.first << ")\n" 00375 << " Information = " << entry.second.info << "\n" 00376 << " RCPNode address = " << entry.second.nodePtr << "\n" 00377 #ifdef TEUCHOS_DEBUG 00378 << " insertionNumber = " << entry.second.nodePtr->insertion_number() 00379 #endif 00380 ; 00381 ++i; 00382 } 00383 out << "\n\n" 00384 << getCommonDebugNotesString(); 00385 } 00386 } 00387 } 00388 00389 00390 // Internal implementation functions 00391 00392 00393 void RCPNodeTracer::addNewRCPNode( RCPNode* rcp_node, const std::string &info ) 00394 { 00395 00396 // Used to allow unique identification of rcp_node to allow setting breakpoints 00397 static int insertionNumber = 0; 00398 00399 // Set the insertion number right away in case an exception gets thrown so 00400 // that you can set a break point to debug this. 00401 #ifdef TEUCHOS_DEBUG 00402 rcp_node->set_insertion_number(insertionNumber); 00403 #endif 00404 00405 if (loc_isTracingActiveRCPNodes()) { 00406 00407 // Print the node we are adding if configured to do so. We have to send 00408 // to std::cerr to make sure that this gets printed. 00409 #ifdef RCP_NODE_DEBUG_TRACE_PRINT 00410 std::cerr 00411 << "RCPNodeTracer::addNewRCPNode(...): Adding " 00412 << convertRCPNodeToString(rcp_node) << " ...\n"; 00413 #endif 00414 00415 TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list()); 00416 00417 const void * const map_key_void_ptr = get_map_key_void_ptr(rcp_node); 00418 00419 // See if the rcp_node or its object has already been added. 00420 typedef rcp_node_list_t::iterator itr_t; 00421 typedef std::pair<itr_t, itr_t> itr_itr_t; 00422 const itr_itr_t itr_itr = rcp_node_list()->equal_range(map_key_void_ptr); 00423 const bool rcp_node_already_exists = itr_itr.first != itr_itr.second; 00424 RCPNode *previous_rcp_node = 0; 00425 bool previous_rcp_node_has_ownership = false; 00426 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) { 00427 previous_rcp_node = itr->second.nodePtr; 00428 if (previous_rcp_node->has_ownership()) { 00429 previous_rcp_node_has_ownership = true; 00430 break; 00431 } 00432 } 00433 TEUCHOS_TEST_FOR_EXCEPTION( 00434 rcp_node_already_exists && rcp_node->has_ownership() && previous_rcp_node_has_ownership, 00435 DuplicateOwningRCPError, 00436 "RCPNodeTracer::addNewRCPNode(rcp_node): Error, the client is trying to create a new\n" 00437 "RCPNode object to an existing managed object in another RCPNode:\n" 00438 "\n" 00439 " New " << convertRCPNodeToString(rcp_node) << "\n" 00440 "\n" 00441 " Existing " << convertRCPNodeToString(previous_rcp_node) << "\n" 00442 "\n" 00443 " Number current nodes = " << rcp_node_list()->size() << "\n" 00444 "\n" 00445 "This may indicate that the user might be trying to create a weak RCP to an existing\n" 00446 "object but forgot make it non-ownning. Perhaps they meant to use rcpFromRef(...)\n" 00447 "or an equivalent function?\n" 00448 "\n" 00449 << getCommonDebugNotesString(); 00450 ); 00451 00452 // NOTE: We allow duplicate RCPNodes if the new node is non-owning. This 00453 // might indicate a advanced usage of the RCP class that we want to 00454 // support. The typical problem is when the programmer unknowingly 00455 // creates an owning RCP to an object already owned by another RCPNode. 00456 00457 // Add the new RCP node keyed as described above. 00458 (*rcp_node_list()).insert( 00459 itr_itr.second, 00460 std::make_pair(map_key_void_ptr, RCPNodeInfo(info, rcp_node)) 00461 ); 00462 // NOTE: Above, if there is already an existing RCPNode with the same key 00463 // value, this iterator itr_itr.second will point to one after the found 00464 // range. I suspect that this might also ensure that the elements are 00465 // sorted in natural order. 00466 00467 // Update the insertion number an node tracing statistics 00468 ++insertionNumber; 00469 ++loc_rcpNodeStatistics().totalNumRCPNodeAllocations; 00470 loc_rcpNodeStatistics().maxNumRCPNodes = 00471 TEUCHOS_MAX(loc_rcpNodeStatistics().maxNumRCPNodes, numActiveRCPNodes()); 00472 } 00473 } 00474 00475 00476 #define TEUCHOS_RCPNODE_REMOVE_RCPNODE(CONDITION, RCPNODE) \ 00477 TEUCHOS_TEST_FOR_EXCEPTION((CONDITION), \ 00478 std::logic_error, \ 00479 "RCPNodeTracer::removeRCPNode(node_ptr): Error, the " \ 00480 << convertRCPNodeToString(RCPNODE) << " is not found in the list of" \ 00481 " active RCP nodes being traced even though all nodes should be traced." \ 00482 " This should not be possible and can only be an internal programming error!") 00483 00484 00485 void RCPNodeTracer::removeRCPNode( RCPNode* rcp_node ) 00486 { 00487 00488 // Here, we will try to remove an RCPNode reguardless if whether 00489 // loc_isTracingActiveRCPNodes==true or not. This will not be a performance 00490 // problem and it will ensure that any RCPNode objects that are added to 00491 // this list will be removed and will not look like a memory leak. In 00492 // non-debug mode, this function will never be called. In debug mode, with 00493 // loc_isTracingActiveRCPNodes==false, the list *rcp_node_list will be empty and 00494 // therefore this find(...) operation should be pretty cheap (even for a bad 00495 // implementation of std::map). 00496 00497 TEUCHOS_ASSERT(rcp_node_list()); 00498 typedef rcp_node_list_t::iterator itr_t; 00499 typedef std::pair<itr_t, itr_t> itr_itr_t; 00500 00501 const itr_itr_t itr_itr = 00502 rcp_node_list()->equal_range(get_map_key_void_ptr(rcp_node)); 00503 const bool rcp_node_exists = itr_itr.first != itr_itr.second; 00504 00505 #ifdef HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING 00506 // If we have the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned on a 00507 // compile time, then all RCPNode objects that get created will have been 00508 // added to this list. In this case, we can asset that the node exists. 00509 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!rcp_node_exists, rcp_node); 00510 #else 00511 // If the macro HAVE_TEUCHOS_DEBUG_RCP_NODE_TRACING turned off, then is is 00512 // possible that an RCP got created before the bool 00513 // loc_isTracingActiveRCPNodes was turned on. In this case, we must allow 00514 // for an RCP node not to have been added to this list. In this case we 00515 // will just let this go! 00516 #endif 00517 00518 if (rcp_node_exists) { 00519 #ifdef RCP_NODE_DEBUG_TRACE_PRINT 00520 std::cerr 00521 << "RCPNodeTracer::removeRCPNode(...): Removing " 00522 << convertRCPNodeToString(rcp_node) << " ...\n"; 00523 #endif 00524 bool foundRCPNode = false; 00525 for(itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) { 00526 if (itr->second.nodePtr == rcp_node) { 00527 rcp_node_list()->erase(itr); 00528 ++loc_rcpNodeStatistics().totalNumRCPNodeDeletions; 00529 foundRCPNode = true; 00530 break; 00531 } 00532 } 00533 // Whoops! Did not find the node! 00534 TEUCHOS_RCPNODE_REMOVE_RCPNODE(!foundRCPNode, rcp_node); 00535 } 00536 00537 } 00538 00539 00540 RCPNode* RCPNodeTracer::getExistingRCPNodeGivenLookupKey(const void* p) 00541 { 00542 typedef rcp_node_list_t::iterator itr_t; 00543 typedef std::pair<itr_t, itr_t> itr_itr_t; 00544 if (!p) 00545 return 0; 00546 const itr_itr_t itr_itr = rcp_node_list()->equal_range(p); 00547 for (itr_t itr = itr_itr.first; itr != itr_itr.second; ++itr) { 00548 RCPNode* rcpNode = itr->second.nodePtr; 00549 if (rcpNode->has_ownership()) { 00550 return rcpNode; 00551 } 00552 } 00553 return 0; 00554 // NOTE: Above, we return the first RCPNode added that has the given key 00555 // value. 00556 } 00557 00558 00559 std::string RCPNodeTracer::getActiveRCPNodeHeaderString() 00560 { 00561 return std::string( 00562 "\n***" 00563 "\n*** Warning! The following Teuchos::RCPNode objects were created but have" 00564 "\n*** not been destroyed yet. A memory checking tool may complain that these" 00565 "\n*** objects are not destroyed correctly." 00566 "\n***" 00567 "\n*** There can be many possible reasons that this might occur including:" 00568 "\n***" 00569 "\n*** a) The program called abort() or exit() before main() was finished." 00570 "\n*** All of the objects that would have been freed through destructors" 00571 "\n*** are not freed but some compilers (e.g. GCC) will still call the" 00572 "\n*** destructors on static objects (which is what causes this message" 00573 "\n*** to be printed)." 00574 "\n***" 00575 "\n*** b) The program is using raw new/delete to manage some objects and" 00576 "\n*** delete was not called correctly and the objects not deleted hold" 00577 "\n*** other objects through reference-counted pointers." 00578 "\n***" 00579 "\n*** c) This may be an indication that these objects may be involved in" 00580 "\n*** a circular dependency of reference-counted managed objects." 00581 "\n***\n" 00582 ); 00583 } 00584 00585 00586 std::string RCPNodeTracer::getCommonDebugNotesString() 00587 { 00588 return std::string( 00589 "NOTE: To debug issues, open a debugger, and set a break point in the function where\n" 00590 "the RCPNode object is first created to determine the context where the object first\n" 00591 "gets created. Each RCPNode object is given a unique insertionNumber to allow setting\n" 00592 "breakpoints in the code. For example, in GDB one can perform:\n" 00593 "\n" 00594 "1) Open the debugger (GDB) and run the program again to get updated object addresses\n" 00595 "\n" 00596 "2) Set a breakpoint in the RCPNode insertion routine when the desired RCPNode is first\n" 00597 "inserted. In GDB, to break when the RCPNode with insertionNumber==3 is added, do:\n" 00598 "\n" 00599 " (gdb) b 'Teuchos::RCPNodeTracer::addNewRCPNode( [TAB] ' [ENTER]\n" 00600 " (gdb) cond 1 insertionNumber==3 [ENTER]\n" 00601 "\n" 00602 "3) Run the program in the debugger. In GDB, do:\n" 00603 "\n" 00604 " (gdb) run [ENTER]\n" 00605 "\n" 00606 "4) Examine the call stack when the program breaks in the function addNewRCPNode(...)\n" 00607 ); 00608 } 00609 00610 00611 // 00612 // ActiveRCPNodesSetup 00613 // 00614 00615 00616 ActiveRCPNodesSetup::ActiveRCPNodesSetup() 00617 { 00618 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 00619 std::cerr << "\nCalled ActiveRCPNodesSetup::ActiveRCPNodesSetup() : count = " << count_ << "\n"; 00620 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 00621 if (!rcp_node_list()) 00622 rcp_node_list() = new rcp_node_list_t; 00623 ++count_; 00624 } 00625 00626 00627 ActiveRCPNodesSetup::~ActiveRCPNodesSetup() 00628 { 00629 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 00630 std::cerr << "\nCalled ActiveRCPNodesSetup::~ActiveRCPNodesSetup() : count = " << count_ << "\n"; 00631 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 00632 if( --count_ == 0 ) { 00633 #ifdef TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 00634 std::cerr << "\nPrint active nodes!\n"; 00635 #endif // TEUCHOS_SHOW_ACTIVE_REFCOUNTPTR_NODE_TRACE 00636 std::cout << std::flush; 00637 TEUCHOS_TEST_FOR_EXCEPT(0==rcp_node_list()); 00638 RCPNodeTracer::RCPNodeStatistics rcpNodeStatistics = 00639 RCPNodeTracer::getRCPNodeStatistics(); 00640 if (rcpNodeStatistics.maxNumRCPNodes 00641 && RCPNodeTracer::getPrintRCPNodeStatisticsOnExit()) 00642 { 00643 RCPNodeTracer::printRCPNodeStatistics(rcpNodeStatistics, std::cout); 00644 } 00645 RCPNodeTracer::printActiveRCPNodes(std::cerr); 00646 delete rcp_node_list(); 00647 rcp_node_list() = 0; 00648 } 00649 } 00650 00651 00652 void Teuchos::ActiveRCPNodesSetup::foo() 00653 { 00654 int dummy = count_; 00655 ++dummy; // Avoid unused variable warning (bug 2664) 00656 } 00657 00658 00659 int Teuchos::ActiveRCPNodesSetup::count_ = 0; 00660 00661 00662 // 00663 // RCPNodeHandle 00664 // 00665 00666 00667 void RCPNodeHandle::unbindOne() 00668 { 00669 if (node_) { 00670 // NOTE: We only deincrement the reference count after 00671 // we have called delete on the underlying object since 00672 // that call to delete may actually thrown an exception! 00673 if (node_->strong_count()==1 && strength()==RCP_STRONG) { 00674 // Delete the object (which might throw) 00675 node_->delete_obj(); 00676 #ifdef TEUCHOS_DEBUG 00677 // We actaully also need to remove the RCPNode from the active list for 00678 // some specialized use cases that need to be able to create a new RCP 00679 // node pointing to the same memory. What this means is that when the 00680 // strong count goes to zero and the referenced object is destroyed, 00681 // then it will not longer be picked up by any other code and instead it 00682 // will only be known by its remaining weak RCPNodeHandle objects in 00683 // order to perform debug-mode runtime checking in case a client tries 00684 // to access the obejct. 00685 local_activeRCPNodesSetup.foo(); // Make sure created! 00686 RCPNodeTracer::removeRCPNode(node_); 00687 #endif 00688 } 00689 // If we get here, no exception was thrown! 00690 if ( (node_->strong_count() + node_->weak_count()) == 1 ) { 00691 // The last RCP object is going away so time to delete 00692 // the entire node! 00693 delete node_; 00694 node_ = 0; 00695 // NOTE: No need to deincrement the reference count since this is 00696 // the last RCP object being deleted! 00697 } 00698 else { 00699 // The last RCP has not gone away so just deincrement the reference 00700 // count. 00701 node_->deincr_count(strength()); 00702 } 00703 } 00704 } 00705 00706 00707 } // namespace Teuchos 00708 00709 00710 // 00711 // Non-member helpers 00712 // 00713 00714 00715 void Teuchos::throw_null_ptr_error( const std::string &type_name ) 00716 { 00717 TEUCHOS_TEST_FOR_EXCEPTION( 00718 true, NullReferenceError, 00719 type_name << " : You can not call operator->() or operator*()" 00720 <<" if getRawPtr()==0!" ); 00721 }
1.7.6.1