#include #include #include "../shared/MiscSupport.h" #include "../shared/Random.h" #include "NamedReference.h" ///////////////////////////////////////////////////////////////////// // HasNamedReference ///////////////////////////////////////////////////////////////////// uint64_t HasNamedReference::_nextId = 0; std::string HasNamedReference::createName() { std::string result = ntoa(__sync_fetch_and_add(&_nextId, 1)); result += 'h'; result += ntoa(getRandom64()); return result; } // This is, more or less, what pthread_self() does. It does not require any // system calls. It's using the FS segment register, which has a pointer to // thread local storage. pthread_self() has a lot of issues. It's a pain to // compare two values. While there is a NULL value, pthread_self doesn't // export that. In my system I know that no thread will have NULL for its id. static __thread bool tls; inline void *getThreadId() { return &tls; } HasNamedReference::HasNamedReference(bool onlyThisThread) : _name(createName()), _threadId(onlyThisThread?getThreadId():NULL) { } std::string HasNamedReference::getTypeName() const { return typeid(*this).name(); } bool HasNamedReference::correctThread() const { if (!_threadId) // Thread safe. Can be used anywhere. return true; return _threadId == getThreadId(); } ///////////////////////////////////////////////////////////////////// // NamedReference ///////////////////////////////////////////////////////////////////// std::map< std::string, NamedReference::Container * > NamedReference::_allNames; std::string NamedReference::s_NULL = "NULL"; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void NamedReference::initializeNotNull(HasNamedReference *basePointer) { assert(basePointer); _container = new Container; _container->count = 1; _container->basePointer = basePointer; pthread_mutex_lock(&mutex); const bool notPreviouslyPresent = _allNames.insert(std::pair< std::string, Container *> (basePointer->getName(), _container)).second; pthread_mutex_unlock(&mutex); assert(notPreviouslyPresent); } void NamedReference::destroy() { assert(_container); pthread_mutex_lock(&mutex); if (_container->count == 0) { _allNames.erase(_container->basePointer->getName()); delete _container->basePointer; delete _container; } pthread_mutex_unlock(&mutex); } NamedReference NamedReference::find(std::string const &name) { NamedReference result; pthread_mutex_lock(&mutex); auto it = _allNames.find(name); if (it != _allNames.end()) { // Found! Now check if it's accessible in this thread. if (it->second->basePointer->correctThread()) { // Copy it and bump the reference count. result._container = it->second; result.increment(); } } pthread_mutex_unlock(&mutex); return result; } uint64_t NamedReference::getObjectCount() { pthread_mutex_lock(&mutex); static const uint64_t result = _allNames.size(); pthread_mutex_unlock(&mutex); return result; } std::vector< std::string > NamedReference::getAllNames() { std::vector< std::string > result; pthread_mutex_lock(&mutex); for (auto &kvp : _allNames) result.push_back(kvp.second->basePointer->getName()); pthread_mutex_unlock(&mutex); return result; }