LSSTApplications  11.0-24-g0a022a1,14.0+77,15.0,15.0+1
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/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) {
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) {
82  "Could not create Citizen lock");
83  }
84  };
85  void lock(void) {
86  int ret = pthread_rwlock_wrlock(&_lock);
87  if (ret != 0) {
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;
97  "Could not acquire Citizen read lock");
98  };
99  void unlock(void) {
100  int ret = pthread_rwlock_unlock(&_lock);
101  if (ret != 0) {
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 //
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 
175  _sentinel(magicSentinel),
176  _CitizenId(_addCitizen(this)),
177  _typeName(type.name()) {
178 }
179 
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 
235  return perThreadId.getRef();
236 }
237 
240  return perThreadId.getRef()++;
241 }
242 
244 //
246  return boost::str(boost::format("%d: %08x %s")
247  % _CitizenId
248  % this
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 //
292  memId startingMemId
293  ) {
294  ReadGuard guard(citizenLock);
295 
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 //
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 
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  ) {
416  _newCallback = func;
417 
418  return old;
419 }
420 
424  ) {
426  _deleteCallback = func;
427 
428  return old;
429 }
430 
434  ) {
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  ) {
469  str(boost::format("Citizen \"%s\" is corrupted") % ptr->repr()));
470 
471  return ptr->getId(); // NOTREACHED
472 }
473 
475  return perThreadPersistFlag.getRef();
476 }
477 
479 //
480 // Initialise static members
481 //
486 
490 
491 
494 }
495 
498 }
unsigned long memId
Type of the block&#39;s ID.
Definition: Citizen.h:56
std::string demangleType(std::string const _typeName)
Definition: Demangle.cc:113
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
Definition: Citizen.cc:457
CitizenInit one
Definition: Citizen.cc:156
static memId _newId
Definition: Citizen.h:108
table::Key< std::string > name
Definition: ApCorrMap.cc:71
volatile int _dummy
Definition: Citizen.cc:153
static int init()
Called once when the memory system is being initialised.
Definition: Citizen.cc:214
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
T end(T... args)
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
Definition: Citizen.cc:432
std::map< Citizen const *, CitizenInfo > table
Definition: Citizen.h:90
STL class.
Include files required for standard LSST Exception handling.
static table _activeCitizens
Definition: Citizen.h:102
T push_back(T... args)
void markPersistent(void)
Mark a Citizen as persistent and not destroyed until process end.
Definition: Citizen.cc:254
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 & _shouldPersistCitizens()
Set the NewCallback function.
Definition: Citizen.cc:474
static bool hasBeenCorrupted()
Check all allocated blocks for corruption.
Definition: Citizen.cc:353
int end
static memCallback _deleteCallback
Definition: Citizen.h:112
T erase(T... args)
std::string repr() const
Return a string representation of a Citizen.
Definition: Citizen.cc:245
def format(config, name=None, writeSourceLine=True, prefix="", verbose=False)
Definition: history.py:134
table::Key< int > b
T lock(T... args)
T make_pair(T... args)
const char * _typeName
Definition: Citizen.h:94
static table _persistentCitizens
Definition: Citizen.h:103
static memId setDeleteCallbackId(memId id)
Call the current DeleteCallback when block is deleted.
Definition: Citizen.cc:387
memId getId() const
Return the Citizen&#39;s ID.
Definition: Citizen.cc:224
T size(T... args)
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
Definition: Exception.h:46
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:174
T begin(T... args)
bool _hasBeenCorrupted() const
Check for corruption Return true if the block is corrupted, but only after calling the corruptionCall...
Definition: Citizen.cc:343
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.
Definition: Citizen.cc:422
memId(* memCallback)(const Citizen *ptr)
Definition: Citizen.h:59
int id
Definition: CR.cc:155
static memId _nextMemIdAndIncrement(void)
Return the memId and prepare for the next object to be allocated.
Definition: Citizen.cc:239
static memId _deleteId
Definition: Citizen.h:109
static memId _nextMemId(void)
Return the memId of the next object to be allocated.
Definition: Citizen.cc:234
table::Key< int > a
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
static memCallback _corruptionCallback
Definition: Citizen.h:113
STL class.
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.
Definition: Citizen.cc:466
static memId _addCitizen(Citizen const *c)
Definition: Citizen.cc:160
static memNewCallback _newCallback
Definition: Citizen.h:111
static memId getNextMemId()
Return the memId of the next object to be allocated.
Definition: Citizen.cc:229
static const std::vector< const Citizen * > * census()
Return a (newly allocated) std::vector of active Citizens sorted by ID.
Definition: Citizen.cc:322
T reserve(T... args)