34 #include <boost/format.hpp> 37 #include "lsst/pex/exceptions.h" 38 #include "lsst/utils/Demangle.h" 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()) {
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 {
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.
dafBase::Citizen::memId defaultDeleteCallback(dafBase::Citizen const *ptr)
Default DeleteCallback.
static int init()
Called once when the memory system is being initialised.
~PersistentCitizenScope()
dafBase::Citizen::memId defaultNewCallback(dafBase::Citizen::memId const cid)
Default callbacks.
Called once when the memory system is being initialised.
static memCallback setCorruptionCallback(memCallback func)
Set the CorruptionCallback function.
void markPersistent(void)
Mark a Citizen as persistent and not destroyed until process end.
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.
std::string repr() const
Return a string representation of a Citizen.
static memId setDeleteCallbackId(memId id)
Call the current DeleteCallback when block is deleted.
memId getId() const
Return the Citizen's ID.
memId(* memNewCallback)(const memId cid)
A function used to register a callback.
Citizen(const std::type_info &)
static memCallback setDeleteCallback(memCallback func)
Set the DeleteCallback function.
memId(* memCallback)(const Citizen *ptr)
Citizen is a class that should be among all LSST classes base classes, and handles basic memory manag...
dafBase::Citizen::memId defaultCorruptionCallback(dafBase::Citizen const *ptr)
Default CorruptionCallback.
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.