diff --git a/iceoryx_dust/include/iceoryx_dust/internal/singleton.inl b/iceoryx_dust/include/iceoryx_dust/internal/singleton.inl new file mode 100644 index 00000000000..0e8bf099ce4 --- /dev/null +++ b/iceoryx_dust/include/iceoryx_dust/internal/singleton.inl @@ -0,0 +1,123 @@ +// Copyright (c) 2022 by Apex.AI Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// SPDX-License-Identifier: Apache-2.0 + +#ifndef IOX_DUST_SINGLETON_INL +#define IOX_DUST_SINGLETON_INL + +#include "iceoryx_dust/singleton.hpp" + +namespace iox +{ + +template +bool Singleton::isInitialized() +{ + return ptr().load(std::memory_order_relaxed) != nullptr; +} + +template +template +T& Singleton::init(Args&&... args) +{ + std::lock_guard g(lock()); + if (!isInitialized()) + { + // initialized by this call + return *initialize(std::forward(args)...); + } + // initialized before by some other call + return *ptr().load(std::memory_order_acquire); +} + +template +void Singleton::destroy() +{ + std::lock_guard g(lock()); + auto p = ptr().load(std::memory_order_acquire); + if (p) + { + p->~T(); + ptr().store(nullptr); + } +} + +template +T& Singleton::instance() +{ + // need to sync the memory at *p as well + auto p = ptr().load(std::memory_order_acquire); + if (!p) + { + std::lock_guard g(lock()); + // could have been initialized in the meantime, + // so we double check under lock + auto p = ptr().load(); + if (p) + { + return *p; + } + + p = initialize(); // lazy default initialization + ptr().store(p, std::memory_order_release); + + // was initialized and stays initialized until destroy + return *p; + } + return *p; +} + +template +Singleton::~Singleton() +{ + destroy(); +} + +template +auto& Singleton::storage() +{ + static storage_t s; + return s; +} + +template +auto& Singleton::ptr() +{ + static std::atomic p; + return p; +} + +template +auto& Singleton::lock() +{ + static std::mutex m; + return m; +} + +template +template +T* Singleton::initialize(Args&&... args) +{ + static Singleton singleton; // dtor will be called later and call destroy + // NOLINTJUSTIFICATION implicit conversion from raw pointer is intentional in design of relocatable structures + // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) T dtor will be called by singleton dtor + auto p = new (&storage()) T(std::forward(args)...); + ptr().store(p, std::memory_order_relaxed); // memory synced by lock + return p; +} + +} // namespace iox + +#endif diff --git a/iceoryx_dust/include/iceoryx_dust/singleton.hpp b/iceoryx_dust/include/iceoryx_dust/singleton.hpp index 11dfd99660f..bd41f3d169d 100644 --- a/iceoryx_dust/include/iceoryx_dust/singleton.hpp +++ b/iceoryx_dust/include/iceoryx_dust/singleton.hpp @@ -92,101 +92,8 @@ class Singleton static T* initialize(Args&&... args); }; -template -bool Singleton::isInitialized() -{ - return ptr().load(std::memory_order_relaxed) != nullptr; -} - -template -template -T& Singleton::init(Args&&... args) -{ - std::lock_guard g(lock()); - if (!isInitialized()) - { - // initialized by this call - return *initialize(std::forward(args)...); - } - // initialized before by some other call - return *ptr().load(std::memory_order_acquire); -} - -template -void Singleton::destroy() -{ - std::lock_guard g(lock()); - auto p = ptr().load(std::memory_order_acquire); - if (p) - { - p->~T(); - ptr().store(nullptr); - } -} - -template -T& Singleton::instance() -{ - // need to sync the memory at *p as well - auto p = ptr().load(std::memory_order_acquire); - if (!p) - { - std::lock_guard g(lock()); - // could have been initialized in the meantime, - // so we double check under lock - auto p = ptr().load(); - if (p) - { - return *p; - } - - p = initialize(); // lazy default initialization - ptr().store(p, std::memory_order_release); - - // was initialized and stays initialized until destroy - return *p; - } - return *p; -} - -template -Singleton::~Singleton() -{ - destroy(); -} - -template -auto& Singleton::storage() -{ - static storage_t s; - return s; -} - -template -auto& Singleton::ptr() -{ - static std::atomic p; - return p; -} - -template -auto& Singleton::lock() -{ - static std::mutex m; - return m; -} - -template -template -T* Singleton::initialize(Args&&... args) -{ - static Singleton singleton; // dtor will be called later and call destroy - // NOLINTJUSTIFICATION implicit conversion from raw pointer is intentional in design of relocatable structures - // NOLINTNEXTLINE(cppcoreguidelines-owning-memory) T dtor will be called by singleton dtor - auto p = new (&storage()) T(std::forward(args)...); - ptr().store(p, std::memory_order_relaxed); // memory synced by lock - return p; -} } // namespace iox -#endif // IOX_DUST_SINGLETON_HPP \ No newline at end of file +#include "iceoryx_dust/internal/singleton.inl" + +#endif // IOX_DUST_SINGLETON_HPP