diff --git a/lib/base/atomic.hpp b/lib/base/atomic.hpp index 0ebcddefb..c8f169c0b 100644 --- a/lib/base/atomic.hpp +++ b/lib/base/atomic.hpp @@ -4,6 +4,9 @@ #define ATOMIC_H #include +#include +#include +#include namespace icinga { @@ -38,6 +41,51 @@ public: } }; +/** + * Wraps any T into a std::atomic-like interface that locks using a mutex. + * + * In contrast to std::atomic, Locked is also valid for types that are not trivially copyable. + * In case T is trivially copyable, std::atomic is almost certainly the better choice. + * + * @ingroup base + */ +template +class Locked +{ +public: + inline T load() const + { + std::unique_lock lock(m_Mutex); + + return m_Value; + } + + inline void store(T desired) + { + std::unique_lock lock(m_Mutex); + + m_Value = std::move(desired); + } + +private: + mutable std::mutex m_Mutex; + T m_Value; +}; + +/** + * Type alias for std::atomic if possible, otherwise Locked is used as a fallback. + * + * @ingroup base + */ +template +using AtomicOrLocked = +#if defined(__GNUC__) && __GNUC__ < 5 + // GCC does not implement std::is_trivially_copyable until version 5. + typename std::conditional::value || std::is_pointer::value, std::atomic, Locked>::type; +#else /* defined(__GNUC__) && __GNUC__ < 5 */ + typename std::conditional::value, std::atomic, Locked>::type; +#endif /* defined(__GNUC__) && __GNUC__ < 5 */ + } #endif /* ATOMIC_H */ diff --git a/lib/base/configobject.ti b/lib/base/configobject.ti index fcfcb0223..19b7cde83 100644 --- a/lib/base/configobject.ti +++ b/lib/base/configobject.ti @@ -59,10 +59,11 @@ abstract class ConfigObject : ConfigObjectBase < ConfigType [config, no_user_modify] String __name (Name); [config, no_user_modify] String "name" (ShortName) { get {{{ - if (m_ShortName.IsEmpty()) + String shortName = m_ShortName.load(); + if (shortName.IsEmpty()) return GetName(); else - return m_ShortName; + return shortName; }}} }; [config, no_user_modify] name(Zone) zone (ZoneName); diff --git a/lib/icinga/host.ti b/lib/icinga/host.ti index 03c606228..de47c1b59 100644 --- a/lib/icinga/host.ti +++ b/lib/icinga/host.ti @@ -21,10 +21,11 @@ class Host : Checkable [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + String displayName = m_DisplayName.load(); + if (displayName.IsEmpty()) return GetName(); else - return m_DisplayName; + return displayName; }}} }; diff --git a/lib/icinga/hostgroup.ti b/lib/icinga/hostgroup.ti index a4404eafe..b679344aa 100644 --- a/lib/icinga/hostgroup.ti +++ b/lib/icinga/hostgroup.ti @@ -11,10 +11,11 @@ class HostGroup : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + String displayName = m_DisplayName.load(); + if (displayName.IsEmpty()) return GetName(); else - return m_DisplayName; + return displayName; }}} }; diff --git a/lib/icinga/service.ti b/lib/icinga/service.ti index bab1ebc8f..45fa98ea2 100644 --- a/lib/icinga/service.ti +++ b/lib/icinga/service.ti @@ -33,10 +33,11 @@ class Service : Checkable < ServiceNameComposer [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + String displayName = m_DisplayName.load(); + if (displayName.IsEmpty()) return GetShortName(); else - return m_DisplayName; + return displayName; }}} }; [config, required] name(Host) host_name; diff --git a/lib/icinga/servicegroup.ti b/lib/icinga/servicegroup.ti index 69f300508..7daf9d419 100644 --- a/lib/icinga/servicegroup.ti +++ b/lib/icinga/servicegroup.ti @@ -11,10 +11,11 @@ class ServiceGroup : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + String displayName = m_DisplayName.load(); + if (displayName.IsEmpty()) return GetName(); else - return m_DisplayName; + return displayName; }}} }; diff --git a/lib/icinga/timeperiod.ti b/lib/icinga/timeperiod.ti index 27365988e..6729a4a6a 100644 --- a/lib/icinga/timeperiod.ti +++ b/lib/icinga/timeperiod.ti @@ -12,10 +12,11 @@ class TimePeriod : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + String displayName = m_DisplayName.load(); + if (displayName.IsEmpty()) return GetName(); else - return m_DisplayName; + return displayName; }}} }; [config] Dictionary::Ptr ranges; diff --git a/lib/icinga/user.ti b/lib/icinga/user.ti index 450d95358..f1b3faa6b 100644 --- a/lib/icinga/user.ti +++ b/lib/icinga/user.ti @@ -13,10 +13,11 @@ class User : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + String displayName = m_DisplayName.load(); + if (displayName.IsEmpty()) return GetName(); else - return m_DisplayName; + return displayName; }}} }; [config, no_user_modify, required] array(name(UserGroup)) groups { diff --git a/lib/icinga/usergroup.ti b/lib/icinga/usergroup.ti index 311932171..e955c5e5e 100644 --- a/lib/icinga/usergroup.ti +++ b/lib/icinga/usergroup.ti @@ -11,10 +11,11 @@ class UserGroup : CustomVarObject { [config] String display_name { get {{{ - if (m_DisplayName.IsEmpty()) + String displayName = m_DisplayName.load(); + if (displayName.IsEmpty()) return GetName(); else - return m_DisplayName; + return displayName; }}} }; diff --git a/tools/mkclass/classcompiler.cpp b/tools/mkclass/classcompiler.cpp index fd30df8e1..acd9e390b 100644 --- a/tools/mkclass/classcompiler.cpp +++ b/tools/mkclass/classcompiler.cpp @@ -797,7 +797,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) << "{" << std::endl; if (field.GetAccessor.empty() && !(field.Attributes & FANoStorage)) - m_Impl << "\t" << "return m_" << field.GetFriendlyName() << ";" << std::endl; + m_Impl << "\t" << "return m_" << field.GetFriendlyName() << ".load();" << std::endl; else m_Impl << field.GetAccessor << std::endl; @@ -835,7 +835,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) if (field.SetAccessor.empty() && !(field.Attributes & FANoStorage)) - m_Impl << "\t" << "m_" << field.GetFriendlyName() << " = value;" << std::endl; + m_Impl << "\t" << "m_" << field.GetFriendlyName() << ".store(value);" << std::endl; else m_Impl << field.SetAccessor << std::endl << std::endl; @@ -1044,7 +1044,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) if (field.Attributes & FANoStorage) continue; - m_Header << "\t" << field.Type.GetRealType() << " m_" << field.GetFriendlyName() << ";" << std::endl; + m_Header << "\tAtomicOrLocked<" << field.Type.GetRealType() << "> m_" << field.GetFriendlyName() << ";" << std::endl; } /* signal */ @@ -1431,6 +1431,7 @@ void ClassCompiler::CompileStream(const std::string& path, std::istream& input, << "#include \"base/type.hpp\"" << std::endl << "#include \"base/value.hpp\"" << std::endl << "#include \"base/array.hpp\"" << std::endl + << "#include \"base/atomic.hpp\"" << std::endl << "#include \"base/dictionary.hpp\"" << std::endl << "#include " << std::endl << std::endl;