lsst.daf.base  13.0-4-g2dbbef6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Citizen.cc
Go to the documentation of this file.
1 // -*- LSST-C++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
27 
28 #include <ctype.h>
29 
30 #include <cerrno>
31 #include <iostream>
32 #include <memory>
33 
34 #include <boost/format.hpp>
35 
36 #include "lsst/daf/base/Citizen.h"
37 #include "lsst/pex/exceptions.h"
38 #include "lsst/utils/Demangle.h"
39 
40 namespace dafBase = lsst::daf::base;
41 
42 namespace {
43 
44 template <typename T>
45 class ThreadPrivate {
46 public:
47  ThreadPrivate(T const& t) : _init(t) {
48  int ret = pthread_key_create(&_key, del);
49  if (ret != 0) {
50  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
51  "Could not create key");
52  }
53  };
54  T& getRef(void) {
55  T* d = reinterpret_cast<T*>(pthread_getspecific(_key));
56  if (d == 0) {
57  d = new T(_init);
58  pthread_setspecific(_key, d);
59  }
60  return *d;
61  };
62 
63 private:
64  pthread_key_t _key;
65  T _init;
66 
67  static void del(void* data) {
68  T* d = reinterpret_cast<T*>(data);
69  delete d;
70  };
71 };
72 
73 static ThreadPrivate<dafBase::Citizen::memId> perThreadId(1);
74 static ThreadPrivate<bool> perThreadPersistFlag(false);
75 
76 class RwLock {
77 public:
78  RwLock(void) {
79  int ret = pthread_rwlock_init(&_lock, 0);
80  if (ret != 0) {
81  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
82  "Could not create Citizen lock");
83  }
84  };
85  void lock(void) {
86  int ret = pthread_rwlock_wrlock(&_lock);
87  if (ret != 0) {
88  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
89  "Could not acquire Citizen write lock");
90  }
91  };
92  bool rdlock(void) {
93  int ret = pthread_rwlock_rdlock(&_lock);
94  if (ret == 0) return true;
95  if (ret == EDEADLK) return false;
96  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
97  "Could not acquire Citizen read lock");
98  };
99  void unlock(void) {
100  int ret = pthread_rwlock_unlock(&_lock);
101  if (ret != 0) {
102  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
103  "Could not release Citizen lock");
104  }
105  };
106 
107 private:
108  pthread_rwlock_t _lock;
109 };
110 
111 static RwLock citizenLock;
112 
113 class ReadGuard {
114 public:
115  ReadGuard(RwLock& lock) : _lock(lock) {
116  _mustUnlock = _lock.rdlock();
117  };
118  ~ReadGuard(void) {
119  if (_mustUnlock) _lock.unlock();
120  };
121 
122 private:
123  RwLock& _lock;
124  bool _mustUnlock;
125 };
126 
127 class WriteGuard {
128 public:
129  WriteGuard(RwLock& lock) : _lock(lock) {
130  _lock.lock();
131  };
132  ~WriteGuard(void) {
133  _lock.unlock();
134  };
135 
136 private:
137  RwLock& _lock;
138 };
139 
140 } // anonymous namespace
141 
143 //
144 // \brief A class that is instantiated once during startup
145 //
146 // The main purpose of CitizenInit is to provide a place to set
147 // breakpoints to setup memory debugging; see discussion on trac
148 //
149 class CitizenInit {
150 public:
151  CitizenInit() : _dummy(1) { }
152 private:
153  volatile int _dummy;
154 };
155 
157 //
158 // Con/Destructors
159 //
160 dafBase::Citizen::memId dafBase::Citizen::_addCitizen(Citizen const* c) {
161  memId cid = _nextMemIdAndIncrement();
162  WriteGuard guard(citizenLock);
163  if (_shouldPersistCitizens()) {
164  _persistentCitizens[c] = std::make_pair(cid, pthread_self());
165  } else {
166  _activeCitizens[c] = std::make_pair(cid, pthread_self());
167  }
168  if (cid == _newId) {
169  _newId += _newCallback(cid);
170  }
171  return cid;
172 }
173 
174 dafBase::Citizen::Citizen(std::type_info const& type) :
175  _sentinel(magicSentinel),
176  _CitizenId(_addCitizen(this)),
177  _typeName(type.name()) {
178 }
179 
181  _sentinel(magicSentinel),
182  _CitizenId(_addCitizen(this)),
183  _typeName(citizen._typeName) {
184 }
185 
187  {
188  WriteGuard guard(citizenLock);
189  if (_CitizenId == _deleteId) {
190  _deleteId += _deleteCallback(this);
191  }
192  }
193 
194  (void)_hasBeenCorrupted(); // may execute callback
195  _sentinel = 0x0000dead; // In case we have a dangling pointer
196 
197  bool corrupt = false;
198  {
199  WriteGuard guard(citizenLock);
200  size_t nActive = _activeCitizens.erase(this);
201  corrupt = nActive > 1 ||
202  (nActive == 0 && _persistentCitizens.erase(this) != 1);
203  }
204  if (corrupt) {
205  (void)_corruptionCallback(this);
206  }
207 }
208 
210 //
211 // The main purpose of this routine is as a place to set
212 // breakpoints to setup memory debugging; see discussion on trac
213 //
215  volatile int dummy = 1;
216  return dummy;
217 }
218 
219 /******************************************************************************/
220 //
221 // Return (some) private state
222 //
225  return _CitizenId;
226 }
227 
230  return _nextMemId();
231 }
232 
234 dafBase::Citizen::memId dafBase::Citizen::_nextMemId() {
235  return perThreadId.getRef();
236 }
237 
239 dafBase::Citizen::memId dafBase::Citizen::_nextMemIdAndIncrement() {
240  return perThreadId.getRef()++;
241 }
242 
244 //
245 std::string dafBase::Citizen::repr() const {
246  return boost::str(boost::format("%d: %08x %s")
247  % _CitizenId
248  % this
249  % lsst::utils::demangleType(_typeName)
250  );
251 }
252 
255  WriteGuard guard(citizenLock);
256  _persistentCitizens[this] = _activeCitizens[this];
257  _activeCitizens.erase(this);
258 }
259 
262 
263 //
264 //
266 //
268  int, //<! the int argument allows overloading
269  memId startingMemId
270  ) {
271  if (startingMemId == 0) { // easy
272  ReadGuard guard(citizenLock);
273  return _activeCitizens.size();
274  }
275 
276  int n = 0;
277  ReadGuard guard(citizenLock);
278  for (table::iterator cur = _activeCitizens.begin();
279  cur != _activeCitizens.end(); cur++) {
280  if (cur->first->_CitizenId >= startingMemId) {
281  n++;
282  }
283  }
284 
285  return n;
286 }
287 //
289 //
291  std::ostream &stream,
292  memId startingMemId
293  ) {
294  ReadGuard guard(citizenLock);
295 
296  std::unique_ptr<std::vector<Citizen const*> const> leaks(Citizen::census());
297 
298  for (std::vector<Citizen const *>::const_iterator citizen = leaks->begin(), end = leaks->end();
299  citizen != end; ++citizen) {
300  if ((*citizen)->getId() >= startingMemId) {
301  stream << (*citizen)->repr() << "\n";
302  }
303  }
304 }
305 
306 /************************************************************************************************************/
307 namespace {
308 bool cmpId(dafBase::Citizen const *a, dafBase::Citizen const *b)
309 {
310  return a->getId() < b->getId();
311 }
312 }
313 
314 //
316 //
321 //
322 std::vector<dafBase::Citizen const*> const* dafBase::Citizen::census() {
323  std::vector<Citizen const*>* vec =
324  new std::vector<Citizen const*>(0);
325  ReadGuard guard(citizenLock);
326  vec->reserve(_activeCitizens.size());
327 
328  for (table::iterator cur = _activeCitizens.begin();
329  cur != _activeCitizens.end(); cur++) {
330  vec->push_back(dynamic_cast<Citizen const*>(cur->first));
331  }
332 
333  std::sort(vec->begin(), vec->end(), cmpId);
334 
335  return vec;
336 }
337 
339 
343 bool dafBase::Citizen::_hasBeenCorrupted() const {
344  if (_sentinel == static_cast<int>(magicSentinel)) {
345  return false;
346  }
347 
348  (void)_corruptionCallback(this);
349  return true;
350 }
351 
354  ReadGuard guard(citizenLock);
355  for (table::iterator cur = _activeCitizens.begin();
356  cur != _activeCitizens.end(); cur++) {
357  if (cur->first->_hasBeenCorrupted()) {
358  return true;
359  }
360  }
361  for (table::iterator cur = _persistentCitizens.begin();
362  cur != _persistentCitizens.end(); cur++) {
363  if (cur->first->_hasBeenCorrupted()) {
364  return true;
365  }
366  }
367 
368  return false;
369 }
370 
373 
374 //
377  Citizen::memId id
378  ) {
379  WriteGuard guard(citizenLock);
380  Citizen::memId oldId = _newId;
381  _newId = id;
382 
383  return oldId;
384 }
385 
388  Citizen::memId id
389  ) {
390  WriteGuard guard(citizenLock);
391  Citizen::memId oldId = _deleteId;
392  _deleteId = id;
393 
394  return oldId;
395 }
397 
407 //
408 
410 
414  ) {
415  Citizen::memNewCallback old = _newCallback;
416  _newCallback = func;
417 
418  return old;
419 }
420 
424  ) {
425  Citizen::memCallback old = _deleteCallback;
426  _deleteCallback = func;
427 
428  return old;
429 }
430 
434  ) {
435  Citizen::memCallback old = _corruptionCallback;
436  _corruptionCallback = func;
437 
438  return old;
439 }
440 
445 
448  dafBase::Citizen::memId const cid
449  ) {
450  static int dId = 0; // how much to incr memId
451  std::cerr << boost::format("Allocating memId %d\n") % cid;
452 
453  return dId;
454 }
455 
458  ) {
459  static int dId = 0; // how much to incr memId
460  std::cerr << boost::format("Deleting memId %s\n") % ptr->repr();
461 
462  return dId;
463 }
464 
467  ) {
468  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
469  str(boost::format("Citizen \"%s\" is corrupted") % ptr->repr()));
470 
471  return ptr->getId(); // NOTREACHED
472 }
473 
474 bool& dafBase::Citizen::_shouldPersistCitizens(void) {
475  return perThreadPersistFlag.getRef();
476 }
477 
479 //
480 // Initialise static members
481 //
482 dafBase::Citizen::memId dafBase::Citizen::_newId = 0;
483 dafBase::Citizen::memId dafBase::Citizen::_deleteId = 0;
484 dafBase::Citizen::table dafBase::Citizen::_activeCitizens;
485 dafBase::Citizen::table dafBase::Citizen::_persistentCitizens;
486 
487 dafBase::Citizen::memNewCallback dafBase::Citizen::_newCallback = defaultNewCallback;
488 dafBase::Citizen::memCallback dafBase::Citizen::_deleteCallback = defaultDeleteCallback;
489 dafBase::Citizen::memCallback dafBase::Citizen::_corruptionCallback = defaultCorruptionCallback;
490 
491 
493  Citizen::_shouldPersistCitizens() = true;
494 }
495 
497  Citizen::_shouldPersistCitizens() = false;
498 }
unsigned long memId
Type of the block&#39;s ID.
Definition: Citizen.h:56
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
Definition: Citizen.cc:457
CitizenInit one
Definition: Citizen.cc:156
static int init()
Called once when the memory system is being initialised.
Definition: Citizen.cc:214
memId getId() const
Return the Citizen&#39;s ID.
Definition: Citizen.cc:224
memId(* memNewCallback)(const memId cid)
A function used to register a callback.
Definition: Citizen.h:58
dafBase::Citizen::memId defaultNewCallback(dafBase::Citizen::memId const cid)
Default callbacks.
Definition: Citizen.cc:447
Called once when the memory system is being initialised.
Definition: Citizen.cc:149
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
Definition: Citizen.cc:432
memId(* memCallback)(const Citizen *ptr)
Definition: Citizen.h:59
void markPersistent(void)
Mark a Citizen as persistent and not destroyed until process end.
Definition: Citizen.cc:254
std::string repr() const
Return a string representation of a Citizen.
Definition: Citizen.cc:245
static memId setNewCallbackId(memId id)
Call the NewCallback when block is allocated.
Definition: Citizen.cc:376
static memNewCallback setNewCallback(memNewCallback func)
Set the NewCallback function.
Definition: Citizen.cc:412
static bool hasBeenCorrupted()
Check all allocated blocks for corruption.
Definition: Citizen.cc:353
static memId setDeleteCallbackId(memId id)
Call the current DeleteCallback when block is deleted.
Definition: Citizen.cc:387
Citizen(const std::type_info &)
Definition: Citizen.cc:174
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.
Definition: Citizen.cc:422
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
Definition: Citizen.h:53
static const std::vector< const Citizen * > * census()
Return a (newly allocated) std::vector of active Citizens sorted by ID.
Definition: Citizen.cc:322
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.
Definition: Citizen.cc:466
static memId getNextMemId()
Return the memId of the next object to be allocated.
Definition: Citizen.cc:229