Commit a5575438 authored by Dominik Charousset's avatar Dominik Charousset

Make actor flags atomic to silence false positives

Use `atomic<int>` instead of `int` for `local_actor::m_flags`. The atomic uses
only relaxed memory ordering, since all flags that are allowed to be read by
others never change after an actor has launched. This should produce the same
compiler output as before---at least on x86 or any platform with atomic
load/store for word sized memory regions---but suppresses false positives from
analyser tools such as Thread Sanitizer. Close #255.
parent ea75c71d
...@@ -207,24 +207,22 @@ class abstract_actor : public abstract_channel { ...@@ -207,24 +207,22 @@ class abstract_actor : public abstract_channel {
remove_backlink_op remove_backlink_op
}; };
enum actor_state_flag { // used by ...
// used by ... static constexpr int trap_exit_flag = 0x01; // local_actor
trap_exit_flag = 0x01, // local_actor static constexpr int has_timeout_flag = 0x02; // single_timeout
has_timeout_flag = 0x02, // mixin::single_timeout static constexpr int is_registered_flag = 0x04; // (several actors)
is_registered_flag = 0x04, // no_resume, resumable, and scoped_actor static constexpr int is_initialized_flag = 0x08; // event-based actors
is_initialized_flag = 0x08, // event-based actors static constexpr int is_blocking_flag = 0x10; // blocking_actor
is_blocking_flag = 0x10, // blocking_actor static constexpr int is_detached_flag = 0x20; // local_actor
is_detached_flag = 0x20, // local_actor (set by spawn) static constexpr int is_priority_aware_flag = 0x40; // local_actor
is_priority_aware_flag = 0x40 // local_actor (set by spawn)
}; inline void set_flag(bool enable_flag, int mask) {
auto x = flags();
inline void set_flag(bool enable_flag, actor_state_flag mask) { flags(enable_flag ? x | mask : x & ~mask);
m_flags = enable_flag ? m_flags | static_cast<int>(mask)
: m_flags & ~static_cast<int>(mask);
} }
inline bool get_flag(actor_state_flag mask) const { inline bool get_flag(int mask) const {
return static_cast<bool>(m_flags & static_cast<int>(mask)); return static_cast<bool>(flags() & mask);
} }
inline bool has_timeout() const { inline bool has_timeout() const {
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#ifndef CAF_ABSTRACT_CHANNEL_HPP #ifndef CAF_ABSTRACT_CHANNEL_HPP
#define CAF_ABSTRACT_CHANNEL_HPP #define CAF_ABSTRACT_CHANNEL_HPP
#include <atomic>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/node_id.hpp" #include "caf/node_id.hpp"
#include "caf/message_id.hpp" #include "caf/message_id.hpp"
...@@ -66,32 +68,44 @@ class abstract_channel : public ref_counted { ...@@ -66,32 +68,44 @@ class abstract_channel : public ref_counted {
*/ */
bool is_remote() const; bool is_remote() const;
enum channel_type_flag { static constexpr int is_abstract_actor_flag = 0x100000;
is_abstract_actor_flag = 0x100000,
is_abstract_group_flag = 0x200000 static constexpr int is_abstract_group_flag = 0x200000;
};
inline bool is_abstract_actor() const { inline bool is_abstract_actor() const {
return m_flags & static_cast<int>(is_abstract_actor_flag); return flags() & static_cast<int>(is_abstract_actor_flag);
} }
inline bool is_abstract_group() const { inline bool is_abstract_group() const {
return m_flags & static_cast<int>(is_abstract_group_flag); return flags() & static_cast<int>(is_abstract_group_flag);
} }
protected: protected:
/** // note: *both* operations use relaxed memory order, this is because
// only the actor itself is granted write access while all access
// from other actors or threads is always read-only; further, only
// flags that are considered constant after an actor has launched are
// read by others, i.e., there is no acquire/release semantic between
// setting and reading flags
inline int flags() const {
return m_flags.load(std::memory_order_relaxed);
}
inline void flags(int new_value) {
m_flags.store(new_value, std::memory_order_relaxed);
}
private:
// can only be called from abstract_actor and abstract_group
abstract_channel(int init_flags);
abstract_channel(int init_flags, node_id nid);
/*
* Accumulates several state and type flags. Subtypes may use only the * Accumulates several state and type flags. Subtypes may use only the
* first 20 bits, i.e., the bitmask 0xFFF00000 is reserved for * first 20 bits, i.e., the bitmask 0xFFF00000 is reserved for
* channel-related flags. * channel-related flags.
*/ */
int m_flags; std::atomic<int> m_flags;
private:
// can only be called from abstract_actor and abstract_group
abstract_channel(channel_type_flag subtype);
abstract_channel(channel_type_flag subtype, node_id nid);
// identifies the node of this channel // identifies the node of this channel
node_id m_node; node_id m_node;
}; };
......
...@@ -26,14 +26,14 @@ namespace caf { ...@@ -26,14 +26,14 @@ namespace caf {
using detail::singletons; using detail::singletons;
abstract_channel::abstract_channel(channel_type_flag subtype) abstract_channel::abstract_channel(int init_flags)
: m_flags(static_cast<int>(subtype)), : m_flags(init_flags),
m_node(singletons::get_node_id()) { m_node(singletons::get_node_id()) {
// nop // nop
} }
abstract_channel::abstract_channel(channel_type_flag subtype, node_id nid) abstract_channel::abstract_channel(int init_flags, node_id nid)
: m_flags(static_cast<int>(subtype)), : m_flags(init_flags),
m_node(std::move(nid)) { m_node(std::move(nid)) {
// nop // nop
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment