LSSTApplications  10.0+286,10.0+36,10.0+46,10.0-2-g4f67435,10.1+152,10.1+37,11.0,11.0+1,11.0-1-g47edd16,11.0-1-g60db491,11.0-1-g7418c06,11.0-2-g04d2804,11.0-2-g68503cd,11.0-2-g818369d,11.0-2-gb8b8ce7
LSSTDataManagementBasePackage
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 <iostream>
29 #include <boost/shared_ptr.hpp>
30 #include <boost/scoped_ptr.hpp> // should use std::unique_ptr from C++11 when available
31 #include <boost/format.hpp>
32 #include <ctype.h>
33 #include <cerrno>
34 
35 #include "lsst/daf/base/Citizen.h"
36 #include "lsst/pex/exceptions.h"
37 #include "lsst/utils/Demangle.h"
38 
39 namespace dafBase = lsst::daf::base;
40 
41 namespace {
42 
43 template <typename T>
44 class ThreadPrivate {
45 public:
46  ThreadPrivate(T const& t) : _init(t) {
47  int ret = pthread_key_create(&_key, del);
48  if (ret != 0) {
49  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
50  "Could not create key");
51  }
52  };
53  T& getRef(void) {
54  T* d = reinterpret_cast<T*>(pthread_getspecific(_key));
55  if (d == 0) {
56  d = new T(_init);
57  pthread_setspecific(_key, d);
58  }
59  return *d;
60  };
61 
62 private:
63  pthread_key_t _key;
64  T _init;
65 
66  static void del(void* data) {
67  T* d = reinterpret_cast<T*>(data);
68  delete d;
69  };
70 };
71 
72 static ThreadPrivate<dafBase::Citizen::memId> perThreadId(1);
73 static ThreadPrivate<bool> perThreadPersistFlag(false);
74 
75 class RwLock {
76 public:
77  RwLock(void) {
78  int ret = pthread_rwlock_init(&_lock, 0);
79  if (ret != 0) {
80  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
81  "Could not create Citizen lock");
82  }
83  };
84  void lock(void) {
85  int ret = pthread_rwlock_wrlock(&_lock);
86  if (ret != 0) {
87  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
88  "Could not acquire Citizen write lock");
89  }
90  };
91  bool rdlock(void) {
92  int ret = pthread_rwlock_rdlock(&_lock);
93  if (ret == 0) return true;
94  if (ret == EDEADLK) return false;
95  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
96  "Could not acquire Citizen read lock");
97  };
98  void unlock(void) {
99  int ret = pthread_rwlock_unlock(&_lock);
100  if (ret != 0) {
101  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
102  "Could not release Citizen lock");
103  }
104  };
105 
106 private:
107  pthread_rwlock_t _lock;
108 };
109 
110 static RwLock citizenLock;
111 
112 class ReadGuard {
113 public:
114  ReadGuard(RwLock& lock) : _lock(lock) {
115  _mustUnlock = _lock.rdlock();
116  };
117  ~ReadGuard(void) {
118  if (_mustUnlock) _lock.unlock();
119  };
120 
121 private:
122  RwLock& _lock;
123  bool _mustUnlock;
124 };
125 
126 class WriteGuard {
127 public:
128  WriteGuard(RwLock& lock) : _lock(lock) {
129  _lock.lock();
130  };
131  ~WriteGuard(void) {
132  _lock.unlock();
133  };
134 
135 private:
136  RwLock& _lock;
137 };
138 
139 } // anonymous namespace
140 
142 //
143 // \brief A class that is instantiated once during startup
144 //
145 // The main purpose of CitizenInit is to provide a place to set
146 // breakpoints to setup memory debugging; see discussion on trac
147 //
148 class CitizenInit {
149 public:
150  CitizenInit() : _dummy(1) { }
151 private:
152  volatile int _dummy;
153 };
154 
156 //
157 // Con/Destructors
158 //
161  WriteGuard guard(citizenLock);
162  if (_shouldPersistCitizens()) {
163  _persistentCitizens[c] = std::make_pair(cid, pthread_self());
164  } else {
165  _activeCitizens[c] = std::make_pair(cid, pthread_self());
166  }
167  if (cid == _newId) {
168  _newId += _newCallback(cid);
169  }
170  return cid;
171 }
172 
173 dafBase::Citizen::Citizen(std::type_info const& type) :
174  _sentinel(magicSentinel),
175  _CitizenId(_addCitizen(this)),
176  _typeName(type.name()) {
177 }
178 
180  _sentinel(magicSentinel),
181  _CitizenId(_addCitizen(this)),
182  _typeName(citizen._typeName) {
183 }
184 
186  {
187  WriteGuard guard(citizenLock);
188  if (_CitizenId == _deleteId) {
189  _deleteId += _deleteCallback(this);
190  }
191  }
192 
193  (void)_hasBeenCorrupted(); // may execute callback
194  _sentinel = 0x0000dead; // In case we have a dangling pointer
195 
196  bool corrupt = false;
197  {
198  WriteGuard guard(citizenLock);
199  size_t nActive = _activeCitizens.erase(this);
200  corrupt = nActive > 1 ||
201  (nActive == 0 && _persistentCitizens.erase(this) != 1);
202  }
203  if (corrupt) {
204  (void)_corruptionCallback(this);
205  }
206 }
207 
209 //
210 // The main purpose of this routine is as a place to set
211 // breakpoints to setup memory debugging; see discussion on trac
212 //
214  volatile int dummy = 1;
215  return dummy;
216 }
217 
218 /******************************************************************************/
219 //
220 // Return (some) private state
221 //
224  return _CitizenId;
225 }
226 
229  return _nextMemId();
230 }
231 
234  return perThreadId.getRef();
235 }
236 
239  return perThreadId.getRef()++;
240 }
241 
243 //
244 std::string dafBase::Citizen::repr() const {
245  return boost::str(boost::format("%d: %08x %s")
246  % _CitizenId
247  % this
248  % lsst::utils::demangleType(_typeName)
249  );
250 }
251 
254  WriteGuard guard(citizenLock);
255  _persistentCitizens[this] = _activeCitizens[this];
256  _activeCitizens.erase(this);
257 }
258 
261 
262 //
263 //
265 //
267  int, //<! the int argument allows overloading
268  memId startingMemId
269  ) {
270  if (startingMemId == 0) { // easy
271  ReadGuard guard(citizenLock);
272  return _activeCitizens.size();
273  }
274 
275  int n = 0;
276  ReadGuard guard(citizenLock);
277  for (table::iterator cur = _activeCitizens.begin();
278  cur != _activeCitizens.end(); cur++) {
279  if (cur->first->_CitizenId >= startingMemId) {
280  n++;
281  }
282  }
283 
284  return n;
285 }
286 //
288 //
290  std::ostream &stream,
291  memId startingMemId
292  ) {
293  ReadGuard guard(citizenLock);
294 
295  boost::scoped_ptr<std::vector<Citizen const*> const> leaks(Citizen::census());
296 
297  for (std::vector<Citizen const *>::const_iterator citizen = leaks->begin(), end = leaks->end();
298  citizen != end; ++citizen) {
299  if ((*citizen)->getId() >= startingMemId) {
300  stream << (*citizen)->repr() << "\n";
301  }
302  }
303 }
304 
305 /************************************************************************************************************/
306 namespace {
307 bool cmpId(dafBase::Citizen const *a, dafBase::Citizen const *b)
308 {
309  return a->getId() < b->getId();
310 }
311 }
312 
313 //
315 //
320 //
321 std::vector<dafBase::Citizen const*> const* dafBase::Citizen::census() {
322  std::vector<Citizen const*>* vec =
323  new std::vector<Citizen const*>(0);
324  ReadGuard guard(citizenLock);
325  vec->reserve(_activeCitizens.size());
326 
327  for (table::iterator cur = _activeCitizens.begin();
328  cur != _activeCitizens.end(); cur++) {
329  vec->push_back(dynamic_cast<Citizen const*>(cur->first));
330  }
331 
332  std::sort(vec->begin(), vec->end(), cmpId);
333 
334  return vec;
335 }
336 
338 
343  if (_sentinel == static_cast<int>(magicSentinel)) {
344  return false;
345  }
346 
347  (void)_corruptionCallback(this);
348  return true;
349 }
350 
353  ReadGuard guard(citizenLock);
354  for (table::iterator cur = _activeCitizens.begin();
355  cur != _activeCitizens.end(); cur++) {
356  if (cur->first->_hasBeenCorrupted()) {
357  return true;
358  }
359  }
360  for (table::iterator cur = _persistentCitizens.begin();
361  cur != _persistentCitizens.end(); cur++) {
362  if (cur->first->_hasBeenCorrupted()) {
363  return true;
364  }
365  }
366 
367  return false;
368 }
369 
372 
373 //
376  Citizen::memId id
377  ) {
378  WriteGuard guard(citizenLock);
379  Citizen::memId oldId = _newId;
380  _newId = id;
381 
382  return oldId;
383 }
384 
387  Citizen::memId id
388  ) {
389  WriteGuard guard(citizenLock);
390  Citizen::memId oldId = _deleteId;
391  _deleteId = id;
392 
393  return oldId;
394 }
396 
406 //
407 
409 
413  ) {
414  Citizen::memNewCallback old = _newCallback;
415  _newCallback = func;
416 
417  return old;
418 }
419 
423  ) {
424  Citizen::memCallback old = _deleteCallback;
425  _deleteCallback = func;
426 
427  return old;
428 }
429 
433  ) {
434  Citizen::memCallback old = _corruptionCallback;
435  _corruptionCallback = func;
436 
437  return old;
438 }
439 
444 
447  dafBase::Citizen::memId const cid
448  ) {
449  static int dId = 0; // how much to incr memId
450  std::cerr << boost::format("Allocating memId %d\n") % cid;
451 
452  return dId;
453 }
454 
457  ) {
458  static int dId = 0; // how much to incr memId
459  std::cerr << boost::format("Deleting memId %s\n") % ptr->repr();
460 
461  return dId;
462 }
463 
466  ) {
467  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
468  str(boost::format("Citizen \"%s\" is corrupted") % ptr->repr()));
469 
470  return ptr->getId(); // NOTREACHED
471 }
472 
474  return perThreadPersistFlag.getRef();
475 }
476 
478 //
479 // Initialise static members
480 //
485 
489 
490 
493 }
494 
497 }
unsigned long memId
Type of the block&#39;s ID.
Definition: Citizen.h:59
std::string demangleType(std::string const _typeName)
Definition: Demangle.cc:113
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
Definition: Citizen.cc:456
CitizenInit one
Definition: Citizen.cc:155
static memId _newId
Definition: Citizen.h:111
table::Key< std::string > name
Definition: ApCorrMap.cc:71
volatile int _dummy
Definition: Citizen.cc:152
static int init()
Called once when the memory system is being initialised.
Definition: Citizen.cc:213
Include files required for standard LSST Exception handling.
memId getId() const
Return the Citizen&#39;s ID.
Definition: Citizen.cc:223
memId(* memNewCallback)(const memId cid)
A function used to register a callback.
Definition: Citizen.h:61
dafBase::Citizen::memId defaultNewCallback(dafBase::Citizen::memId const cid)
Default NewCallback.
Definition: Citizen.cc:446
Called once when the memory system is being initialised.
Definition: Citizen.cc:148
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
Definition: Citizen.cc:431
std::map< Citizen const *, CitizenInfo > table
Definition: Citizen.h:93
memId(* memCallback)(const Citizen *ptr)
Definition: Citizen.h:62
static table _activeCitizens
Definition: Citizen.h:105
void markPersistent(void)
Mark a Citizen as persistent and not destroyed until process end.
Definition: Citizen.cc:253
std::string repr() const
Return a string representation of a Citizen.
Definition: Citizen.cc:244
static memId setNewCallbackId(memId id)
Call the NewCallback when block is allocated.
Definition: Citizen.cc:375
static memNewCallback setNewCallback(memNewCallback func)
Set the NewCallback function.
Definition: Citizen.cc:411
static bool & _shouldPersistCitizens()
Set the NewCallback function.
Definition: Citizen.cc:473
static bool hasBeenCorrupted()
Check all allocated blocks for corruption.
Definition: Citizen.cc:352
static memCallback _deleteCallback
Definition: Citizen.h:115
static table _persistentCitizens
Definition: Citizen.h:106
static memId setDeleteCallbackId(memId id)
Call the current DeleteCallback when block is deleted.
Definition: Citizen.cc:386
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
Citizen(const std::type_info &)
Definition: Citizen.cc:173
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.
Definition: Citizen.cc:421
int id
Definition: CR.cc:151
static memId _nextMemIdAndIncrement(void)
Return the memId and prepare for the next object to be allocated.
Definition: Citizen.cc:238
static memId _deleteId
Definition: Citizen.h:112
afw::table::Key< double > b
static memId _nextMemId(void)
Return the memId of the next object to be allocated.
Definition: Citizen.cc:233
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
Definition: Citizen.h:56
static memCallback _corruptionCallback
Definition: Citizen.h:116
static const std::vector< const Citizen * > * census()
Return a (newly allocated) std::vector of active Citizens sorted by ID.
Definition: Citizen.cc:321
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.
Definition: Citizen.cc:465
static memId _addCitizen(Citizen const *c)
Definition: Citizen.cc:159
static memNewCallback _newCallback
Definition: Citizen.h:114
static memId getNextMemId()
Return the memId of the next object to be allocated.
Definition: Citizen.cc:228
bool _hasBeenCorrupted() const
Definition: Citizen.cc:342