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();
std::string demangleType(std::string const _typeName)
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
Citizen(const std::type_info &)
table::Key< std::string > name
static memId setDeleteCallbackId(memId id)
Call the current DeleteCallback when block is deleted.
Include files required for standard LSST Exception handling.
static table _activeCitizens
dafBase::Citizen::memId defaultNewCallback(dafBase::Citizen::memId const cid)
Default callbacks.
Called once when the memory system is being initialised.
static memId getNextMemId()
Return the memId of the next object to be allocated.
static const std::vector< const Citizen * > * census()
Return a (newly allocated) std::vector of active Citizens sorted by ID.
static memId _nextMemIdAndIncrement(void)
Return the memId and prepare for the next object to be allocated.
static memNewCallback _newCallback
static memId _addCitizen(Citizen const *c)
static table _persistentCitizens
static bool hasBeenCorrupted()
Check all allocated blocks for corruption.
static bool & _shouldPersistCitizens()
Set the NewCallback function.
metadata import lsst afw display as afwDisplay n
std::map< Citizen const *, CitizenInfo > table
~PersistentCitizenScope()
static memCallback _corruptionCallback
bool _hasBeenCorrupted() const
Check for corruption Return true if the block is corrupted, but only after calling the corruptionCall...
void markPersistent(void)
Mark a Citizen as persistent and not destroyed until process end.
static int init()
Called once when the memory system is being initialised.
static memCallback _deleteCallback
static memId _nextMemId(void)
Return the memId of the next object to be allocated.
#define LSST_EXCEPT(type,...)
Create an exception with a given type and message and optionally other arguments (dependent on the ty...
std::string repr() const
Return a string representation of a Citizen.
static memId setNewCallbackId(memId id)
Call the NewCallback when block is allocated.
memId(* memCallback)(const Citizen *ptr)
memId(* memNewCallback)(const memId cid)
A function used to register a callback.
afw::table::Key< double > b
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
unsigned long memId
Type of the block's ID.
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
memId getId() const
Return the Citizen's ID.
static memNewCallback setNewCallback(memNewCallback func)
Set the NewCallback function.
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.