Merge pull request #9364 from Icinga/bugfix/atomic-members

Replace `EventuallyAtomic` with `AtomicOrLocked` which falls back to a mutex
This commit is contained in:
Julian Brost 2022-05-05 13:19:03 +02:00 committed by GitHub
commit f610289b3f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 47 additions and 67 deletions

View File

@ -4,6 +4,7 @@
#define ATOMIC_H #define ATOMIC_H
#include <atomic> #include <atomic>
#include <mutex>
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
@ -41,78 +42,49 @@ public:
}; };
/** /**
* Wraps T into a std::atomic<T>-like interface. * Wraps any T into a std::atomic<T>-like interface that locks using a mutex.
*
* In contrast to std::atomic<T>, Locked<T> is also valid for types that are not trivially copyable.
* In case T is trivially copyable, std::atomic<T> is almost certainly the better choice.
* *
* @ingroup base * @ingroup base
*/ */
template<class T> template<typename T>
class NotAtomic class Locked
{ {
public: public:
inline T load() const inline T load() const
{ {
std::unique_lock<std::mutex> lock(m_Mutex);
return m_Value; return m_Value;
} }
inline void store(T desired) inline void store(T desired)
{ {
std::unique_lock<std::mutex> lock(m_Mutex);
m_Value = std::move(desired); m_Value = std::move(desired);
} }
private:
mutable std::mutex m_Mutex;
T m_Value; T m_Value;
}; };
/** /**
* Tells whether to use std::atomic<T> or NotAtomic<T>. * Type alias for std::atomic<T> if possible, otherwise Locked<T> is used as a fallback.
* *
* @ingroup base * @ingroup base
*/ */
template<class T> template <typename T>
struct Atomicable using AtomicOrLocked =
{ #if defined(__GNUC__) && __GNUC__ < 5
// Doesn't work with too old compilers. // GCC does not implement std::is_trivially_copyable until version 5.
//static constexpr bool value = std::is_trivially_copyable<T>::value && sizeof(T) <= sizeof(void*); typename std::conditional<std::is_fundamental<T>::value || std::is_pointer<T>::value, std::atomic<T>, Locked<T>>::type;
static constexpr bool value = (std::is_fundamental<T>::value || std::is_pointer<T>::value) && sizeof(T) <= sizeof(void*); #else /* defined(__GNUC__) && __GNUC__ < 5 */
}; typename std::conditional<std::is_trivially_copyable<T>::value, std::atomic<T>, Locked<T>>::type;
#endif /* defined(__GNUC__) && __GNUC__ < 5 */
/**
* Uses either std::atomic<T> or NotAtomic<T> depending on atomicable.
*
* @ingroup base
*/
template<bool atomicable>
struct AtomicTemplate;
template<>
struct AtomicTemplate<false>
{
template<class T>
struct tmplt
{
typedef NotAtomic<T> type;
};
};
template<>
struct AtomicTemplate<true>
{
template<class T>
struct tmplt
{
typedef std::atomic<T> type;
};
};
/**
* Uses either std::atomic<T> or NotAtomic<T> depending on T.
*
* @ingroup base
*/
template<class T>
struct EventuallyAtomic
{
typedef typename AtomicTemplate<Atomicable<T>::value>::template tmplt<T>::type type;
};
} }

View File

@ -59,10 +59,11 @@ abstract class ConfigObject : ConfigObjectBase < ConfigType
[config, no_user_modify] String __name (Name); [config, no_user_modify] String __name (Name);
[config, no_user_modify] String "name" (ShortName) { [config, no_user_modify] String "name" (ShortName) {
get {{{ get {{{
if (m_ShortName.m_Value.IsEmpty()) String shortName = m_ShortName.load();
if (shortName.IsEmpty())
return GetName(); return GetName();
else else
return m_ShortName.m_Value; return shortName;
}}} }}}
}; };
[config, no_user_modify] name(Zone) zone (ZoneName); [config, no_user_modify] name(Zone) zone (ZoneName);

View File

@ -21,10 +21,11 @@ class Host : Checkable
[config] String display_name { [config] String display_name {
get {{{ get {{{
if (m_DisplayName.m_Value.IsEmpty()) String displayName = m_DisplayName.load();
if (displayName.IsEmpty())
return GetName(); return GetName();
else else
return m_DisplayName.m_Value; return displayName;
}}} }}}
}; };

View File

@ -11,10 +11,11 @@ class HostGroup : CustomVarObject
{ {
[config] String display_name { [config] String display_name {
get {{{ get {{{
if (m_DisplayName.m_Value.IsEmpty()) String displayName = m_DisplayName.load();
if (displayName.IsEmpty())
return GetName(); return GetName();
else else
return m_DisplayName.m_Value; return displayName;
}}} }}}
}; };

View File

@ -33,10 +33,11 @@ class Service : Checkable < ServiceNameComposer
[config] String display_name { [config] String display_name {
get {{{ get {{{
if (m_DisplayName.m_Value.IsEmpty()) String displayName = m_DisplayName.load();
if (displayName.IsEmpty())
return GetShortName(); return GetShortName();
else else
return m_DisplayName.m_Value; return displayName;
}}} }}}
}; };
[config, required] name(Host) host_name; [config, required] name(Host) host_name;

View File

@ -11,10 +11,11 @@ class ServiceGroup : CustomVarObject
{ {
[config] String display_name { [config] String display_name {
get {{{ get {{{
if (m_DisplayName.m_Value.IsEmpty()) String displayName = m_DisplayName.load();
if (displayName.IsEmpty())
return GetName(); return GetName();
else else
return m_DisplayName.m_Value; return displayName;
}}} }}}
}; };

View File

@ -12,10 +12,11 @@ class TimePeriod : CustomVarObject
{ {
[config] String display_name { [config] String display_name {
get {{{ get {{{
if (m_DisplayName.m_Value.IsEmpty()) String displayName = m_DisplayName.load();
if (displayName.IsEmpty())
return GetName(); return GetName();
else else
return m_DisplayName.m_Value; return displayName;
}}} }}}
}; };
[config, signal_with_old_value] Dictionary::Ptr ranges; [config, signal_with_old_value] Dictionary::Ptr ranges;

View File

@ -13,10 +13,11 @@ class User : CustomVarObject
{ {
[config] String display_name { [config] String display_name {
get {{{ get {{{
if (m_DisplayName.m_Value.IsEmpty()) String displayName = m_DisplayName.load();
if (displayName.IsEmpty())
return GetName(); return GetName();
else else
return m_DisplayName.m_Value; return displayName;
}}} }}}
}; };
[config, no_user_modify, required, signal_with_old_value] array(name(UserGroup)) groups { [config, no_user_modify, required, signal_with_old_value] array(name(UserGroup)) groups {

View File

@ -11,10 +11,11 @@ class UserGroup : CustomVarObject
{ {
[config] String display_name { [config] String display_name {
get {{{ get {{{
if (m_DisplayName.m_Value.IsEmpty()) String displayName = m_DisplayName.load();
if (displayName.IsEmpty())
return GetName(); return GetName();
else else
return m_DisplayName.m_Value; return displayName;
}}} }}}
}; };

View File

@ -1060,7 +1060,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&)
if (field.Attributes & FANoStorage) if (field.Attributes & FANoStorage)
continue; continue;
m_Header << "\tEventuallyAtomic<" << field.Type.GetRealType() << ">::type m_" << field.GetFriendlyName() << ";" << std::endl; m_Header << "\tAtomicOrLocked<" << field.Type.GetRealType() << "> m_" << field.GetFriendlyName() << ";" << std::endl;
} }
/* signal */ /* signal */