34 #include <boost/format.hpp>
37 #include "lsst/pex/exceptions.h"
38 #include "lsst/utils/Demangle.h"
40 namespace dafBase = lsst::daf::base;
47 ThreadPrivate(T
const& t) : _init(t) {
48 int ret = pthread_key_create(&_key, del);
50 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
51 "Could not create key");
55 T* d =
reinterpret_cast<T*
>(pthread_getspecific(_key));
58 pthread_setspecific(_key, d);
67 static void del(
void* data) {
68 T* d =
reinterpret_cast<T*
>(data);
73 static ThreadPrivate<dafBase::Citizen::memId> perThreadId(1);
74 static ThreadPrivate<bool> perThreadPersistFlag(
false);
79 int ret = pthread_rwlock_init(&_lock, 0);
81 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
82 "Could not create Citizen lock");
86 int ret = pthread_rwlock_wrlock(&_lock);
88 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
89 "Could not acquire Citizen write lock");
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");
100 int ret = pthread_rwlock_unlock(&_lock);
102 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
103 "Could not release Citizen lock");
108 pthread_rwlock_t _lock;
111 static RwLock citizenLock;
115 ReadGuard(RwLock& lock) : _lock(lock) {
116 _mustUnlock = _lock.rdlock();
119 if (_mustUnlock) _lock.unlock();
129 WriteGuard(RwLock& lock) : _lock(lock) {
161 memId cid = _nextMemIdAndIncrement();
162 WriteGuard guard(citizenLock);
163 if (_shouldPersistCitizens()) {
164 _persistentCitizens[c] = std::make_pair(cid, pthread_self());
166 _activeCitizens[c] = std::make_pair(cid, pthread_self());
169 _newId += _newCallback(cid);
175 _sentinel(magicSentinel),
176 _CitizenId(_addCitizen(this)),
177 _typeName(type.name()) {
181 _sentinel(magicSentinel),
182 _CitizenId(_addCitizen(this)),
183 _typeName(citizen._typeName) {
188 WriteGuard guard(citizenLock);
189 if (_CitizenId == _deleteId) {
190 _deleteId += _deleteCallback(
this);
194 (void)_hasBeenCorrupted();
195 _sentinel = 0x0000dead;
197 bool corrupt =
false;
199 WriteGuard guard(citizenLock);
200 size_t nActive = _activeCitizens.erase(
this);
201 corrupt = nActive > 1 ||
202 (nActive == 0 && _persistentCitizens.erase(
this) != 1);
205 (void)_corruptionCallback(
this);
215 volatile int dummy = 1;
235 return perThreadId.getRef();
240 return perThreadId.getRef()++;
246 return boost::str(boost::format(
"%d: %08x %s")
249 % lsst::utils::demangleType(_typeName)
255 WriteGuard guard(citizenLock);
256 _persistentCitizens[
this] = _activeCitizens[
this];
257 _activeCitizens.erase(
this);
271 if (startingMemId == 0) {
272 ReadGuard guard(citizenLock);
273 return _activeCitizens.size();
277 ReadGuard guard(citizenLock);
278 for (table::iterator cur = _activeCitizens.begin();
279 cur != _activeCitizens.end(); cur++) {
280 if (cur->first->_CitizenId >= startingMemId) {
291 std::ostream &stream,
294 ReadGuard guard(citizenLock);
296 std::unique_ptr<std::vector<Citizen const*>
const> leaks(
Citizen::census());
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";
323 std::vector<Citizen const*>* vec =
324 new std::vector<Citizen const*>(0);
325 ReadGuard guard(citizenLock);
326 vec->reserve(_activeCitizens.size());
328 for (table::iterator cur = _activeCitizens.begin();
329 cur != _activeCitizens.end(); cur++) {
330 vec->push_back(dynamic_cast<Citizen const*>(cur->first));
333 std::sort(vec->begin(), vec->end(), cmpId);
343 bool dafBase::Citizen::_hasBeenCorrupted()
const {
344 if (_sentinel == static_cast<int>(magicSentinel)) {
348 (void)_corruptionCallback(
this);
354 ReadGuard guard(citizenLock);
355 for (table::iterator cur = _activeCitizens.begin();
356 cur != _activeCitizens.end(); cur++) {
357 if (cur->first->_hasBeenCorrupted()) {
361 for (table::iterator cur = _persistentCitizens.begin();
362 cur != _persistentCitizens.end(); cur++) {
363 if (cur->first->_hasBeenCorrupted()) {
379 WriteGuard guard(citizenLock);
390 WriteGuard guard(citizenLock);
426 _deleteCallback = func;
436 _corruptionCallback = func;
451 std::cerr << boost::format(
"Allocating memId %d\n") % cid;
460 std::cerr << boost::format(
"Deleting memId %s\n") % ptr->
repr();
468 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
469 str(boost::format(
"Citizen \"%s\" is corrupted") % ptr->
repr()));
474 bool& dafBase::Citizen::_shouldPersistCitizens(
void) {
475 return perThreadPersistFlag.getRef();
484 dafBase::Citizen::table dafBase::Citizen::_activeCitizens;
485 dafBase::Citizen::table dafBase::Citizen::_persistentCitizens;
493 Citizen::_shouldPersistCitizens() =
true;
497 Citizen::_shouldPersistCitizens() =
false;
unsigned long memId
Type of the block's ID.
static int init()
Called once when the memory system is being initialised.
~PersistentCitizenScope()
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
memId getId() const
Return the Citizen's ID.
memId(* memNewCallback)(const memId cid)
A function used to register a callback.
Called once when the memory system is being initialised.
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
memId(* memCallback)(const Citizen *ptr)
void markPersistent(void)
Mark a Citizen as persistent and not destroyed until process end.
std::string repr() const
Return a string representation of a Citizen.
static memId setNewCallbackId(memId id)
Call the NewCallback when block is allocated.
static memNewCallback setNewCallback(memNewCallback func)
Set the NewCallback function.
static bool hasBeenCorrupted()
Check all allocated blocks for corruption.
dafBase::Citizen::memId defaultNewCallback(dafBase::Citizen::memId const cid)
Default callbacks.
static memId setDeleteCallbackId(memId id)
Call the current DeleteCallback when block is deleted.
Citizen(const std::type_info &)
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
static const std::vector< const Citizen * > * census()
Return a (newly allocated) std::vector of active Citizens sorted by ID.
static memId getNextMemId()
Return the memId of the next object to be allocated.
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.