LSSTApplications  18.1.0
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 <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) { _mustUnlock = _lock.rdlock(); };
110  ~ReadGuard(void) {
111  if (_mustUnlock) _lock.unlock();
112  };
113 
114 private:
115  RwLock& _lock;
116  bool _mustUnlock;
117 };
118 
119 class WriteGuard {
120 public:
121  WriteGuard(RwLock& lock) : _lock(lock) { _lock.lock(); };
122  ~WriteGuard(void) { _lock.unlock(); };
123 
124 private:
125  RwLock& _lock;
126 };
127 
128 } // anonymous namespace
129 
131 //
132 // \brief A class that is instantiated once during startup
133 //
134 // The main purpose of CitizenInit is to provide a place to set
135 // breakpoints to setup memory debugging; see discussion on trac
136 //
137 class CitizenInit {
138 public:
139  CitizenInit() : _dummy(1) {}
140 
141 private:
142  volatile int _dummy;
143 };
144 
146 //
147 // Con/Destructors
148 //
149 dafBase::Citizen::memId dafBase::Citizen::_addCitizen(Citizen const* c) {
150  memId cid = _nextMemIdAndIncrement();
151  WriteGuard guard(citizenLock);
152  if (_shouldPersistCitizens()) {
153  _persistentCitizens[c] = std::make_pair(cid, pthread_self());
154  } else {
155  _activeCitizens[c] = std::make_pair(cid, pthread_self());
156  }
157  if (cid == _newId) {
158  _newId += _newCallback(cid);
159  }
160  return cid;
161 }
162 
164  : _sentinel(magicSentinel), _CitizenId(_addCitizen(this)), _typeName(type.name()) {}
165 
167  : _sentinel(magicSentinel), _CitizenId(_addCitizen(this)), _typeName(citizen._typeName) {}
168 
170  {
171  WriteGuard guard(citizenLock);
172  if (_CitizenId == _deleteId) {
173  _deleteId += _deleteCallback(this);
174  }
175  }
176 
177  (void)_hasBeenCorrupted(); // may execute callback
178  _sentinel = 0x0000dead; // In case we have a dangling pointer
179 
180  bool corrupt = false;
181  {
182  WriteGuard guard(citizenLock);
183  size_t nActive = _activeCitizens.erase(this);
184  corrupt = nActive > 1 || (nActive == 0 && _persistentCitizens.erase(this) != 1);
185  }
186  if (corrupt) {
187  (void)_corruptionCallback(this);
188  }
189 }
190 
192 //
193 // The main purpose of this routine is as a place to set
194 // breakpoints to setup memory debugging; see discussion on trac
195 //
197  volatile int dummy = 1;
198  return dummy;
199 }
200 
201 /******************************************************************************/
202 //
203 // Return (some) private state
204 //
206 dafBase::Citizen::memId dafBase::Citizen::getId() const { return _CitizenId; }
207 
210 
212 dafBase::Citizen::memId dafBase::Citizen::_nextMemId() { return perThreadId.getRef(); }
213 
215 dafBase::Citizen::memId dafBase::Citizen::_nextMemIdAndIncrement() { return perThreadId.getRef()++; }
216 
218 //
220  return boost::str(boost::format("%d: %08x %s") % _CitizenId % this %
221  lsst::utils::demangleType(_typeName));
222 }
223 
226  WriteGuard guard(citizenLock);
227  _persistentCitizens[this] = _activeCitizens[this];
228  _activeCitizens.erase(this);
229 }
230 
233 
234 //
235 //
237 //
238 int dafBase::Citizen::census(int, //<! the int argument allows overloading
239  memId startingMemId
240 ) {
241  if (startingMemId == 0) { // easy
242  ReadGuard guard(citizenLock);
243  return _activeCitizens.size();
244  }
245 
246  int n = 0;
247  ReadGuard guard(citizenLock);
248  for (table::iterator cur = _activeCitizens.begin(); cur != _activeCitizens.end(); cur++) {
249  if (cur->first->_CitizenId >= startingMemId) {
250  n++;
251  }
252  }
253 
254  return n;
255 }
256 //
258 //
260  memId startingMemId
261 ) {
262  ReadGuard guard(citizenLock);
263 
265 
266  for (std::vector<Citizen const*>::const_iterator citizen = leaks->begin(), end = leaks->end();
267  citizen != end; ++citizen) {
268  if ((*citizen)->getId() >= startingMemId) {
269  stream << (*citizen)->repr() << "\n";
270  }
271  }
272 }
273 
274 /************************************************************************************************************/
275 namespace {
276 bool cmpId(dafBase::Citizen const* a, dafBase::Citizen const* b) { return a->getId() < b->getId(); }
277 } // namespace
278 
279 //
281 //
286 //
289  ReadGuard guard(citizenLock);
290  vec->reserve(_activeCitizens.size());
291 
292  for (table::iterator cur = _activeCitizens.begin(); cur != _activeCitizens.end(); cur++) {
293  vec->push_back(dynamic_cast<Citizen const*>(cur->first));
294  }
295 
296  std::sort(vec->begin(), vec->end(), cmpId);
297 
298  return vec;
299 }
300 
302 
306 bool dafBase::Citizen::_hasBeenCorrupted() const {
307  if (_sentinel == static_cast<int>(magicSentinel)) {
308  return false;
309  }
310 
311  (void)_corruptionCallback(this);
312  return true;
313 }
314 
317  ReadGuard guard(citizenLock);
318  for (table::iterator cur = _activeCitizens.begin(); cur != _activeCitizens.end(); cur++) {
319  if (cur->first->_hasBeenCorrupted()) {
320  return true;
321  }
322  }
323  for (table::iterator cur = _persistentCitizens.begin(); cur != _persistentCitizens.end(); cur++) {
324  if (cur->first->_hasBeenCorrupted()) {
325  return true;
326  }
327  }
328 
329  return false;
330 }
331 
334 
335 //
338 ) {
339  WriteGuard guard(citizenLock);
340  Citizen::memId oldId = _newId;
341  _newId = id;
342 
343  return oldId;
344 }
345 
348 ) {
349  WriteGuard guard(citizenLock);
350  Citizen::memId oldId = _deleteId;
351  _deleteId = id;
352 
353  return oldId;
354 }
356 
366 //
367 
369 
373 ) {
374  Citizen::memNewCallback old = _newCallback;
375  _newCallback = func;
376 
377  return old;
378 }
379 
383 ) {
384  Citizen::memCallback old = _deleteCallback;
385  _deleteCallback = func;
386 
387  return old;
388 }
389 
393 ) {
394  Citizen::memCallback old = _corruptionCallback;
395  _corruptionCallback = func;
396 
397  return old;
398 }
399 
404 
407  dafBase::Citizen::memId const cid
408 ) {
409  static int dId = 0; // how much to incr memId
410  std::cerr << boost::format("Allocating memId %d\n") % cid;
411 
412  return dId;
413 }
414 
417 ) {
418  static int dId = 0; // how much to incr memId
419  std::cerr << boost::format("Deleting memId %s\n") % ptr->repr();
420 
421  return dId;
422 }
423 
426  dafBase::Citizen const* ptr
427 ) {
428  throw std::bad_alloc();
429 
430  return ptr->getId(); // NOTREACHED
431 }
432 
433 bool& dafBase::Citizen::_shouldPersistCitizens(void) { return perThreadPersistFlag.getRef(); }
434 
436 //
437 // Initialise static members
438 //
439 dafBase::Citizen::memId dafBase::Citizen::_newId = 0;
440 dafBase::Citizen::memId dafBase::Citizen::_deleteId = 0;
441 dafBase::Citizen::table dafBase::Citizen::_activeCitizens;
442 dafBase::Citizen::table dafBase::Citizen::_persistentCitizens;
443 
444 dafBase::Citizen::memNewCallback dafBase::Citizen::_newCallback = defaultNewCallback;
445 dafBase::Citizen::memCallback dafBase::Citizen::_deleteCallback = defaultDeleteCallback;
446 dafBase::Citizen::memCallback dafBase::Citizen::_corruptionCallback = defaultCorruptionCallback;
447 
448 dafBase::PersistentCitizenScope::PersistentCitizenScope() { Citizen::_shouldPersistCitizens() = true; }
449 
450 dafBase::PersistentCitizenScope::~PersistentCitizenScope() { Citizen::_shouldPersistCitizens() = false; }
unsigned long memId
Type of the block&#39;s ID.
Definition: Citizen.h:58
std::string demangleType(std::string const _typeName)
Definition: Demangle.cc:113
uint64_t * ptr
Definition: RangeSet.cc:88
static int init()
Called once when the memory system is being initialised.
Definition: Citizen.cc:196
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
Definition: Citizen.cc:416
table::Key< int > b
table::Key< int > a
Called once when the memory system is being initialised.
Definition: Citizen.cc:137
T end(T... args)
table::Key< int > id
Definition: Detector.cc:166
CitizenInit one
Definition: Citizen.cc:145
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
Definition: Citizen.cc:391
STL class.
T push_back(T... args)
void markPersistent(void)
Mark a Citizen as persistent and not destroyed until process end.
Definition: Citizen.cc:225
static memId setNewCallbackId(memId id)
Call the NewCallback when block is allocated.
Definition: Citizen.cc:337
static memNewCallback setNewCallback(memNewCallback func)
Set the NewCallback function.
Definition: Citizen.cc:371
static bool hasBeenCorrupted()
Check all allocated blocks for corruption.
Definition: Citizen.cc:316
char * data
Definition: BaseRecord.cc:62
table::Key< int > type
Definition: Detector.cc:167
T erase(T... args)
std::string repr() const
Return a string representation of a Citizen.
Definition: Citizen.cc:219
dafBase::Citizen::memId defaultNewCallback(dafBase::Citizen::memId const cid)
Default callbacks.
Definition: Citizen.cc:406
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:168
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:347
memId getId() const
Return the Citizen&#39;s ID.
Definition: Citizen.cc:206
T size(T... args)
memId(* memNewCallback)(const memId cid)
A function used to register a callback.
Definition: Citizen.h:60
STL class.
STL class.
Citizen(const std::type_info &)
Definition: Citizen.cc:163
T begin(T... args)
STL class.
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.
Definition: Citizen.cc:381
memId(* memCallback)(const Citizen *ptr)
Definition: Citizen.h:61
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:55
STL class.
static memId getNextMemId()
Return the memId of the next object to be allocated.
Definition: Citizen.cc:209
int end
static const std::vector< const Citizen * > * census()
Return a (newly allocated) std::vector of active Citizens sorted by ID.
Definition: Citizen.cc:287
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.
Definition: Citizen.cc:425
T reserve(T... args)