29 #include <boost/shared_ptr.hpp>
30 #include <boost/scoped_ptr.hpp>
31 #include <boost/format.hpp>
39 namespace dafBase = lsst::daf::base;
46 ThreadPrivate(T
const& t) : _init(t) {
47 int ret = pthread_key_create(&_key, del);
49 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
50 "Could not create key");
54 T* d =
reinterpret_cast<T*
>(pthread_getspecific(_key));
57 pthread_setspecific(_key, d);
66 static void del(
void* data) {
67 T* d =
reinterpret_cast<T*
>(data);
72 static ThreadPrivate<dafBase::Citizen::memId> perThreadId(1);
73 static ThreadPrivate<bool> perThreadPersistFlag(
false);
78 int ret = pthread_rwlock_init(&_lock, 0);
80 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
81 "Could not create Citizen lock");
85 int ret = pthread_rwlock_wrlock(&_lock);
87 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
88 "Could not acquire Citizen write lock");
92 int ret = pthread_rwlock_rdlock(&_lock);
93 if (ret == 0)
return true;
94 if (ret == EDEADLK)
return false;
95 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
96 "Could not acquire Citizen read lock");
99 int ret = pthread_rwlock_unlock(&_lock);
101 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
102 "Could not release Citizen lock");
107 pthread_rwlock_t _lock;
110 static RwLock citizenLock;
114 ReadGuard(RwLock& lock) : _lock(lock) {
115 _mustUnlock = _lock.rdlock();
118 if (_mustUnlock) _lock.unlock();
128 WriteGuard(RwLock& lock) : _lock(lock) {
161 WriteGuard guard(citizenLock);
174 _sentinel(magicSentinel),
175 _CitizenId(_addCitizen(this)),
176 _typeName(type.
name()) {
180 _sentinel(magicSentinel),
181 _CitizenId(_addCitizen(this)),
182 _typeName(citizen._typeName) {
187 WriteGuard guard(citizenLock);
188 if (_CitizenId == _deleteId) {
189 _deleteId += _deleteCallback(
this);
193 (void)_hasBeenCorrupted();
194 _sentinel = 0x0000dead;
196 bool corrupt =
false;
198 WriteGuard guard(citizenLock);
199 size_t nActive = _activeCitizens.erase(
this);
200 corrupt = nActive > 1 ||
201 (nActive == 0 && _persistentCitizens.erase(
this) != 1);
204 (void)_corruptionCallback(
this);
214 volatile int dummy = 1;
234 return perThreadId.getRef();
239 return perThreadId.getRef()++;
254 WriteGuard guard(citizenLock);
255 _persistentCitizens[
this] = _activeCitizens[
this];
256 _activeCitizens.erase(
this);
270 if (startingMemId == 0) {
271 ReadGuard guard(citizenLock);
272 return _activeCitizens.size();
276 ReadGuard guard(citizenLock);
277 for (table::iterator cur = _activeCitizens.begin();
278 cur != _activeCitizens.end(); cur++) {
279 if (cur->first->_CitizenId >= startingMemId) {
290 std::ostream &stream,
293 ReadGuard guard(citizenLock);
295 boost::scoped_ptr<std::vector<Citizen const*>
const> leaks(
Citizen::census());
297 for (std::vector<Citizen const *>::const_iterator citizen = leaks->begin(), end = leaks->end();
298 citizen != end; ++citizen) {
299 if ((*citizen)->getId() >= startingMemId) {
300 stream << (*citizen)->repr() <<
"\n";
322 std::vector<Citizen const*>* vec =
323 new std::vector<Citizen const*>(0);
324 ReadGuard guard(citizenLock);
325 vec->reserve(_activeCitizens.size());
327 for (table::iterator cur = _activeCitizens.begin();
328 cur != _activeCitizens.end(); cur++) {
329 vec->push_back(dynamic_cast<Citizen const*>(cur->first));
332 std::sort(vec->begin(), vec->end(), cmpId);
343 if (_sentinel == static_cast<int>(magicSentinel)) {
347 (void)_corruptionCallback(
this);
353 ReadGuard guard(citizenLock);
354 for (table::iterator cur = _activeCitizens.begin();
355 cur != _activeCitizens.end(); cur++) {
356 if (cur->first->_hasBeenCorrupted()) {
360 for (table::iterator cur = _persistentCitizens.begin();
361 cur != _persistentCitizens.end(); cur++) {
362 if (cur->first->_hasBeenCorrupted()) {
378 WriteGuard guard(citizenLock);
389 WriteGuard guard(citizenLock);
425 _deleteCallback = func;
435 _corruptionCallback = func;
467 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
474 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()
Include files required for standard LSST Exception handling.
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
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