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