lsst.daf.base  15.0-1-gf4f1c34+8
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/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 std::bad_alloc();
50  }
51  };
52  T& getRef(void) {
53  T* d = reinterpret_cast<T*>(pthread_getspecific(_key));
54  if (d == 0) {
55  d = new T(_init);
56  pthread_setspecific(_key, d);
57  }
58  return *d;
59  };
60 
61 private:
62  pthread_key_t _key;
63  T _init;
64 
65  static void del(void* data) {
66  T* d = reinterpret_cast<T*>(data);
67  delete d;
68  };
69 };
70 
71 static ThreadPrivate<dafBase::Citizen::memId> perThreadId(1);
72 static ThreadPrivate<bool> perThreadPersistFlag(false);
73 
74 class RwLock {
75 public:
76  RwLock(void) {
77  int ret = pthread_rwlock_init(&_lock, 0);
78  if (ret != 0) {
79  throw std::bad_alloc();
80  }
81  };
82  void lock(void) {
83  int ret = pthread_rwlock_wrlock(&_lock);
84  if (ret != 0) {
85  throw std::bad_alloc();
86  }
87  };
88  bool rdlock(void) {
89  int ret = pthread_rwlock_rdlock(&_lock);
90  if (ret == 0) return true;
91  if (ret == EDEADLK) return false;
92  throw std::bad_alloc();
93  };
94  void unlock(void) {
95  int ret = pthread_rwlock_unlock(&_lock);
96  if (ret != 0) {
97  throw std::bad_alloc();
98  }
99  };
100 
101 private:
102  pthread_rwlock_t _lock;
103 };
104 
105 static RwLock citizenLock;
106 
107 class ReadGuard {
108 public:
109  ReadGuard(RwLock& lock) : _lock(lock) {
110  _mustUnlock = _lock.rdlock();
111  };
112  ~ReadGuard(void) {
113  if (_mustUnlock) _lock.unlock();
114  };
115 
116 private:
117  RwLock& _lock;
118  bool _mustUnlock;
119 };
120 
121 class WriteGuard {
122 public:
123  WriteGuard(RwLock& lock) : _lock(lock) {
124  _lock.lock();
125  };
126  ~WriteGuard(void) {
127  _lock.unlock();
128  };
129 
130 private:
131  RwLock& _lock;
132 };
133 
134 } // anonymous namespace
135 
137 //
138 // \brief A class that is instantiated once during startup
139 //
140 // The main purpose of CitizenInit is to provide a place to set
141 // breakpoints to setup memory debugging; see discussion on trac
142 //
143 class CitizenInit {
144 public:
145  CitizenInit() : _dummy(1) { }
146 private:
147  volatile int _dummy;
148 };
149 
151 //
152 // Con/Destructors
153 //
154 dafBase::Citizen::memId dafBase::Citizen::_addCitizen(Citizen const* c) {
155  memId cid = _nextMemIdAndIncrement();
156  WriteGuard guard(citizenLock);
157  if (_shouldPersistCitizens()) {
158  _persistentCitizens[c] = std::make_pair(cid, pthread_self());
159  } else {
160  _activeCitizens[c] = std::make_pair(cid, pthread_self());
161  }
162  if (cid == _newId) {
163  _newId += _newCallback(cid);
164  }
165  return cid;
166 }
167 
169  _sentinel(magicSentinel),
170  _CitizenId(_addCitizen(this)),
171  _typeName(type.name()) {
172 }
173 
175  _sentinel(magicSentinel),
176  _CitizenId(_addCitizen(this)),
177  _typeName(citizen._typeName) {
178 }
179 
181  {
182  WriteGuard guard(citizenLock);
183  if (_CitizenId == _deleteId) {
184  _deleteId += _deleteCallback(this);
185  }
186  }
187 
188  (void)_hasBeenCorrupted(); // may execute callback
189  _sentinel = 0x0000dead; // In case we have a dangling pointer
190 
191  bool corrupt = false;
192  {
193  WriteGuard guard(citizenLock);
194  size_t nActive = _activeCitizens.erase(this);
195  corrupt = nActive > 1 ||
196  (nActive == 0 && _persistentCitizens.erase(this) != 1);
197  }
198  if (corrupt) {
199  (void)_corruptionCallback(this);
200  }
201 }
202 
204 //
205 // The main purpose of this routine is as a place to set
206 // breakpoints to setup memory debugging; see discussion on trac
207 //
209  volatile int dummy = 1;
210  return dummy;
211 }
212 
213 /******************************************************************************/
214 //
215 // Return (some) private state
216 //
219  return _CitizenId;
220 }
221 
224  return _nextMemId();
225 }
226 
228 dafBase::Citizen::memId dafBase::Citizen::_nextMemId() {
229  return perThreadId.getRef();
230 }
231 
233 dafBase::Citizen::memId dafBase::Citizen::_nextMemIdAndIncrement() {
234  return perThreadId.getRef()++;
235 }
236 
238 //
240  return boost::str(boost::format("%d: %08x %s")
241  % _CitizenId
242  % this
243  % lsst::utils::demangleType(_typeName)
244  );
245 }
246 
249  WriteGuard guard(citizenLock);
250  _persistentCitizens[this] = _activeCitizens[this];
251  _activeCitizens.erase(this);
252 }
253 
256 
257 //
258 //
260 //
262  int, //<! the int argument allows overloading
263  memId startingMemId
264  ) {
265  if (startingMemId == 0) { // easy
266  ReadGuard guard(citizenLock);
267  return _activeCitizens.size();
268  }
269 
270  int n = 0;
271  ReadGuard guard(citizenLock);
272  for (table::iterator cur = _activeCitizens.begin();
273  cur != _activeCitizens.end(); cur++) {
274  if (cur->first->_CitizenId >= startingMemId) {
275  n++;
276  }
277  }
278 
279  return n;
280 }
281 //
283 //
285  std::ostream &stream,
286  memId startingMemId
287  ) {
288  ReadGuard guard(citizenLock);
289 
291 
292  for (std::vector<Citizen const *>::const_iterator citizen = leaks->begin(), end = leaks->end();
293  citizen != end; ++citizen) {
294  if ((*citizen)->getId() >= startingMemId) {
295  stream << (*citizen)->repr() << "\n";
296  }
297  }
298 }
299 
300 /************************************************************************************************************/
301 namespace {
302 bool cmpId(dafBase::Citizen const *a, dafBase::Citizen const *b)
303 {
304  return a->getId() < b->getId();
305 }
306 }
307 
308 //
310 //
315 //
319  ReadGuard guard(citizenLock);
320  vec->reserve(_activeCitizens.size());
321 
322  for (table::iterator cur = _activeCitizens.begin();
323  cur != _activeCitizens.end(); cur++) {
324  vec->push_back(dynamic_cast<Citizen const*>(cur->first));
325  }
326 
327  std::sort(vec->begin(), vec->end(), cmpId);
328 
329  return vec;
330 }
331 
333 
337 bool dafBase::Citizen::_hasBeenCorrupted() const {
338  if (_sentinel == static_cast<int>(magicSentinel)) {
339  return false;
340  }
341 
342  (void)_corruptionCallback(this);
343  return true;
344 }
345 
348  ReadGuard guard(citizenLock);
349  for (table::iterator cur = _activeCitizens.begin();
350  cur != _activeCitizens.end(); cur++) {
351  if (cur->first->_hasBeenCorrupted()) {
352  return true;
353  }
354  }
355  for (table::iterator cur = _persistentCitizens.begin();
356  cur != _persistentCitizens.end(); cur++) {
357  if (cur->first->_hasBeenCorrupted()) {
358  return true;
359  }
360  }
361 
362  return false;
363 }
364 
367 
368 //
371  Citizen::memId id
372  ) {
373  WriteGuard guard(citizenLock);
374  Citizen::memId oldId = _newId;
375  _newId = id;
376 
377  return oldId;
378 }
379 
382  Citizen::memId id
383  ) {
384  WriteGuard guard(citizenLock);
385  Citizen::memId oldId = _deleteId;
386  _deleteId = id;
387 
388  return oldId;
389 }
391 
401 //
402 
404 
408  ) {
409  Citizen::memNewCallback old = _newCallback;
410  _newCallback = func;
411 
412  return old;
413 }
414 
418  ) {
419  Citizen::memCallback old = _deleteCallback;
420  _deleteCallback = func;
421 
422  return old;
423 }
424 
428  ) {
429  Citizen::memCallback old = _corruptionCallback;
430  _corruptionCallback = func;
431 
432  return old;
433 }
434 
439 
442  dafBase::Citizen::memId const cid
443  ) {
444  static int dId = 0; // how much to incr memId
445  std::cerr << boost::format("Allocating memId %d\n") % cid;
446 
447  return dId;
448 }
449 
452  ) {
453  static int dId = 0; // how much to incr memId
454  std::cerr << boost::format("Deleting memId %s\n") % ptr->repr();
455 
456  return dId;
457 }
458 
461  ) {
462  throw std::bad_alloc();
463 
464  return ptr->getId(); // NOTREACHED
465 }
466 
467 bool& dafBase::Citizen::_shouldPersistCitizens(void) {
468  return perThreadPersistFlag.getRef();
469 }
470 
472 //
473 // Initialise static members
474 //
475 dafBase::Citizen::memId dafBase::Citizen::_newId = 0;
476 dafBase::Citizen::memId dafBase::Citizen::_deleteId = 0;
477 dafBase::Citizen::table dafBase::Citizen::_activeCitizens;
478 dafBase::Citizen::table dafBase::Citizen::_persistentCitizens;
479 
480 dafBase::Citizen::memNewCallback dafBase::Citizen::_newCallback = defaultNewCallback;
481 dafBase::Citizen::memCallback dafBase::Citizen::_deleteCallback = defaultDeleteCallback;
482 dafBase::Citizen::memCallback dafBase::Citizen::_corruptionCallback = defaultCorruptionCallback;
483 
484 
486  Citizen::_shouldPersistCitizens() = true;
487 }
488 
490  Citizen::_shouldPersistCitizens() = false;
491 }
unsigned long memId
Type of the block&#39;s ID.
Definition: Citizen.h:56
std::string demangleType(std::string const _typeName)
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
Definition: Citizen.cc:451
CitizenInit one
Definition: Citizen.cc:150
static int init()
Called once when the memory system is being initialised.
Definition: Citizen.cc:208
dafBase::Citizen::memId defaultNewCallback(dafBase::Citizen::memId const cid)
Default callbacks.
Definition: Citizen.cc:441
Called once when the memory system is being initialised.
Definition: Citizen.cc:143
T end(T... args)
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
Definition: Citizen.cc:426
STL class.
T push_back(T... args)
void markPersistent(void)
Mark a Citizen as persistent and not destroyed until process end.
Definition: Citizen.cc:248
static memId setNewCallbackId(memId id)
Call the NewCallback when block is allocated.
Definition: Citizen.cc:370
static memNewCallback setNewCallback(memNewCallback func)
Set the NewCallback function.
Definition: Citizen.cc:406
static bool hasBeenCorrupted()
Check all allocated blocks for corruption.
Definition: Citizen.cc:347
T erase(T... args)
std::string repr() const
Return a string representation of a Citizen.
Definition: Citizen.cc:239
T lock(T... args)
T make_pair(T... args)
static memId setDeleteCallbackId(memId id)
Call the current DeleteCallback when block is deleted.
Definition: Citizen.cc:381
memId getId() const
Return the Citizen&#39;s ID.
Definition: Citizen.cc:218
T size(T... args)
memId(* memNewCallback)(const memId cid)
A function used to register a callback.
Definition: Citizen.h:58
STL class.
STL class.
Citizen(const std::type_info &)
Definition: Citizen.cc:168
T begin(T... args)
STL class.
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.
Definition: Citizen.cc:416
memId(* memCallback)(const Citizen *ptr)
Definition: Citizen.h:59
T sort(T... args)
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
Definition: Citizen.h:53
STL class.
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.
Definition: Citizen.cc:460
static memId getNextMemId()
Return the memId of the next object to be allocated.
Definition: Citizen.cc:223
static const std::vector< const Citizen * > * census()
Return a (newly allocated) std::vector of active Citizens sorted by ID.
Definition: Citizen.cc:316
T reserve(T... args)