34 #include <boost/format.hpp>
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) {
162 WriteGuard guard(citizenLock);
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()++;
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);
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;
468 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
475 return perThreadPersistFlag.getRef();
unsigned long memId
Type of the block's ID.
std::string demangleType(std::string const _typeName)
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
table::Key< std::string > name
static int init()
Called once when the memory system is being initialised.
~PersistentCitizenScope()
memId getId() const
Return the Citizen's ID.
memId(* memNewCallback)(const memId cid)
A function used to register a callback.
dafBase::Citizen::memId defaultNewCallback(dafBase::Citizen::memId const cid)
Default NewCallback.
Called once when the memory system is being initialised.
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
std::map< Citizen const *, CitizenInfo > table
memId(* memCallback)(const Citizen *ptr)
static table _activeCitizens
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 & _shouldPersistCitizens()
Set the NewCallback function.
static bool hasBeenCorrupted()
Check all allocated blocks for corruption.
static memCallback _deleteCallback
static table _persistentCitizens
static memId setDeleteCallbackId(memId id)
Call the current DeleteCallback when block is deleted.
#define LSST_EXCEPT(type,...)
Citizen(const std::type_info &)
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.
static memId _nextMemIdAndIncrement(void)
Return the memId and prepare for the next object to be allocated.
afw::table::Key< double > b
static memId _nextMemId(void)
Return the memId of the next object to be allocated.
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
static memCallback _corruptionCallback
Include files required for standard LSST Exception handling.
static const std::vector< const Citizen * > * census()
Return a (newly allocated) std::vector of active Citizens sorted by ID.
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.
static memId _addCitizen(Citizen const *c)
static memNewCallback _newCallback
static memId getNextMemId()
Return the memId of the next object to be allocated.
bool _hasBeenCorrupted() const