diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 108ca27c1..c1f28a06d 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -64,6 +64,7 @@ set(base_SOURCES shared-object.hpp singleton.hpp socket.cpp socket.hpp + spinlock.cpp spinlock.hpp stacktrace.cpp stacktrace.hpp statsfunction.hpp stdiostream.cpp stdiostream.hpp diff --git a/lib/base/spinlock.cpp b/lib/base/spinlock.cpp new file mode 100644 index 000000000..03de2e6be --- /dev/null +++ b/lib/base/spinlock.cpp @@ -0,0 +1,22 @@ +/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */ + +#include "base/spinlock.hpp" +#include + +using namespace icinga; + +void SpinLock::lock() +{ + while (m_Locked.test_and_set(std::memory_order_acquire)) { + } +} + +bool SpinLock::try_lock() +{ + return !m_Locked.test_and_set(std::memory_order_acquire); +} + +void SpinLock::unlock() +{ + m_Locked.clear(std::memory_order_release); +} diff --git a/lib/base/spinlock.hpp b/lib/base/spinlock.hpp new file mode 100644 index 000000000..d6da5876e --- /dev/null +++ b/lib/base/spinlock.hpp @@ -0,0 +1,35 @@ +/* Icinga 2 | (c) 2020 Icinga GmbH | GPLv2+ */ + +#ifndef SPINLOCK_H +#define SPINLOCK_H + +#include + +namespace icinga +{ + +/** + * A spin lock. + * + * @ingroup base + */ +class SpinLock +{ +public: + SpinLock() = default; + SpinLock(const SpinLock&) = delete; + SpinLock& operator=(const SpinLock&) = delete; + SpinLock(SpinLock&&) = delete; + SpinLock& operator=(SpinLock&&) = delete; + + void lock(); + bool try_lock(); + void unlock(); + +private: + std::atomic_flag m_Locked = ATOMIC_FLAG_INIT; +}; + +} + +#endif /* SPINLOCK_H */ diff --git a/lib/remote/apilistener-filesync.cpp b/lib/remote/apilistener-filesync.cpp index 468c0038f..af56db4b3 100644 --- a/lib/remote/apilistener-filesync.cpp +++ b/lib/remote/apilistener-filesync.cpp @@ -20,7 +20,7 @@ using namespace icinga; REGISTER_APIFUNCTION(Update, config, &ApiListener::ConfigUpdateHandler); -boost::mutex ApiListener::m_ConfigSyncStageLock; +SpinLock ApiListener::m_ConfigSyncStageLock; /** * Entrypoint for updating all authoritative configs from /etc/zones.d, packages, etc. @@ -330,7 +330,7 @@ void ApiListener::HandleConfigUpdate(const MessageOrigin::Ptr& origin, const Dic /* Only one transaction is allowed, concurrent message handlers need to wait. * This affects two parent endpoints sending the config in the same moment. */ - auto lock (Shared::Make(m_ConfigSyncStageLock)); + auto lock (Shared>::Make(m_ConfigSyncStageLock)); String apiZonesStageDir = GetApiZonesStageDir(); String fromEndpointName = origin->FromClient->GetEndpoint()->GetName(); @@ -627,7 +627,7 @@ void ApiListener::TryActivateZonesStageCallback(const ProcessResult& pr, * * @param relativePaths Required for later file operations in the callback. Provides the zone name plus path in a list. */ -void ApiListener::AsyncTryActivateZonesStage(const std::vector& relativePaths, const Shared::Ptr& lock) +void ApiListener::AsyncTryActivateZonesStage(const std::vector& relativePaths, const Shared>::Ptr& lock) { VERIFY(Application::GetArgC() >= 1); diff --git a/lib/remote/apilistener.hpp b/lib/remote/apilistener.hpp index 4a3623a68..3205fa265 100644 --- a/lib/remote/apilistener.hpp +++ b/lib/remote/apilistener.hpp @@ -11,6 +11,7 @@ #include "base/configobject.hpp" #include "base/process.hpp" #include "base/shared.hpp" +#include "base/spinlock.hpp" #include "base/timer.hpp" #include "base/workqueue.hpp" #include "base/tcpsocket.hpp" @@ -21,6 +22,7 @@ #include #include #include +#include #include namespace icinga @@ -186,7 +188,7 @@ private: void RemoveStatusFile(); /* filesync */ - static boost::mutex m_ConfigSyncStageLock; + static SpinLock m_ConfigSyncStageLock; void SyncLocalZoneDirs() const; void SyncLocalZoneDir(const Zone::Ptr& zone) const; @@ -200,7 +202,7 @@ private: static void TryActivateZonesStageCallback(const ProcessResult& pr, const std::vector& relativePaths); - static void AsyncTryActivateZonesStage(const std::vector& relativePaths, const Shared::Ptr& lock); + static void AsyncTryActivateZonesStage(const std::vector& relativePaths, const Shared>::Ptr& lock); static String GetChecksum(const String& content); static bool CheckConfigChange(const ConfigDirInformation& oldConfig, const ConfigDirInformation& newConfig);