diff --git a/utils/messageqcpp/messagequeuepool.cpp b/utils/messageqcpp/messagequeuepool.cpp index 2debf46cd..25af41a5c 100644 --- a/utils/messageqcpp/messagequeuepool.cpp +++ b/utils/messageqcpp/messagequeuepool.cpp @@ -25,58 +25,41 @@ #include #include + namespace messageqcpp { using ClientMapType = std::multimap>; -template -struct Immortal +struct LockedClientMap { - template - Immortal(Args&&... args) - { - ::new (space) T(std::forward(args)...); - } - - operator T&() & noexcept - { - return reinterpret_cast(space); - } - - private: - alignas(T) unsigned char space[sizeof(T)]; -}; - -class LockedClientMap -{ - struct KeyToUsePrivateCtor - { - explicit KeyToUsePrivateCtor() = default; - }; - - public: - LockedClientMap(const LockedClientMap&) = delete; - LockedClientMap& operator=(const LockedClientMap&) = delete; - ~LockedClientMap() = delete; - - static LockedClientMap& getInstance() - { - static Immortal instance(KeyToUsePrivateCtor{}); - return instance; - } - - LockedClientMap(KeyToUsePrivateCtor) + LockedClientMap() + { + } + ~LockedClientMap() { } - - private: ClientMapType clientMap; std::mutex queueMutex; - - friend class MessageQueueClientPool; }; +static int clientMapNiftyCounter; + +static typename std::aligned_storage::type clientMapBuf; + +auto& lockedMap = reinterpret_cast(clientMapBuf); + + +LockedClientMapInitilizer::LockedClientMapInitilizer () +{ + if (clientMapNiftyCounter++ == 0) new (&lockedMap) LockedClientMap (); // placement new +} +LockedClientMapInitilizer::~LockedClientMapInitilizer () +{ + if (--clientMapNiftyCounter == 0) (&lockedMap)->~LockedClientMap(); +} + + // 300 seconds idle until cleanup #define MAX_IDLE_TIME 300 @@ -87,7 +70,7 @@ static uint64_t TimeSpecToSeconds(struct timespec* ts) MessageQueueClient* MessageQueueClientPool::getInstance(const std::string& dnOrIp, uint64_t port) { - auto lock = std::scoped_lock(LockedClientMap::getInstance().queueMutex); + auto lock = std::scoped_lock(lockedMap.queueMutex); std::ostringstream oss; oss << dnOrIp << "_" << port; @@ -110,13 +93,14 @@ MessageQueueClient* MessageQueueClientPool::getInstance(const std::string& dnOrI newClientObject->client.reset(new MessageQueueClient(dnOrIp, port)); newClientObject->inUse = true; newClientObject->lastUsed = nowSeconds; - LockedClientMap::getInstance().clientMap.emplace(std::move(searchString), std::move(newClientObject)); + lockedMap.clientMap.emplace(std::move(searchString), std::move(newClientObject)); return newClientObject->client.get(); } MessageQueueClient* MessageQueueClientPool::getInstance(const std::string& module) { - auto lock = std::scoped_lock(LockedClientMap::getInstance().queueMutex); + auto lock = std::scoped_lock(lockedMap.queueMutex); + MessageQueueClient* returnClient = MessageQueueClientPool::findInPool(module); @@ -132,11 +116,13 @@ MessageQueueClient* MessageQueueClientPool::getInstance(const std::string& modul clock_gettime(CLOCK_MONOTONIC, &now); uint64_t nowSeconds = TimeSpecToSeconds(&now); + + newClientObject->client.reset(new MessageQueueClient(module)); newClientObject->inUse = true; newClientObject->lastUsed = nowSeconds; auto result = newClientObject->client.get(); - LockedClientMap::getInstance().clientMap.emplace(std::move(module), std::move(newClientObject)); + lockedMap.clientMap.emplace(std::move(module), std::move(newClientObject)); return result; } @@ -147,10 +133,11 @@ MessageQueueClient* MessageQueueClientPool::findInPool(const std::string& search uint64_t nowSeconds = TimeSpecToSeconds(&now); MessageQueueClient* returnClient = NULL; - auto it = LockedClientMap::getInstance().clientMap.begin(); + auto it = lockedMap.clientMap.begin(); + // Scan pool - while (it != LockedClientMap::getInstance().clientMap.end()) + while (it != lockedMap.clientMap.end()) { ClientObject* clientObject = it->second.get(); uint64_t elapsedTime = nowSeconds - clientObject->lastUsed; @@ -162,7 +149,7 @@ MessageQueueClient* MessageQueueClientPool::findInPool(const std::string& search // Do this so we don't invalidate current interator auto toDelete = it; it++; - LockedClientMap::getInstance().clientMap.erase(toDelete); + lockedMap.clientMap.erase(toDelete); continue; } @@ -176,7 +163,7 @@ MessageQueueClient* MessageQueueClientPool::findInPool(const std::string& search // Do this so we don't invalidate current interator auto toDelete = it; it++; - LockedClientMap::getInstance().clientMap.erase(toDelete); + lockedMap.clientMap.erase(toDelete); continue; } } @@ -206,10 +193,10 @@ void MessageQueueClientPool::releaseInstance(MessageQueueClient* client) if (client == NULL) return; - auto lock = std::scoped_lock(LockedClientMap::getInstance().queueMutex); - auto it = LockedClientMap::getInstance().clientMap.begin(); + auto lock = std::scoped_lock(lockedMap.queueMutex); + auto it = lockedMap.clientMap.begin(); - while (it != LockedClientMap::getInstance().clientMap.end()) + while (it != lockedMap.clientMap.end()) { if (it->second->client.get() == client) { @@ -234,14 +221,15 @@ void MessageQueueClientPool::deleteInstance(MessageQueueClient* client) if (client == NULL) return; - auto lock = std::scoped_lock(LockedClientMap::getInstance().queueMutex); - auto it = LockedClientMap::getInstance().clientMap.begin(); - while (it != LockedClientMap::getInstance().clientMap.end()) + auto lock = std::scoped_lock(lockedMap.queueMutex); + auto it = lockedMap.clientMap.begin(); + + while (it != lockedMap.clientMap.end()) { if (it->second->client.get() == client) { - LockedClientMap::getInstance().clientMap.erase(it); + lockedMap.clientMap.erase(it); return; } diff --git a/utils/messageqcpp/messagequeuepool.h b/utils/messageqcpp/messagequeuepool.h index 6af5e1cc6..17899b76a 100644 --- a/utils/messageqcpp/messagequeuepool.h +++ b/utils/messageqcpp/messagequeuepool.h @@ -26,6 +26,12 @@ namespace messageqcpp { + +static struct LockedClientMapInitilizer { + LockedClientMapInitilizer (); + ~LockedClientMapInitilizer (); +} clientMapInitilizer; // static initializer for every translation unit + struct ClientObject { std::unique_ptr client; @@ -43,8 +49,8 @@ class MessageQueueClientPool static MessageQueueClient* findInPool(const std::string& search); private: - MessageQueueClientPool() {}; - ~MessageQueueClientPool() {}; + MessageQueueClientPool(){}; + ~MessageQueueClientPool(){}; }; } // namespace messageqcpp