Line data Source code
1 : // The libMesh Finite Element Library. 2 : // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 3 : 4 : // This library is free software; you can redistribute it and/or 5 : // modify it under the terms of the GNU Lesser General Public 6 : // License as published by the Free Software Foundation; either 7 : // version 2.1 of the License, or (at your option) any later version. 8 : 9 : // This library is distributed in the hope that it will be useful, 10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 : // Lesser General Public License for more details. 13 : 14 : // You should have received a copy of the GNU Lesser General Public 15 : // License along with this library; if not, write to the Free Software 16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 : 18 : 19 : 20 : #ifndef LIBMESH_REFERENCE_COUNTER_H 21 : #define LIBMESH_REFERENCE_COUNTER_H 22 : 23 : // Local includes 24 : #include "libmesh/libmesh_config.h" 25 : #include "libmesh/threads.h" 26 : #include "libmesh/libmesh.h" // libMesh::on_command_line 27 : #include "libmesh/libmesh_exceptions.h" // libmesh_try, libmesh_catch 28 : 29 : // C++ includes 30 : #include <iostream> 31 : #include <string> 32 : #include <map> 33 : #include <exception> // std::terminate 34 : 35 : namespace libMesh 36 : { 37 : 38 : /** 39 : * This is the base class for enabling reference counting. It 40 : * should not be used by the user, thus it has a private constructor. 41 : * 42 : * \author Benjamin S. Kirk 43 : * \date 2002-2007 44 : * \brief Common base for all objects whose creations/destructions are counted. 45 : */ 46 : class ReferenceCounter 47 : { 48 : protected: 49 : 50 : /** 51 : * Constructors. Protected so that you cannot 52 : * instantiate a \p ReferenceCounter, only derive 53 : * from it. 54 : */ 55 : ReferenceCounter (); 56 : ReferenceCounter (const ReferenceCounter &); 57 : 58 : 59 : /** 60 : * Move constructor, must be declared noexcept. 61 : */ 62 : ReferenceCounter(ReferenceCounter && other) noexcept; 63 : 64 : public: 65 : 66 : /** 67 : * Destructor. 68 : */ 69 : ~ReferenceCounter (); 70 : 71 : /** 72 : * Gets a string containing the reference information. 73 : */ 74 : static std::string get_info (); 75 : 76 : /** 77 : * Prints the reference information, by default to \p libMesh::out. 78 : */ 79 : static void print_info (std::ostream & out_stream = libMesh::out); 80 : 81 : /** 82 : * Prints the number of outstanding (created, but not yet 83 : * destroyed) objects. 84 : */ 85 462 : static unsigned int n_objects () 86 462 : { return _n_objects; } 87 : 88 : /** 89 : * Methods to enable/disable the reference counter output 90 : * from print_info() 91 : */ 92 : static void enable_print_counter_info(); 93 : static void disable_print_counter_info(); 94 : 95 : 96 : protected: 97 : 98 : #if defined(LIBMESH_ENABLE_REFERENCE_COUNTING) && defined(DEBUG) 99 : 100 : /** 101 : * Increments the construction counter. Should be called in 102 : * the constructor of any derived class that will be 103 : * reference counted. 104 : */ 105 : void increment_constructor_count (const std::string & name) noexcept; 106 : 107 : /** 108 : * Increments the destruction counter. Should be called in 109 : * the destructor of any derived class that will be 110 : * reference counted. 111 : */ 112 : void increment_destructor_count (const std::string & name) noexcept; 113 : 114 : /** 115 : * Data structure to log the information. The log is 116 : * identified by the class name. 117 : */ 118 : typedef std::map<std::string, std::pair<unsigned int, 119 : unsigned int>> Counts; 120 : 121 : /** 122 : * Actually holds the data. 123 : */ 124 : static Counts _counts; 125 : 126 : #endif 127 : 128 : /** 129 : * The number of objects. Print the reference count 130 : * information when the number returns to 0. 131 : */ 132 : static Threads::atomic<unsigned int> _n_objects; 133 : 134 : /** 135 : * Mutual exclusion object to enable thread-safe reference counting. 136 : */ 137 : static Threads::spin_mutex _mutex; 138 : 139 : /** 140 : * Flag to control whether reference count information 141 : * is printed when print_info is called. 142 : */ 143 : static bool _enable_print_counter; 144 : }; 145 : 146 : 147 : 148 : // ------------------------------------------------------------ 149 : // ReferenceCounter class inline methods 150 880360428 : inline ReferenceCounter::ReferenceCounter() 151 : { 152 1566996938 : ++_n_objects; 153 880360428 : } 154 : 155 : 156 : 157 1024 : inline ReferenceCounter::ReferenceCounter(const ReferenceCounter & /*other*/) 158 : { 159 29944 : ++_n_objects; 160 1024 : } 161 : 162 : 163 : 164 : inline ReferenceCounter::ReferenceCounter(ReferenceCounter && /*other*/) noexcept 165 : { 166 : ++_n_objects; 167 : } 168 : 169 : 170 : 171 190901715 : inline ReferenceCounter::~ReferenceCounter() 172 : { 173 4632454354 : --_n_objects; 174 190901715 : } 175 : 176 : 177 : 178 : 179 : 180 : 181 : #if defined(LIBMESH_ENABLE_REFERENCE_COUNTING) && defined(DEBUG) 182 : inline 183 42729276 : void ReferenceCounter::increment_constructor_count (const std::string & name) noexcept 184 : { 185 : libmesh_try 186 : { 187 42729276 : Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 188 42729276 : std::pair<unsigned int, unsigned int> & p = _counts[name]; 189 42729276 : p.first++; 190 : } 191 0 : libmesh_catch (...) 192 : { 193 0 : auto stream = libMesh::err.get(); 194 0 : stream->exceptions(stream->goodbit); // stream must not throw 195 0 : libMesh::err << "Encountered unrecoverable error while calling " 196 0 : << "ReferenceCounter::increment_constructor_count() " 197 0 : << "for a(n) " << name << " object." << std::endl; 198 0 : std::terminate(); 199 : } 200 42729276 : } 201 : #endif 202 : 203 : 204 : 205 : #if defined(LIBMESH_ENABLE_REFERENCE_COUNTING) && defined(DEBUG) 206 : inline 207 12207561 : void ReferenceCounter::increment_destructor_count (const std::string & name) noexcept 208 : { 209 : libmesh_try 210 : { 211 12207561 : Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx); 212 12207561 : std::pair<unsigned int, unsigned int> & p = _counts[name]; 213 12207561 : p.second++; 214 : } 215 0 : libmesh_catch (...) 216 : { 217 0 : auto stream = libMesh::err.get(); 218 0 : stream->exceptions(stream->goodbit); // stream must not throw 219 0 : libMesh::err << "Encountered unrecoverable error while calling " 220 0 : << "ReferenceCounter::increment_destructor_count() " 221 0 : << "for a(n) " << name << " object." << std::endl; 222 0 : std::terminate(); 223 : } 224 12207561 : } 225 : #endif 226 : 227 : 228 : } // namespace libMesh 229 : 230 : 231 : #endif // LIBMESH_REFERENCE_COUNTER_H