Commit 47dd7cad authored by Dominik Charousset's avatar Dominik Charousset

Garbage collect actors using weak pointers

Give actor_addr weak pointer semantics to break loops when linking two actors
and to avoid keeping actors alive only by monitoring them. Use strong_actor_ptr
wherever a type-erased form of actor or typed_actor<...> is needed.

Relates #420.
parent 2341e313
...@@ -13,25 +13,37 @@ endif() ...@@ -13,25 +13,37 @@ endif()
if(NOT CAF_ENABLE_RUNTIME_CHECKS) if(NOT CAF_ENABLE_RUNTIME_CHECKS)
set(CAF_ENABLE_RUNTIME_CHECKS no) set(CAF_ENABLE_RUNTIME_CHECKS no)
endif() endif()
if(NOT CAF_NO_MEM_MANAGEMENT) if(NOT CAF_NO_MEM_MANAGEMENT)
set(CAF_NO_MEM_MANAGEMENT no) set(CAF_NO_MEM_MANAGEMENT no)
endif() endif()
if(NOT CAF_BUILD_STATIC_ONLY) if(NOT CAF_BUILD_STATIC_ONLY)
set(CAF_BUILD_STATIC_ONLY no) set(CAF_BUILD_STATIC_ONLY no)
endif() endif()
if(NOT CAF_BUILD_STATIC) if(NOT CAF_BUILD_STATIC)
set(CAF_BUILD_STATIC no) set(CAF_BUILD_STATIC no)
endif() endif()
if(NOT CAF_NO_OPENCL) if(NOT CAF_NO_OPENCL)
set(CAF_NO_OPENCL no) set(CAF_NO_OPENCL no)
endif() endif()
if(NOT CAF_NO_TOOLS) if(NOT CAF_NO_TOOLS)
set(CAF_NO_TOOLS no) set(CAF_NO_TOOLS no)
endif() endif()
if(NOT CAF_NO_SUMMARY) if(NOT CAF_NO_SUMMARY)
set(CAF_NO_SUMMARY no) set(CAF_NO_SUMMARY no)
endif() endif()
if(NOT CAF_NO_IO)
set(CAF_NO_IO no)
else()
set(CAF_NO_RIAC yes)
set(CAF_NO_TOOLS yes)
endif()
################################################################################ ################################################################################
# get version of CAF # # get version of CAF #
...@@ -429,7 +441,7 @@ endmacro() ...@@ -429,7 +441,7 @@ endmacro()
# build core and I/O library # build core and I/O library
add_caf_lib(core) add_caf_lib(core)
add_caf_lib(io) add_optional_caf_lib(io)
# build opencl library if not told otherwise and OpenCL package was found # build opencl library if not told otherwise and OpenCL package was found
if(NOT CAF_NO_OPENCL) if(NOT CAF_NO_OPENCL)
...@@ -570,6 +582,7 @@ macro(invertYesNo in out) ...@@ -570,6 +582,7 @@ macro(invertYesNo in out)
endif() endif()
endmacro() endmacro()
# invert CAF_NO_* variables for nicer output # invert CAF_NO_* variables for nicer output
invertYesNo(CAF_NO_IO CAF_BUILD_IO)
invertYesNo(CAF_NO_EXAMPLES CAF_BUILD_EXAMPLES) invertYesNo(CAF_NO_EXAMPLES CAF_BUILD_EXAMPLES)
invertYesNo(CAF_NO_TOOLS CAF_BUILD_TOOLS) invertYesNo(CAF_NO_TOOLS CAF_BUILD_TOOLS)
invertYesNo(CAF_NO_UNIT_TESTS CAF_BUILD_UNIT_TESTS) invertYesNo(CAF_NO_UNIT_TESTS CAF_BUILD_UNIT_TESTS)
...@@ -596,6 +609,7 @@ if(NOT CAF_NO_SUMMARY) ...@@ -596,6 +609,7 @@ if(NOT CAF_NO_SUMMARY)
"\nLog level: ${LOG_LEVEL_STR}" "\nLog level: ${LOG_LEVEL_STR}"
"\nWith mem. mgmt.: ${CAF_BUILD_MEM_MANAGEMENT}" "\nWith mem. mgmt.: ${CAF_BUILD_MEM_MANAGEMENT}"
"\n" "\n"
"\nBuild I/O module: ${CAF_BUILD_IO}"
"\nBuild tools: ${CAF_BUILD_TOOLS}" "\nBuild tools: ${CAF_BUILD_TOOLS}"
"\nBuild examples: ${CAF_BUILD_EXAMPLES}" "\nBuild examples: ${CAF_BUILD_EXAMPLES}"
"\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}" "\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}"
......
...@@ -60,12 +60,13 @@ Usage: $0 [OPTION]... [VAR=VALUE]... ...@@ -60,12 +60,13 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--no-protobuf-examples build without Google Protobuf examples --no-protobuf-examples build without Google Protobuf examples
--no-curl-examples build without libcurl examples --no-curl-examples build without libcurl examples
--no-unit-tests build without unit tests --no-unit-tests build without unit tests
--no-opencl build without opencl --no-opencl build without OpenCL module
--no-nexus build without nexus --no-nexus build without nexus
--no-cash build without cash --no-cash build without cash
--no-benchmarks build without benchmarks --no-benchmarks build without benchmarks
--no-riac build without riac --no-riac build without RIAC module
--no-tools build without CAF tools such as caf-run --no-tools build without CAF tools such as caf-run
--no-io build without I/O module
--no-summary do not print configuration before building --no-summary do not print configuration before building
Testing: Testing:
...@@ -354,6 +355,9 @@ while [ $# -ne 0 ]; do ...@@ -354,6 +355,9 @@ while [ $# -ne 0 ]; do
--no-tools) --no-tools)
append_cache_entry CAF_NO_TOOLS BOOL yes append_cache_entry CAF_NO_TOOLS BOOL yes
;; ;;
--no-io)
append_cache_entry CAF_NO_IO BOOL yes
;;
--no-summary) --no-summary)
append_cache_entry CAF_NO_SUMMARY BOOL yes append_cache_entry CAF_NO_SUMMARY BOOL yes
;; ;;
......
...@@ -19,6 +19,7 @@ set (LIBCAF_CORE_SRCS ...@@ -19,6 +19,7 @@ set (LIBCAF_CORE_SRCS
src/actor.cpp src/actor.cpp
src/actor_addr.cpp src/actor_addr.cpp
src/actor_config.cpp src/actor_config.cpp
src/actor_control_block.cpp
src/actor_companion.cpp src/actor_companion.cpp
src/actor_ostream.cpp src/actor_ostream.cpp
src/actor_pool.cpp src/actor_pool.cpp
...@@ -35,7 +36,6 @@ set (LIBCAF_CORE_SRCS ...@@ -35,7 +36,6 @@ set (LIBCAF_CORE_SRCS
src/binary_deserializer.cpp src/binary_deserializer.cpp
src/binary_serializer.cpp src/binary_serializer.cpp
src/blocking_actor.cpp src/blocking_actor.cpp
src/channel.cpp
src/concatenated_tuple.cpp src/concatenated_tuple.cpp
src/continue_helper.cpp src/continue_helper.cpp
src/decorated_tuple.cpp src/decorated_tuple.cpp
......
...@@ -52,12 +52,19 @@ using actor_id = uint64_t; ...@@ -52,12 +52,19 @@ using actor_id = uint64_t;
/// Denotes an ID that is never used by an actor. /// Denotes an ID that is never used by an actor.
constexpr actor_id invalid_actor_id = 0; constexpr actor_id invalid_actor_id = 0;
using abstract_actor_ptr = intrusive_ptr<abstract_actor>;
/// Base class for all actor implementations. /// Base class for all actor implementations.
class abstract_actor : public abstract_channel { class abstract_actor : public abstract_channel {
public: public:
void enqueue(const actor_addr& sender, message_id mid, // allow placement new (only)
inline void* operator new(std::size_t, void* ptr) {
return ptr;
}
actor_control_block* ctrl() const;
virtual ~abstract_actor();
void enqueue(strong_actor_ptr sender, message_id mid,
message content, execution_unit* host) override; message content, execution_unit* host) override;
/// Enqueues a new message wrapped in a `mailbox_element` to the actor. /// Enqueues a new message wrapped in a `mailbox_element` to the actor.
...@@ -115,20 +122,18 @@ public: ...@@ -115,20 +122,18 @@ public:
return link_impl(remove_backlink_op, other); return link_impl(remove_backlink_op, other);
} }
/// Returns the unique ID of this actor.
inline actor_id id() const {
return id_;
}
/// Returns the set of accepted messages types as strings or /// Returns the set of accepted messages types as strings or
/// an empty set if this actor is untyped. /// an empty set if this actor is untyped.
virtual std::set<std::string> message_types() const; virtual std::set<std::string> message_types() const;
/// Returns the ID of this actor.
actor_id id() const noexcept;
/// Returns the node this actor is living on.
node_id node() const noexcept;
/// Returns the system that created this actor (or proxy). /// Returns the system that created this actor (or proxy).
actor_system& home_system() { actor_system& home_system() const noexcept;
CAF_ASSERT(home_system_ != nullptr);
return *home_system_;
}
/**************************************************************************** /****************************************************************************
* here be dragons: end of public interface * * here be dragons: end of public interface *
...@@ -143,7 +148,7 @@ public: ...@@ -143,7 +148,7 @@ public:
remove_backlink_op remove_backlink_op
}; };
// used by ... // flags storing runtime information used by ...
static constexpr int trap_exit_flag = 0x01; // local_actor static constexpr int trap_exit_flag = 0x01; // local_actor
static constexpr int has_timeout_flag = 0x02; // single_timeout static constexpr int has_timeout_flag = 0x02; // single_timeout
static constexpr int is_registered_flag = 0x04; // (several actors) static constexpr int is_registered_flag = 0x04; // (several actors)
...@@ -225,13 +230,11 @@ public: ...@@ -225,13 +230,11 @@ public:
void is_registered(bool value); void is_registered(bool value);
virtual bool link_impl(linking_operation op, const actor_addr& other) = 0; inline bool is_actor_decorator() const {
return static_cast<bool>(flags() & is_actor_decorator_mask);
// cannot be changed after construction }
const actor_id id_;
// points to the actor system that created this actor virtual bool link_impl(linking_operation op, const actor_addr& other) = 0;
actor_system* home_system_;
/// @endcond /// @endcond
...@@ -240,8 +243,14 @@ protected: ...@@ -240,8 +243,14 @@ protected:
explicit abstract_actor(actor_config& cfg); explicit abstract_actor(actor_config& cfg);
/// Creates a new actor instance. /// Creates a new actor instance.
abstract_actor(actor_system* sys, actor_id aid, node_id nid, explicit abstract_actor(int flags = 0);
int flags = abstract_channel::is_abstract_actor_flag);
private:
// prohibit copies, assigments, and heap allocations
void* operator new(size_t);
void* operator new[](size_t);
abstract_actor(const abstract_actor&) = delete;
abstract_actor& operator=(const abstract_actor&) = delete;
}; };
std::string to_string(abstract_actor::linking_operation op); std::string to_string(abstract_actor::linking_operation op);
......
...@@ -23,16 +23,14 @@ ...@@ -23,16 +23,14 @@
#include <atomic> #include <atomic>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/node_id.hpp"
#include "caf/message_id.hpp" #include "caf/message_id.hpp"
#include "caf/ref_counted.hpp"
namespace caf { namespace caf {
/// Interface for all message receivers. * This interface describes an /// Interface for all message receivers. * This interface describes an
/// entity that can receive messages and is implemented by {@link actor} /// entity that can receive messages and is implemented by {@link actor}
/// and {@link group}. /// and {@link group}.
class abstract_channel : public ref_counted { class abstract_channel {
public: public:
friend class abstract_actor; friend class abstract_actor;
friend class abstract_group; friend class abstract_group;
...@@ -40,13 +38,8 @@ public: ...@@ -40,13 +38,8 @@ public:
virtual ~abstract_channel(); virtual ~abstract_channel();
/// Enqueues a new message without forwarding stack to the channel. /// Enqueues a new message without forwarding stack to the channel.
virtual void enqueue(const actor_addr& sender, message_id mid, virtual void enqueue(strong_actor_ptr sender, message_id mid, message content,
message content, execution_unit* host) = 0; execution_unit* host = nullptr) = 0;
/// Returns the ID of the node this actor is running on.
inline node_id node() const {
return node_;
}
static constexpr int is_abstract_actor_flag = 0x100000; static constexpr int is_abstract_actor_flag = 0x100000;
...@@ -87,21 +80,14 @@ protected: ...@@ -87,21 +80,14 @@ protected:
private: private:
// can only be called from abstract_actor and abstract_group // can only be called from abstract_actor and abstract_group
abstract_channel(int init_flags, node_id nid); abstract_channel(int init_flags);
// 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.
std::atomic<int> flags_; std::atomic<int> flags_;
// identifies the node of this channel
node_id node_;
}; };
/// A smart pointer to an abstract channel.
/// @relates abstract_channel_ptr
using abstract_channel_ptr = intrusive_ptr<abstract_channel>;
} // namespace caf } // namespace caf
#endif // CAF_ABSTRACT_CHANNEL_HPP #endif // CAF_ABSTRACT_CHANNEL_HPP
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
namespace caf { namespace caf {
/// A multicast group. /// A multicast group.
class abstract_group : public abstract_channel { class abstract_group : public ref_counted, public abstract_channel {
public: public:
friend class local_actor; friend class local_actor;
friend class subscription; friend class subscription;
...@@ -85,7 +85,7 @@ public: ...@@ -85,7 +85,7 @@ public:
/// Subscribes `who` to this group and returns `true` on success /// Subscribes `who` to this group and returns `true` on success
/// or `false` if `who` is already subscribed. /// or `false` if `who` is already subscribed.
virtual bool subscribe(const actor_addr& who) = 0; virtual bool subscribe(strong_actor_ptr who) = 0;
/// Stops any background actors or threads and IO handles. /// Stops any background actors or threads and IO handles.
virtual void stop() = 0; virtual void stop() = 0;
...@@ -99,11 +99,12 @@ protected: ...@@ -99,11 +99,12 @@ protected:
std::string group_id, const node_id& nid); std::string group_id, const node_id& nid);
// called by local_actor // called by local_actor
virtual void unsubscribe(const actor_addr& who) = 0; virtual void unsubscribe(const actor_control_block* who) = 0;
actor_system& system_; actor_system& system_;
module_ptr module_; module_ptr module_;
std::string identifier_; std::string identifier_;
node_id origin_;
}; };
/// A smart pointer type that manages instances of {@link group}. /// A smart pointer type that manages instances of {@link group}.
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/actor_marker.hpp" #include "caf/actor_marker.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/abstract_actor.hpp" #include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
...@@ -71,8 +71,11 @@ public: ...@@ -71,8 +71,11 @@ public:
friend class local_actor; friend class local_actor;
// allow conversion via actor_cast // allow conversion via actor_cast
template <class> template <class, class, int>
friend struct actor_cast_access; friend class actor_cast_access;
// tell actor_cast which semantic this type uses
static constexpr bool has_weak_ptr_semantics = false;
actor() = default; actor() = default;
actor(actor&&) = default; actor(actor&&) = default;
...@@ -80,27 +83,17 @@ public: ...@@ -80,27 +83,17 @@ public:
actor& operator=(actor&&) = default; actor& operator=(actor&&) = default;
actor& operator=(const actor&) = default; actor& operator=(const actor&) = default;
template <class T, actor(const scoped_actor&);
class Enable = actor(const invalid_actor_t&);
typename std::enable_if<
is_convertible_to_actor<T>::value
>::type>
actor(intrusive_ptr<T> ptr) : ptr_(std::move(ptr)) {
// nop
}
template <class T, template <class T,
class Enable = class = typename std::enable_if<
typename std::enable_if< std::is_base_of<dynamically_typed_actor_base, T>::value
is_convertible_to_actor<T>::value >::type>
>::type> actor(T* ptr) : ptr_(ptr->ctrl()) {
actor(T* ptr) : ptr_(ptr) {
// nop // nop
} }
actor(const scoped_actor&);
actor(const invalid_actor_t&);
template <class T> template <class T>
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type
operator=(intrusive_ptr<T> ptr) { operator=(intrusive_ptr<T> ptr) {
...@@ -151,7 +144,8 @@ public: ...@@ -151,7 +144,8 @@ public:
/// @cond PRIVATE /// @cond PRIVATE
inline abstract_actor* operator->() const noexcept { inline abstract_actor* operator->() const noexcept {
return ptr_.get(); CAF_ASSERT(ptr_);
return ptr_->get();
} }
intptr_t compare(const actor&) const noexcept; intptr_t compare(const actor&) const noexcept;
...@@ -168,24 +162,33 @@ public: ...@@ -168,24 +162,33 @@ public:
static actor splice_impl(std::initializer_list<actor> xs); static actor splice_impl(std::initializer_list<actor> xs);
actor(actor_control_block*, bool);
template <class Processor>
friend void serialize(Processor& proc, actor& x, const unsigned int v) {
serialize(proc, x.ptr_, v);
}
friend inline std::string to_string(const actor& x) {
return to_string(x.ptr_);
}
/// @endcond /// @endcond
private: private:
actor bind_impl(message msg) const; actor bind_impl(message msg) const;
inline abstract_actor* get() const noexcept { inline actor_control_block* get() const noexcept {
return ptr_.get(); return ptr_.get();
} }
inline abstract_actor* release() noexcept { inline actor_control_block* release() noexcept {
return ptr_.release(); return ptr_.release();
} }
actor(abstract_actor*); actor(actor_control_block*);
actor(abstract_actor*, bool);
abstract_actor_ptr ptr_; strong_actor_ptr ptr_;
}; };
/// Combine `f` and `g` so that `(f*g)(x) = f(g(x))`. /// Combine `f` and `g` so that `(f*g)(x) = f(g(x))`.
...@@ -198,13 +201,16 @@ actor splice(const actor& x, const actor& y, const Ts&... zs) { ...@@ -198,13 +201,16 @@ actor splice(const actor& x, const actor& y, const Ts&... zs) {
} }
/// @relates actor /// @relates actor
void serialize(serializer&, actor&, const unsigned int); bool operator==(const actor& lhs, abstract_actor* rhs);
/// @relates actor
bool operator==(abstract_actor* lhs, const actor& rhs);
/// @relates actor /// @relates actor
void serialize(deserializer&, actor&, const unsigned int); bool operator!=(const actor& lhs, abstract_actor* rhs);
/// @relates actor /// @relates actor
std::string to_string(const actor& x); bool operator!=(abstract_actor* lhs, const actor& rhs);
} // namespace caf } // namespace caf
......
...@@ -25,10 +25,9 @@ ...@@ -25,10 +25,9 @@
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
#include "caf/intrusive_ptr.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/abstract_actor.hpp" #include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
...@@ -45,15 +44,21 @@ constexpr invalid_actor_addr_t invalid_actor_addr = invalid_actor_addr_t{}; ...@@ -45,15 +44,21 @@ constexpr invalid_actor_addr_t invalid_actor_addr = invalid_actor_addr_t{};
/// Stores the address of typed as well as untyped actors. /// Stores the address of typed as well as untyped actors.
class actor_addr : detail::comparable<actor_addr>, class actor_addr : detail::comparable<actor_addr>,
detail::comparable<actor_addr, weak_actor_ptr>,
detail::comparable<actor_addr, strong_actor_ptr>,
detail::comparable<actor_addr, abstract_actor*>, detail::comparable<actor_addr, abstract_actor*>,
detail::comparable<actor_addr, abstract_actor_ptr> { detail::comparable<actor_addr, actor_control_block*> {
public: public:
// grant access to private ctor // grant access to private ctor
friend class actor; friend class actor;
friend class abstract_actor; friend class abstract_actor;
template <class> // allow conversion via actor_cast
friend struct actor_cast_access; template <class, class, int>
friend class actor_cast_access;
// tell actor_cast which semantic this type uses
static constexpr bool has_weak_ptr_semantics = true;
actor_addr() = default; actor_addr() = default;
actor_addr(actor_addr&&) = default; actor_addr(actor_addr&&) = default;
...@@ -81,49 +86,62 @@ public: ...@@ -81,49 +86,62 @@ public:
/// Returns the origin node of this actor. /// Returns the origin node of this actor.
node_id node() const noexcept; node_id node() const noexcept;
/// Returns the hosting actor system.
actor_system* home_system() const noexcept;
/// Exchange content of `*this` and `other`. /// Exchange content of `*this` and `other`.
void swap(actor_addr& other) noexcept; void swap(actor_addr& other) noexcept;
/// @cond PRIVATE /// @cond PRIVATE
inline abstract_actor* operator->() const noexcept { static intptr_t compare(const actor_control_block* lhs,
return ptr_.get(); const actor_control_block* rhs);
}
static intptr_t compare(const abstract_actor* lhs, const abstract_actor* rhs);
intptr_t compare(const actor_addr& other) const noexcept; intptr_t compare(const actor_addr& other) const noexcept;
intptr_t compare(const abstract_actor* other) const noexcept; intptr_t compare(const abstract_actor* other) const noexcept;
inline intptr_t compare(const abstract_actor_ptr& other) const noexcept { intptr_t compare(const actor_control_block* other) const noexcept;
inline intptr_t compare(const weak_actor_ptr& other) const noexcept {
return compare(other.get());
}
inline intptr_t compare(const strong_actor_ptr& other) const noexcept {
return compare(other.get()); return compare(other.get());
} }
friend void serialize(serializer&, actor_addr&, const unsigned int); template <class Processor>
friend void serialize(Processor& proc, actor_addr& x, const unsigned int v) {
serialize(proc, x.ptr_, v);
}
friend inline std::string to_string(const actor_addr& x) {
return to_string(x.ptr_);
}
friend void serialize(deserializer&, actor_addr&, const unsigned int); actor_addr(actor_control_block*, bool);
/// @endcond /// @endcond
private: private:
inline abstract_actor* get() const noexcept { inline actor_control_block* get() const noexcept {
return ptr_.get(); return ptr_.get();
} }
inline abstract_actor* release() noexcept { inline actor_control_block* release() noexcept {
return ptr_.release(); return ptr_.release();
} }
actor_addr(abstract_actor*); inline actor_control_block* get_locked() const noexcept {
return ptr_.get_locked();
}
actor_addr(abstract_actor*, bool); actor_addr(actor_control_block*);
abstract_actor_ptr ptr_; weak_actor_ptr ptr_;
}; };
/// @relates actor_addr
std::string to_string(const actor_addr& x);
} // namespace caf } // namespace caf
...@@ -134,7 +152,6 @@ struct hash<caf::actor_addr> { ...@@ -134,7 +152,6 @@ struct hash<caf::actor_addr> {
inline size_t operator()(const caf::actor_addr& ref) const { inline size_t operator()(const caf::actor_addr& ref) const {
return static_cast<size_t>(ref.id()); return static_cast<size_t>(ref.id());
} }
}; };
} // namespace std } // namespace std
......
...@@ -22,35 +22,118 @@ ...@@ -22,35 +22,118 @@
#include <type_traits> #include <type_traits>
#include "caf/fwd.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
namespace caf { namespace caf {
namespace {
// actor_cast computes the type of the cast for actor_cast_access via
// the following formula: x = 0 if To is a raw poiner
// = 1 if To is a strong pointer
// = 2 if To is a weak pointer
// y = 0 if From is a raw poiner
// = 6 if From is a strong pointer
// = 2 if From is a weak pointer
// the result of x * y then denotes which operation the cast is performing:
// raw <- raw = 0
// raw <- weak = 0
// raw <- strong = 0
// weak <- raw = 0
// weak <- weak = 6
// weak <- strong = 12
// strong <- raw = 0
// strong <- weak = 3
// strong <- strong = 6
// x * y is then interpreted as follows:
// - 0 is a conversion to or from a raw pointer
// - 6 is a conversion between pointers with same semantics
// - 3 is a conversion from a weak pointer to a strong pointer
// - 12 is a conversion from a strong pointer to a weak pointer
constexpr int raw_ptr_cast = 0; // either To or From is a raw pointer
constexpr int weak_ptr_downgrade_cast = 12; // To is weak, From is strong
constexpr int weak_ptr_upgrade_cast = 3; // To is strong, From is weak
constexpr int neutral_cast = 6; // To and From are both weak or both strong
template <class T>
struct is_weak_ptr {
static constexpr bool value = T::has_weak_ptr_semantics;
};
template <class T> template <class T>
struct actor_cast_access { struct is_weak_ptr<T*> {
constexpr actor_cast_access() { static constexpr bool value = false;
// nop };
} // namespace <anonymous>
template <class To, class From, int>
class actor_cast_access;
template <class To, class From>
class actor_cast_access<To, From, raw_ptr_cast> {
public:
To operator()(actor_control_block* x) const {
return x;
} }
template<class U> To operator()(abstract_actor* x) const {
T operator()(U& y) const { return x ? x->ctrl() : nullptr;
return {y.get(), true};
} }
template<class U> template <class T,
typename std::enable_if<std::is_rvalue_reference<U&&>::value, T>::type class = typename std::enable_if<! std::is_pointer<T>::value>::type>
operator()(U&& y) const { To operator()(const T& x) const {
return {y.release(), false}; return x.get();
} }
}; };
template <class T> template <class From>
struct actor_cast_access<T*> { class actor_cast_access<abstract_actor*, From, raw_ptr_cast> {
constexpr actor_cast_access() { public:
// nop abstract_actor* operator()(actor_control_block* x) const {
return x ? x->get() : nullptr;
}
abstract_actor* operator()(abstract_actor* x) const {
return x;
}
template <class T,
class = typename std::enable_if<! std::is_pointer<T>::value>::type>
abstract_actor* operator()(const T& x) const {
return (*this)(x.get());
}
};
template <class To, class From>
class actor_cast_access<To, From, weak_ptr_downgrade_cast> {
public:
To operator()(const From& x) const {
return x.get();
}
};
template <class To, class From>
class actor_cast_access<To, From, weak_ptr_upgrade_cast> {
public:
To operator()(const From& x) const {
return {x.get_locked(), false};
}
};
template <class To, class From>
class actor_cast_access<To, From, neutral_cast> {
public:
To operator()(const From& x) const {
return x.get();
} }
template<class U> To operator()(From&& x) const {
T* operator()(const U& y) const { return {x.release(), false};
return y.get();
} }
}; };
...@@ -58,7 +141,12 @@ struct actor_cast_access<T*> { ...@@ -58,7 +141,12 @@ struct actor_cast_access<T*> {
/// handle or raw pointer of type `T`. /// handle or raw pointer of type `T`.
template <class T, class U> template <class T, class U>
T actor_cast(U&& what) { T actor_cast(U&& what) {
actor_cast_access<T> f; using from = typename std::remove_const<typename std::remove_reference<U>::type>::type;
constexpr int x = std::is_pointer<T>::value ? 0
: (is_weak_ptr<T>::value ? 2 : 1);
constexpr int y = std::is_pointer<from>::value ? 0
: (is_weak_ptr<from>::value ? 3 : 6);
actor_cast_access<T, from, x * y> f;
return f(std::forward<U>(what)); return f(std::forward<U>(what));
} }
......
...@@ -54,8 +54,8 @@ public: ...@@ -54,8 +54,8 @@ public:
void enqueue(mailbox_element_ptr what, execution_unit* host) override; void enqueue(mailbox_element_ptr what, execution_unit* host) override;
void enqueue(const actor_addr& sender, message_id mid, void enqueue(strong_actor_ptr sender, message_id mid, message content,
message content, execution_unit* host) override; execution_unit* host) override;
void initialize() override; void initialize() override;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_ACTOR_CONTROL_BLOCK_HPP
#define CAF_ACTOR_CONTROL_BLOCK_HPP
#include <atomic>
#include "caf/fwd.hpp"
#include "caf/node_id.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/weak_intrusive_ptr.hpp"
namespace caf {
/// Actors are always allocated with a control block that stores its identity
/// as well as strong and weak reference counts to it. Unlike
/// "common" weak pointer designs, the goal is not to allocate the data
/// separately. Instead, the only goal is to break cycles. For
/// example, linking two actors automatically creates a cycle when using
/// strong reference counts only.
///
/// When allocating a new actor, CAF will always embed the user-defined
/// actor in an `actor_storage` with the control block prefixing the
/// actual actor type, as shown below.
///
/// +----------------------------------------+
/// | actor_storage<T> |
/// +----------------------------------------+
/// | +-----------------+------------------+ |
/// | | control block | actor data (T) | |
/// | +-----------------+------------------+ |
/// | | ref count | mailbox | |
/// | | weak ref count | . | |
/// | | actor ID | . | |
/// | | node ID | . | |
/// | +-----------------+------------------+ |
/// +----------------------------------------+
///
/// Actors start with a strong reference count of 1. This count is transferred
/// to the first `actor` or `typed_actor` handle used to store the actor.
/// Actors will also start with a weak reference count of 1. This count
/// is decremenated once the strong reference count drops to 0.
///
/// The data block is destructed by calling the destructor of `T` when the
/// last strong reference expires. The storage itself is destroyed when
/// the last weak reference expires.
class actor_control_block {
public:
using data_destructor = void (*)(abstract_actor*);
using block_destructor = void (*)(actor_control_block*);
actor_control_block(actor_id x, node_id& y, actor_system* sys,
data_destructor ddtor, block_destructor bdtor)
: strong_refs(1),
weak_refs(1),
aid(x),
nid(std::move(y)),
home_system(sys),
data_dtor(ddtor),
block_dtor(bdtor) {
// nop
}
actor_control_block(const actor_control_block&) = delete;
actor_control_block& operator=(const actor_control_block&) = delete;
std::atomic<size_t> strong_refs;
std::atomic<size_t> weak_refs;
const actor_id aid;
const node_id nid;
actor_system* const home_system;
const data_destructor data_dtor;
const block_destructor block_dtor;
/// Returns a pointer to the actual actor instance.
inline abstract_actor* get() {
// this pointer arithmetic is compile-time checked in actor_storage's ctor
return reinterpret_cast<abstract_actor*>(
reinterpret_cast<intptr_t>(this) + CAF_CACHE_LINE_SIZE);
}
/// Returns a pointer to the control block that stores
/// identity and reference counts for this actor.
static actor_control_block* from(const abstract_actor* ptr) {
// this pointer arithmetic is compile-time checked in actor_storage's ctor
return reinterpret_cast<actor_control_block*>(
reinterpret_cast<intptr_t>(ptr) - CAF_CACHE_LINE_SIZE);
}
/// @cond PRIVATE
inline actor_id id() const noexcept {
return aid;
}
inline const node_id& node() const noexcept {
return nid;
}
void enqueue(strong_actor_ptr sender, message_id mid,
message content, execution_unit* host);
void enqueue(mailbox_element_ptr what, execution_unit* host);
/// @endcond
};
/// @relates actor_control_block
bool intrusive_ptr_upgrade_weak(actor_control_block* x);
/// @relates actor_control_block
inline void intrusive_ptr_add_weak_ref(actor_control_block* x) {
x->weak_refs.fetch_add(1, std::memory_order_relaxed);
}
/// @relates actor_control_block
void intrusive_ptr_release_weak(actor_control_block* x);
/// @relates actor_control_block
inline void intrusive_ptr_add_ref(actor_control_block* x) {
x->strong_refs.fetch_add(1, std::memory_order_relaxed);
}
/// @relates actor_control_block
void intrusive_ptr_release(actor_control_block* x);
/// @relates abstract_actor
/// @relates actor_control_block
using strong_actor_ptr = intrusive_ptr<actor_control_block>;
/// @relates abstract_actor
/// @relates actor_control_block
using weak_actor_ptr = weak_intrusive_ptr<actor_control_block>;
/// @relates strong_actor_ptr
void serialize(serializer&, strong_actor_ptr&, const unsigned int);
/// @relates strong_actor_ptr
void serialize(deserializer&, strong_actor_ptr&, const unsigned int);
/// @relates weak_actor_ptr
void serialize(serializer&, weak_actor_ptr&, const unsigned int);
/// @relates weak_actor_ptr
void serialize(deserializer&, weak_actor_ptr&, const unsigned int);
/// @relates strong_actor_ptr
std::string to_string(const strong_actor_ptr&);
/// @relates weak_actor_ptr
std::string to_string(const weak_actor_ptr&);
} // namespace caf
#endif // CAF_ACTOR_CONTROL_BLOCK_HPP
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
namespace caf { namespace caf {
using actor_factory_result = std::pair<actor_addr, std::set<std::string>>; using actor_factory_result = std::pair<strong_actor_ptr, std::set<std::string>>;
using actor_factory = std::function<actor_factory_result (actor_config&, message&)>; using actor_factory = std::function<actor_factory_result (actor_config&, message&)>;
...@@ -155,7 +155,8 @@ actor_factory make_actor_factory(F fun) { ...@@ -155,7 +155,8 @@ actor_factory make_actor_factory(F fun) {
return result; return result;
}; };
handle hdl = cfg.host->system().spawn_class<impl, no_spawn_options>(cfg); handle hdl = cfg.host->system().spawn_class<impl, no_spawn_options>(cfg);
return {hdl.address(), cfg.host->system().message_types(hdl)}; return {actor_cast<strong_actor_ptr>(std::move(hdl)),
cfg.host->system().message_types(hdl)};
}; };
} }
...@@ -178,14 +179,17 @@ actor_factory_result dyn_spawn_class(actor_config& cfg, message& msg) { ...@@ -178,14 +179,17 @@ actor_factory_result dyn_spawn_class(actor_config& cfg, message& msg) {
msg.apply(factory); msg.apply(factory);
if (hdl == invalid_actor) if (hdl == invalid_actor)
return {}; return {};
return {hdl.address(), cfg.host->system().message_types(hdl)}; return {actor_cast<strong_actor_ptr>(std::move(hdl)),
cfg.host->system().message_types(hdl)};
} }
template <class T, class... Ts> template <class T, class... Ts>
actor_factory make_actor_factory() { actor_factory make_actor_factory() {
/*
static_assert(std::is_same<T*, decltype(new T(std::declval<actor_config&>(), static_assert(std::is_same<T*, decltype(new T(std::declval<actor_config&>(),
std::declval<Ts>()...))>::value, std::declval<Ts>()...))>::value,
"no constructor for T(Ts...) exists"); "no constructor for T(Ts...) exists");
*/
static_assert(detail::conjunction< static_assert(detail::conjunction<
std::is_lvalue_reference<Ts>::value... std::is_lvalue_reference<Ts>::value...
>::value, >::value,
......
...@@ -42,7 +42,9 @@ public: ...@@ -42,7 +42,9 @@ public:
/// Open redirection file in append mode. /// Open redirection file in append mode.
static constexpr int append = 0x01; static constexpr int append = 0x01;
explicit actor_ostream(abstract_actor* self); explicit actor_ostream(local_actor* self);
explicit actor_ostream(scoped_actor& self);
/// Writes `arg` to the buffer allocated for the calling actor. /// Writes `arg` to the buffer allocated for the calling actor.
actor_ostream& write(std::string arg); actor_ostream& write(std::string arg);
...@@ -81,12 +83,12 @@ public: ...@@ -81,12 +83,12 @@ public:
} }
private: private:
intrusive_ptr<abstract_actor> self_; actor self_;
actor printer_; actor printer_;
}; };
/// Convenience factory function for creating an actor output stream. /// Convenience factory function for creating an actor output stream.
actor_ostream aout(abstract_actor* self); actor_ostream aout(local_actor* self);
/// Convenience factory function for creating an actor output stream. /// Convenience factory function for creating an actor output stream.
actor_ostream aout(scoped_actor& self); actor_ostream aout(scoped_actor& self);
......
...@@ -98,16 +98,17 @@ public: ...@@ -98,16 +98,17 @@ public:
/// function `fac` using the dispatch policy `pol`. /// function `fac` using the dispatch policy `pol`.
static actor make(execution_unit* ptr, size_t n, factory fac, policy pol); static actor make(execution_unit* ptr, size_t n, factory fac, policy pol);
void enqueue(const actor_addr& sender, message_id mid, void enqueue(strong_actor_ptr sender, message_id mid, message content,
message content, execution_unit* host) override; execution_unit* host) override;
void enqueue(mailbox_element_ptr what, execution_unit* host) override; void enqueue(mailbox_element_ptr what, execution_unit* host) override;
actor_pool(actor_config& cfg); actor_pool(actor_config& cfg);
private: private:
bool filter(upgrade_lock<detail::shared_spinlock>&, const actor_addr& sender, bool filter(upgrade_lock<detail::shared_spinlock>&,
message_id mid, const message& content, execution_unit* host); const strong_actor_ptr& sender, message_id mid,
const message& content, execution_unit* host);
// call without workers_mtx_ held // call without workers_mtx_ held
void quit(execution_unit* host); void quit(execution_unit* host);
......
...@@ -30,44 +30,11 @@ ...@@ -30,44 +30,11 @@
namespace caf { namespace caf {
class actor_proxy;
/// A smart pointer to an {@link actor_proxy} instance.
/// @relates actor_proxy
using actor_proxy_ptr = intrusive_ptr<actor_proxy>;
/// Represents an actor running on a remote machine, /// Represents an actor running on a remote machine,
/// or different hardware, or in a separate process. /// or different hardware, or in a separate process.
class actor_proxy : public monitorable_actor { class actor_proxy : public monitorable_actor {
public: public:
/// An anchor points to a proxy instance without sharing actor_proxy();
/// ownership to it, i.e., models a weak ptr.
class anchor : public ref_counted {
public:
friend class actor_proxy;
anchor(actor_proxy* instance = nullptr);
~anchor();
/// Queries whether the proxy was already deleted.
bool expired() const;
/// Gets a pointer to the proxy or `nullptr`
/// if the instance is {@link expired()}.
actor_proxy_ptr get();
private:
/*
* Tries to expire this anchor. Fails if reference
* count of the proxy is nonzero.
*/
bool try_expire() noexcept;
std::atomic<actor_proxy*> ptr_;
detail::shared_spinlock lock_;
};
using anchor_ptr = intrusive_ptr<anchor>;
~actor_proxy(); ~actor_proxy();
...@@ -80,17 +47,6 @@ public: ...@@ -80,17 +47,6 @@ public:
/// Invokes cleanup code. /// Invokes cleanup code.
virtual void kill_proxy(execution_unit* ctx, exit_reason reason) = 0; virtual void kill_proxy(execution_unit* ctx, exit_reason reason) = 0;
void request_deletion(bool decremented_ref_count) noexcept override;
inline anchor_ptr get_anchor() const {
return anchor_;
}
protected:
actor_proxy(actor_system* sys, actor_id aid, node_id nid);
anchor_ptr anchor_;
}; };
} // namespace caf } // namespace caf
......
...@@ -29,8 +29,8 @@ ...@@ -29,8 +29,8 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/actor.hpp" #include "caf/actor.hpp"
#include "caf/actor_addr.hpp"
#include "caf/abstract_actor.hpp" #include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/shared_spinlock.hpp" #include "caf/detail/shared_spinlock.hpp"
#include "caf/detail/singleton_mixin.hpp" #include "caf/detail/singleton_mixin.hpp"
...@@ -52,13 +52,13 @@ public: ...@@ -52,13 +52,13 @@ public:
/// A registry entry consists of a pointer to the actor and an /// A registry entry consists of a pointer to the actor and an
/// exit reason. An entry with a nullptr means the actor has finished /// exit reason. An entry with a nullptr means the actor has finished
/// execution for given reason. /// execution for given reason.
using id_entry = std::pair<actor_addr, exit_reason>; using id_entry = std::pair<strong_actor_ptr, exit_reason>;
/// Returns the the local actor associated to `key`. /// Returns the the local actor associated to `key`.
id_entry get(actor_id key) const; id_entry get(actor_id key) const;
/// Associates a local actor with its ID. /// Associates a local actor with its ID.
void put(actor_id key, const actor_addr& value); void put(actor_id key, const strong_actor_ptr& value);
/// Removes an actor from this registry, /// Removes an actor from this registry,
/// leaving `reason` for future reference. /// leaving `reason` for future reference.
...@@ -78,15 +78,21 @@ public: ...@@ -78,15 +78,21 @@ public:
void await_running_count_equal(size_t expected) const; void await_running_count_equal(size_t expected) const;
/// Returns the actor associated with `key` or `invalid_actor`. /// Returns the actor associated with `key` or `invalid_actor`.
actor get(atom_value key) const; strong_actor_ptr get(atom_value key) const;
/// Associates given actor to `key`. /// Associates given actor to `key`.
void put(atom_value key, actor value); void put(atom_value key, strong_actor_ptr value);
/// Removes a name mapping. /// Removes a name mapping.
void erase(atom_value key); void erase(atom_value key);
using name_map = std::unordered_map<atom_value, actor>; /// @cond PRIVATE
void put(actor_id, actor_control_block*);
/// @endcond
using name_map = std::unordered_map<atom_value, strong_actor_ptr>;
name_map named_actors() const; name_map named_actors() const;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_ACTOR_STORAGE_HPP
#define CAF_ACTOR_STORAGE_HPP
#include <new>
#include <atomic>
#include <cstddef>
#include <type_traits>
#include "caf/config.hpp"
#include "caf/actor_control_block.hpp"
namespace caf {
template <class T>
class actor_storage {
public:
template <class... Us>
actor_storage(actor_id x, node_id y, actor_system* sys, Us&&... zs)
: ctrl(x, y, sys, data_dtor, block_dtor) {
// 1) make sure control block fits into a single cache line
static_assert(sizeof(actor_control_block) < CAF_CACHE_LINE_SIZE,
"actor_control_block exceeds a single cache line");
// 2) make sure reinterpret cast of the control block to the storage works
static_assert(offsetof(actor_storage, ctrl) == 0,
"control block is not at the start of the storage");
// 3) make sure we can obtain a data pointer by jumping one cache line
static_assert(offsetof(actor_storage, data) == CAF_CACHE_LINE_SIZE,
"data is not at cache line size boundary");
// 4) make sure static_cast and reinterpret_cast
// between T* and abstract_actor* are identical
constexpr abstract_actor* dummy = nullptr;
constexpr T* derived_dummy = static_cast<T*>(dummy);
static_assert(derived_dummy == nullptr,
"actor subtype has illegal memory alignment "
"(probably due to virtual inheritance)");
// construct data member
new (&data) T(std::forward<Us>(zs)...);
}
~actor_storage() {
// nop
}
actor_storage(const actor_storage&) = delete;
actor_storage& operator=(const actor_storage&) = delete;
actor_control_block ctrl;
char pad[CAF_CACHE_LINE_SIZE - sizeof(actor_control_block)];
union { T data; };
private:
static void data_dtor(abstract_actor* ptr) {
// safe due to static assert #3
static_cast<T*>(ptr)->~T();
}
static void block_dtor(actor_control_block* ptr) {
// safe due to static assert #2
delete reinterpret_cast<actor_storage*>(ptr);
}
};
/// @relates actor_storage
template <class T>
bool intrusive_ptr_upgrade_weak(actor_storage<T>* x) {
auto count = x->ctrl.strong_refs.load();
while (count != 0) {
if (x->ctrl.strong_refs.compare_exchange_weak(count, count + 1,
std::memory_order_relaxed))
return true;
}
return false;
}
/// @relates actor_storage
template <class T>
void intrusive_ptr_add_weak_ref(actor_storage<T>* x) {
x->ctrl.weak_refs.fetch_add(1, std::memory_order_relaxed);
}
/// @relates actor_storage
template <class T>
void intrusive_ptr_release_weak(actor_storage<T>* x) {
// destroy object if last weak pointer expires
if (x->ctrl.weak_refs == 1
|| x->ctrl.weak_refs.fetch_sub(1, std::memory_order_acq_rel) == 1)
delete x;
}
/// @relates actor_storage
template <class T>
void intrusive_ptr_add_ref(actor_storage<T>* x) {
x->ctrl.strong_refs.fetch_add(1, std::memory_order_relaxed);
}
/// @relates actor_storage
template <class T>
void intrusive_ptr_release(actor_storage<T>* x) {
// release implicit weak pointer if the last strong ref expires
// and destroy the data block
if (x->ctrl.strong_refs.fetch_sub(1, std::memory_order_acq_rel) == 1) {
x->destroy_data();
intrusive_ptr_relase_weak(x);
}
}
} // namespace caf
#endif // CAF_ACTOR_STORAGE_HPP
...@@ -28,9 +28,10 @@ ...@@ -28,9 +28,10 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/logger.hpp" #include "caf/logger.hpp"
#include "caf/actor_cast.hpp"
#include "caf/make_actor.hpp"
#include "caf/infer_handle.hpp" #include "caf/infer_handle.hpp"
#include "caf/actor_config.hpp" #include "caf/actor_config.hpp"
#include "caf/make_counted.hpp"
#include "caf/spawn_options.hpp" #include "caf/spawn_options.hpp"
#include "caf/group_manager.hpp" #include "caf/group_manager.hpp"
#include "caf/abstract_actor.hpp" #include "caf/abstract_actor.hpp"
...@@ -412,12 +413,14 @@ private: ...@@ -412,12 +413,14 @@ private:
cfg.flags |= abstract_actor::is_detached_flag; cfg.flags |= abstract_actor::is_detached_flag;
if (! cfg.host) if (! cfg.host)
cfg.host = dummy_execution_unit(); cfg.host = dummy_execution_unit();
auto ptr = make_counted<C>(cfg, std::forward<Ts>(xs)...); auto res = make_actor<C>(next_actor_id(), node(), this,
cfg, std::forward<Ts>(xs)...);
CAF_SET_LOGGER_SYS(this); CAF_SET_LOGGER_SYS(this);
CAF_LOG_DEBUG("spawned actor:" << CAF_ARG(ptr->id())); CAF_LOG_DEBUG("spawned actor:" << CAF_ARG(res.id()));
CAF_PUSH_AID(ptr->id()); CAF_PUSH_AID(res->id());
auto ptr = static_cast<C*>(actor_cast<abstract_actor*>(res));
ptr->launch(cfg.host, has_lazy_init_flag(Os), has_hide_flag(Os)); ptr->launch(cfg.host, has_lazy_init_flag(Os), has_hide_flag(Os));
return ptr; return res;
} }
std::atomic<size_t> ids_; std::atomic<size_t> ids_;
......
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include "caf/extend.hpp" #include "caf/extend.hpp"
#include "caf/logger.hpp" #include "caf/logger.hpp"
#include "caf/result.hpp" #include "caf/result.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/node_id.hpp" #include "caf/node_id.hpp"
#include "caf/anything.hpp" #include "caf/anything.hpp"
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "caf/local_actor.hpp" #include "caf/local_actor.hpp"
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
#include "caf/actor_config.hpp" #include "caf/actor_config.hpp"
#include "caf/actor_marker.hpp"
#include "caf/mailbox_element.hpp" #include "caf/mailbox_element.hpp"
#include "caf/response_handle.hpp" #include "caf/response_handle.hpp"
...@@ -45,7 +46,8 @@ namespace caf { ...@@ -45,7 +46,8 @@ namespace caf {
/// @extends local_actor /// @extends local_actor
class blocking_actor class blocking_actor
: public extend<local_actor, blocking_actor>:: : public extend<local_actor, blocking_actor>::
with<mixin::requester<blocking_response_handle_tag>::impl> { with<mixin::requester<blocking_response_handle_tag>::impl>,
public dynamically_typed_actor_base {
public: public:
using behavior_type = behavior; using behavior_type = behavior;
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#ifndef CAF_CHECK_TYPED_INPUT_HPP #ifndef CAF_CHECK_TYPED_INPUT_HPP
#define CAF_CHECK_TYPED_INPUT_HPP #define CAF_CHECK_TYPED_INPUT_HPP
#include "caf/fwd.hpp"
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
#include "caf/detail/type_list.hpp" #include "caf/detail/type_list.hpp"
...@@ -27,8 +28,8 @@ ...@@ -27,8 +28,8 @@
namespace caf { namespace caf {
/// Checks whether `R` does support an input of type `{Ts...}` via a /// Checks whether `R` does support an input of type `{Ts...}`
/// static assertion (always returns 0). /// via static assertion.
template <class... Sigs, class... Ts> template <class... Sigs, class... Ts>
void check_typed_input(const typed_actor<Sigs...>&, void check_typed_input(const typed_actor<Sigs...>&,
const detail::type_list<Ts...>&) { const detail::type_list<Ts...>&) {
...@@ -45,6 +46,16 @@ void check_typed_input(const typed_actor<Sigs...>&, ...@@ -45,6 +46,16 @@ void check_typed_input(const typed_actor<Sigs...>&,
"typed actor does not support given input"); "typed actor does not support given input");
} }
template <class... Ts>
void check_typed_input(const actor&, const detail::type_list<Ts...>&) {
// nop
}
template <class... Ts>
void check_typed_input(const group&, const detail::type_list<Ts...>&) {
// nop
}
} // namespace caf } // namespace caf
#endif // CAF_CHECK_TYPED_INPUT_HPP #endif // CAF_CHECK_TYPED_INPUT_HPP
...@@ -23,6 +23,9 @@ ...@@ -23,6 +23,9 @@
// this header must be generated by the build system (may be empty) // this header must be generated by the build system (may be empty)
#include "caf/detail/build_config.hpp" #include "caf/detail/build_config.hpp"
// Platform-specific adjustments.
#define CAF_CACHE_LINE_SIZE 64
// Config pararameters defined by the build system (usually CMake): // Config pararameters defined by the build system (usually CMake):
// //
// CAF_ENABLE_RUNTIME_CHECKS: // CAF_ENABLE_RUNTIME_CHECKS:
......
...@@ -20,8 +20,8 @@ ...@@ -20,8 +20,8 @@
#ifndef CAF_DECORATOR_ADAPTER_HPP #ifndef CAF_DECORATOR_ADAPTER_HPP
#define CAF_DECORATOR_ADAPTER_HPP #define CAF_DECORATOR_ADAPTER_HPP
#include "caf/actor.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/actor_addr.hpp"
#include "caf/attachable.hpp" #include "caf/attachable.hpp"
#include "caf/monitorable_actor.hpp" #include "caf/monitorable_actor.hpp"
...@@ -36,7 +36,7 @@ namespace decorator { ...@@ -36,7 +36,7 @@ namespace decorator {
/// the same actor system and node as decorated actors. /// the same actor system and node as decorated actors.
class adapter : public monitorable_actor { class adapter : public monitorable_actor {
public: public:
adapter(actor_addr decorated, message msg); adapter(strong_actor_ptr decorated, message msg);
// non-system messages are processed and then forwarded; // non-system messages are processed and then forwarded;
// system messages are handled and consumed on the spot; // system messages are handled and consumed on the spot;
...@@ -44,7 +44,7 @@ public: ...@@ -44,7 +44,7 @@ public:
void enqueue(mailbox_element_ptr what, execution_unit* host) override; void enqueue(mailbox_element_ptr what, execution_unit* host) override;
private: private:
actor_addr decorated_; strong_actor_ptr decorated_;
message merger_; message merger_;
}; };
......
...@@ -38,7 +38,8 @@ class sequencer : public monitorable_actor { ...@@ -38,7 +38,8 @@ class sequencer : public monitorable_actor {
public: public:
using message_types_set = std::set<std::string>; using message_types_set = std::set<std::string>;
sequencer(actor_addr f, actor_addr g, message_types_set msg_types); sequencer(strong_actor_ptr f, strong_actor_ptr g,
message_types_set msg_types);
// non-system messages are processed and then forwarded; // non-system messages are processed and then forwarded;
// system messages are handled and consumed on the spot; // system messages are handled and consumed on the spot;
...@@ -48,8 +49,8 @@ public: ...@@ -48,8 +49,8 @@ public:
message_types_set message_types() const override; message_types_set message_types() const override;
private: private:
actor_addr f_; strong_actor_ptr f_;
actor_addr g_; strong_actor_ptr g_;
message_types_set msg_types_; message_types_set msg_types_;
}; };
......
...@@ -40,7 +40,7 @@ class splitter : public monitorable_actor { ...@@ -40,7 +40,7 @@ class splitter : public monitorable_actor {
public: public:
using message_types_set = std::set<std::string>; using message_types_set = std::set<std::string>;
splitter(std::vector<actor_addr> workers, message_types_set msg_types); splitter(std::vector<strong_actor_ptr> workers, message_types_set msg_types);
// non-system messages are processed and then forwarded; // non-system messages are processed and then forwarded;
// system messages are handled and consumed on the spot; // system messages are handled and consumed on the spot;
...@@ -50,7 +50,7 @@ public: ...@@ -50,7 +50,7 @@ public:
message_types_set message_types() const override; message_types_set message_types() const override;
private: private:
std::vector<actor_addr> workers_; std::vector<strong_actor_ptr> workers_;
message_types_set msg_types_; message_types_set msg_types_;
}; };
......
...@@ -22,8 +22,6 @@ ...@@ -22,8 +22,6 @@
#include "caf/config.hpp" #include "caf/config.hpp"
#define CAF_CACHE_LINE_SIZE 64
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <atomic> #include <atomic>
......
...@@ -103,7 +103,7 @@ public: ...@@ -103,7 +103,7 @@ public:
const std::vector<actor>& workers, const std::vector<actor>& workers,
mailbox_element_ptr& ptr, mailbox_element_ptr& ptr,
execution_unit* host) { execution_unit* host) {
if (ptr->sender == invalid_actor_addr) if (! ptr->sender)
return; return;
actor_msg_vec xs(workers.size()); actor_msg_vec xs(workers.size());
for (size_t i = 0; i < workers.size(); ++i) for (size_t i = 0; i < workers.size(); ++i)
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <cstdint> #include <cstdint>
#include "caf/fwd.hpp"
#include "caf/exit_reason.hpp" #include "caf/exit_reason.hpp"
namespace caf { namespace caf {
...@@ -39,7 +40,7 @@ namespace detail { ...@@ -39,7 +40,7 @@ namespace detail {
struct sync_request_bouncer { struct sync_request_bouncer {
exit_reason rsn; exit_reason rsn;
explicit sync_request_bouncer(exit_reason r); explicit sync_request_bouncer(exit_reason r);
void operator()(const actor_addr& sender, const message_id& mid) const; void operator()(const strong_actor_ptr& sender, const message_id& mid) const;
void operator()(const mailbox_element& e) const; void operator()(const mailbox_element& e) const;
}; };
......
...@@ -44,7 +44,6 @@ using sorted_builtin_types = ...@@ -44,7 +44,6 @@ using sorted_builtin_types =
actor_addr, // @addr actor_addr, // @addr
std::vector<actor_addr>, // @addrvec std::vector<actor_addr>, // @addrvec
atom_value, // @atom atom_value, // @atom
channel, // @channel
std::vector<char>, // @charbuf std::vector<char>, // @charbuf
down_msg, // @down down_msg, // @down
duration, // @duration duration, // @duration
...@@ -62,6 +61,7 @@ using sorted_builtin_types = ...@@ -62,6 +61,7 @@ using sorted_builtin_types =
node_id, // @node node_id, // @node
std::string, // @str std::string, // @str
strmap, // @strmap strmap, // @strmap
strong_actor_ptr, // @strong_actor_ptr
std::set<std::string>, // @strset std::set<std::string>, // @strset
std::vector<std::string>, // @strvec std::vector<std::string>, // @strvec
timeout_msg, // @timeout timeout_msg, // @timeout
...@@ -72,6 +72,7 @@ using sorted_builtin_types = ...@@ -72,6 +72,7 @@ using sorted_builtin_types =
uint64_t, // @u64 uint64_t, // @u64
uint8_t, // @u8 uint8_t, // @u8
unit_t, // @unit unit_t, // @unit
weak_actor_ptr, // @weak_actor_ptr
bool, // bool bool, // bool
double, // double double, // double
float // float float // float
......
...@@ -120,7 +120,7 @@ struct is_builtin { ...@@ -120,7 +120,7 @@ struct is_builtin {
|| is_one_of<T, anything, std::string, || is_one_of<T, anything, std::string,
std::u16string, std::u32string, std::u16string, std::u32string,
atom_value, message, actor, group, atom_value, message, actor, group,
channel, node_id>::value; node_id>::value;
}; };
/// Chekcs wheter `T` is primitive, i.e., either an arithmetic /// Chekcs wheter `T` is primitive, i.e., either an arithmetic
......
...@@ -30,8 +30,9 @@ namespace caf { ...@@ -30,8 +30,9 @@ namespace caf {
/// Implements a simple proxy forwarding all operations to a manager. /// Implements a simple proxy forwarding all operations to a manager.
class forwarding_actor_proxy : public actor_proxy { class forwarding_actor_proxy : public actor_proxy {
public: public:
forwarding_actor_proxy(actor_system* sys, actor_id mid, using forwarding_stack = std::vector<strong_actor_ptr>;
node_id pinfo, actor parent);
forwarding_actor_proxy(actor parent);
~forwarding_actor_proxy(); ~forwarding_actor_proxy();
...@@ -50,8 +51,8 @@ public: ...@@ -50,8 +51,8 @@ public:
void manager(actor new_manager); void manager(actor new_manager);
private: private:
void forward_msg(const actor_addr& sender, message_id mid, message msg, void forward_msg(strong_actor_ptr sender, message_id mid, message msg,
const std::vector<actor_addr>* fwd_stack = nullptr); const forwarding_stack* fwd_stack = nullptr);
mutable detail::shared_spinlock manager_mtx_; mutable detail::shared_spinlock manager_mtx_;
actor manager_; actor manager_;
......
...@@ -25,15 +25,19 @@ ...@@ -25,15 +25,19 @@
namespace caf { namespace caf {
// templates // 1-class templates
template <class> class maybe; template <class> class maybe;
template <class> class optional; template <class> class optional;
template <class> class intrusive_ptr; template <class> class intrusive_ptr;
template <class> struct actor_cast_access; template <class> class weak_intrusive_ptr;
template <class> class typed_continue_helper; template <class> class typed_continue_helper;
// 2-class templates
template <class, class, int> class actor_cast_access;
// variadic templates // variadic templates
template <class...> class delegated; template <class...> class delegated;
template <class...> class typed_actor;
template <class...> class typed_response_promise; template <class...> class typed_response_promise;
// classes // classes
...@@ -41,7 +45,6 @@ class actor; ...@@ -41,7 +45,6 @@ class actor;
class group; class group;
class error; class error;
class message; class message;
class channel;
class node_id; class node_id;
class duration; class duration;
class behavior; class behavior;
...@@ -69,6 +72,7 @@ class message_handler; ...@@ -69,6 +72,7 @@ class message_handler;
class response_promise; class response_promise;
class event_based_actor; class event_based_actor;
class binary_serializer; class binary_serializer;
class actor_control_block;
class binary_deserializer; class binary_deserializer;
class actor_system_config; class actor_system_config;
class uniform_type_info_map; class uniform_type_info_map;
...@@ -133,6 +137,8 @@ class dynamic_message_data; ...@@ -133,6 +137,8 @@ class dynamic_message_data;
} // namespace detail } // namespace detail
using strong_actor_ptr = intrusive_ptr<actor_control_block>;
using weak_actor_ptr = weak_intrusive_ptr<actor_control_block>;
using mailbox_element_ptr = std::unique_ptr<mailbox_element, detail::disposer>; using mailbox_element_ptr = std::unique_ptr<mailbox_element, detail::disposer>;
} // namespace caf } // namespace caf
......
...@@ -31,9 +31,6 @@ ...@@ -31,9 +31,6 @@
namespace caf { namespace caf {
class channel;
class message;
struct invalid_group_t { struct invalid_group_t {
constexpr invalid_group_t() {} constexpr invalid_group_t() {}
}; };
...@@ -45,8 +42,8 @@ constexpr invalid_group_t invalid_group = invalid_group_t{}; ...@@ -45,8 +42,8 @@ constexpr invalid_group_t invalid_group = invalid_group_t{};
class group : detail::comparable<group>, class group : detail::comparable<group>,
detail::comparable<group, invalid_group_t> { detail::comparable<group, invalid_group_t> {
public: public:
template <class> template <class, class, int>
friend struct actor_cast_access; friend class actor_cast_access;
group() = default; group() = default;
...@@ -95,11 +92,11 @@ public: ...@@ -95,11 +92,11 @@ public:
friend void serialize(deserializer& sink, group& x, const unsigned int); friend void serialize(deserializer& sink, group& x, const unsigned int);
private:
inline abstract_group* get() const noexcept { inline abstract_group* get() const noexcept {
return ptr_.get(); return ptr_.get();
} }
private:
inline abstract_group* release() noexcept { inline abstract_group* release() noexcept {
return ptr_.release(); return ptr_.release();
} }
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
#include "caf/ref_counted.hpp"
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
namespace caf { namespace caf {
...@@ -43,6 +42,9 @@ public: ...@@ -43,6 +42,9 @@ public:
using reference = T&; using reference = T&;
using const_reference = const T&; using const_reference = const T&;
// tell actor_cast which semantic this type uses
static constexpr bool has_weak_ptr_semantics = false;
constexpr intrusive_ptr() : ptr_(nullptr) { constexpr intrusive_ptr() : ptr_(nullptr) {
// nop // nop
} }
...@@ -78,7 +80,8 @@ public: ...@@ -78,7 +80,8 @@ public:
/// count and sets this to `nullptr`. /// count and sets this to `nullptr`.
pointer detach() noexcept { pointer detach() noexcept {
auto result = ptr_; auto result = ptr_;
ptr_ = nullptr; if (result)
ptr_ = nullptr;
return result; return result;
} }
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_IS_MESSAGE_SINK_HPP
#define CAF_IS_MESSAGE_SINK_HPP
#include <type_traits>
#include "caf/fwd.hpp"
namespace caf {
template <class T>
struct is_message_sink : std::false_type { };
template <>
struct is_message_sink<actor> : std::true_type { };
template <>
struct is_message_sink<group> : std::true_type { };
template <class... Ts>
struct is_message_sink<typed_actor<Ts...>> : std::true_type { };
} // namespace caf
#endif // CAF_IS_MESSAGE_SINK_HPP
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
#include "caf/extend.hpp" #include "caf/extend.hpp"
#include "caf/logger.hpp" #include "caf/logger.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/channel.hpp"
#include "caf/duration.hpp" #include "caf/duration.hpp"
#include "caf/behavior.hpp" #include "caf/behavior.hpp"
#include "caf/delegated.hpp" #include "caf/delegated.hpp"
...@@ -92,7 +91,7 @@ public: ...@@ -92,7 +91,7 @@ public:
using mailbox_type = detail::single_reader_queue<mailbox_element, using mailbox_type = detail::single_reader_queue<mailbox_element,
detail::disposer>; detail::disposer>;
static constexpr auto memory_cache_flag = detail::needs_embedding; //static constexpr auto memory_cache_flag = detail::needs_embedding;
~local_actor(); ~local_actor();
...@@ -159,19 +158,34 @@ public: ...@@ -159,19 +158,34 @@ public:
/// Sends `{xs...}` to `dest` using the priority `mp`. /// Sends `{xs...}` to `dest` using the priority `mp`.
template <class... Ts> template <class... Ts>
void send(message_priority mp, const channel& dest, Ts&&... xs) { void send(message_priority mp, const actor& dest, Ts&&... xs) {
static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0"); static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0");
send_impl(message_id::make(mp), actor_cast<abstract_channel*>(dest), send_impl(message_id::make(mp), actor_cast<abstract_actor*>(dest),
std::forward<Ts>(xs)...); std::forward<Ts>(xs)...);
} }
/// Sends `{xs...}` to `dest` using normal priority. /// Sends `{xs...}` to `dest` using normal priority.
template <class... Ts> template <class... Ts>
void send(const channel& dest, Ts&&... xs) { void send(const actor& dest, Ts&&... xs) {
send_impl(message_id::make(), actor_cast<abstract_channel*>(dest), send_impl(message_id::make(), actor_cast<abstract_actor*>(dest),
std::forward<Ts>(xs)...); std::forward<Ts>(xs)...);
} }
/// Sends `{xs...}` to `dest` using the priority `mp`.
template <class... Ts>
void send(message_priority mp, const group& dest, Ts&&... xs) {
static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0");
send_impl(message_id::make(mp), actor_cast<abstract_channel*>(dest),
make_message(std::forward<Ts>(xs)...));
}
/// Sends `{xs...}` to `dest` using normal priority.
template <class... Ts>
void send(const group& dest, Ts&&... xs) {
send_impl(message_id::make(), dest.get(),
make_message(std::forward<Ts>(xs)...));
}
/// Sends `{xs...}` to `dest` using the priority `mp`. /// Sends `{xs...}` to `dest` using the priority `mp`.
template <class... Sigs, class... Ts> template <class... Sigs, class... Ts>
void send(message_priority mp, const typed_actor<Sigs...>& dest, Ts&&... xs) { void send(message_priority mp, const typed_actor<Sigs...>& dest, Ts&&... xs) {
...@@ -200,6 +214,12 @@ public: ...@@ -200,6 +214,12 @@ public:
std::forward<Ts>(xs)...); std::forward<Ts>(xs)...);
} }
/// Sends `{xs...}` to `dest` using normal priority.
template <class... Sigs, class... Ts>
void send(typed_event_based_actor<Sigs...>* dest, Ts&&... xs) {
send(typed_actor<Sigs...>{dest}, std::forward<Ts>(xs)...);
}
/// Sends an exit message to `dest`. /// Sends an exit message to `dest`.
void send_exit(const actor_addr& dest, exit_reason reason); void send_exit(const actor_addr& dest, exit_reason reason);
...@@ -212,7 +232,7 @@ public: ...@@ -212,7 +232,7 @@ public:
/// Sends a message to `dest` that is delayed by `rel_time` /// Sends a message to `dest` that is delayed by `rel_time`
/// using the priority `mp`. /// using the priority `mp`.
template <class... Ts> template <class... Ts>
void delayed_send(message_priority mp, const channel& dest, void delayed_send(message_priority mp, const actor& dest,
const duration& rtime, Ts&&... xs) { const duration& rtime, Ts&&... xs) {
delayed_send_impl(message_id::make(mp), dest, rtime, delayed_send_impl(message_id::make(mp), dest, rtime,
make_message(std::forward<Ts>(xs)...)); make_message(std::forward<Ts>(xs)...));
...@@ -220,9 +240,9 @@ public: ...@@ -220,9 +240,9 @@ public:
/// Sends a message to `dest` that is delayed by `rel_time`. /// Sends a message to `dest` that is delayed by `rel_time`.
template <class... Ts> template <class... Ts>
void delayed_send(const channel& dest, const duration& rtime, Ts&&... xs) { void delayed_send(const actor& dest, const duration& rtime, Ts&&... xs) {
delayed_send_impl(message_id::make(), dest, rtime, delayed_send_impl(message_id::make(), actor_cast<strong_actor_ptr>(dest),
make_message(std::forward<Ts>(xs)...)); rtime, make_message(std::forward<Ts>(xs)...));
} }
/// Sends `{xs...}` delayed by `rtime` to `dest` using the priority `mp`. /// Sends `{xs...}` delayed by `rtime` to `dest` using the priority `mp`.
...@@ -236,7 +256,7 @@ public: ...@@ -236,7 +256,7 @@ public:
>::type...>; >::type...>;
token tk; token tk;
check_typed_input(dest, tk); check_typed_input(dest, tk);
delayed_send_impl(message_id::make(mp), actor_cast<abstract_channel*>(dest), delayed_send_impl(message_id::make(mp), actor_cast<abstract_actor*>(dest),
rtime, make_message(std::forward<Ts>(xs)...)); rtime, make_message(std::forward<Ts>(xs)...));
} }
...@@ -252,10 +272,17 @@ public: ...@@ -252,10 +272,17 @@ public:
>::type...>; >::type...>;
token tk; token tk;
check_typed_input(dest, tk); check_typed_input(dest, tk);
delayed_send_impl(message_id::make(), actor_cast<channel>(dest), delayed_send_impl(message_id::make(), actor_cast<strong_actor_ptr>(dest),
rtime, make_message(std::forward<Ts>(xs)...)); rtime, make_message(std::forward<Ts>(xs)...));
} }
/// Sends `{xs...}` to `dest` using normal priority.
template <class... Sigs, class... Ts>
void delayed_send(typed_event_based_actor<Sigs...>* dest,
const duration& rtime, Ts&&... xs) {
delayed_send(typed_actor<Sigs...>{dest}, rtime, std::forward<Ts>(xs)...);
}
/**************************************************************************** /****************************************************************************
* miscellaneous actor operations * * miscellaneous actor operations *
****************************************************************************/ ****************************************************************************/
...@@ -314,6 +341,7 @@ public: ...@@ -314,6 +341,7 @@ public:
} }
/// @cond PRIVATE /// @cond PRIVATE
/// Returns the currently processed message. /// Returns the currently processed message.
/// @warning Only set during callback invocation. Calling this member function /// @warning Only set during callback invocation. Calling this member function
/// is undefined behavior (dereferencing a `nullptr`) when not in a /// is undefined behavior (dereferencing a `nullptr`) when not in a
...@@ -321,29 +349,24 @@ public: ...@@ -321,29 +349,24 @@ public:
inline message& current_message() { inline message& current_message() {
return current_element_->msg; return current_element_->msg;
} }
void monitor(abstract_actor* whom);
/// @endcond /// @endcond
/// Returns the address of the sender of the current message. /// Returns the address of the sender of the current message.
/// @warning Only set during callback invocation. Calling this member function /// @warning Only set during callback invocation. Calling this member function
/// is undefined behavior (dereferencing a `nullptr`) when not in a /// is undefined behavior (dereferencing a `nullptr`) when not in a
/// callback or `forward_to` has been called previously. /// callback or `forward_to` has been called previously.
inline actor_addr& current_sender() { inline actor_addr current_sender() {
return current_element_->sender; return actor_cast<actor_addr>(current_element_->sender);
} }
/// Adds a unidirectional `monitor` to `whom`. /// Adds a unidirectional `monitor` to `whom`.
/// @note Each call to `monitor` creates a new, independent monitor. /// @note Each call to `monitor` creates a new, independent monitor.
void monitor(const actor_addr& whom); template <class Handle>
void monitor(const Handle& whom) {
/// @copydoc monitor(const actor_addr&) monitor(actor_cast<abstract_actor*>(whom));
inline void monitor(const actor& whom) {
monitor(whom.address());
}
/// @copydoc monitor(const actor_addr&)
template <class... Ts>
inline void monitor(const typed_actor<Ts...>& whom) {
monitor(whom.address());
} }
/// Removes a monitor from `whom`. /// Removes a monitor from `whom`.
...@@ -429,8 +452,6 @@ public: ...@@ -429,8 +452,6 @@ public:
subtype_t subtype() const override; subtype_t subtype() const override;
ref_counted* as_ref_counted_ptr() override;
resume_result resume(execution_unit*, size_t) override; resume_result resume(execution_unit*, size_t) override;
/**************************************************************************** /****************************************************************************
...@@ -446,11 +467,15 @@ public: ...@@ -446,11 +467,15 @@ public:
// handle `ptr` in an event-based actor, not suitable to be called in a loop // handle `ptr` in an event-based actor, not suitable to be called in a loop
virtual void exec_single_event(execution_unit* ctx, mailbox_element_ptr& ptr); virtual void exec_single_event(execution_unit* ctx, mailbox_element_ptr& ptr);
local_actor();
local_actor(int init_flags);
local_actor(actor_config& sys); local_actor(actor_config& sys);
local_actor(actor_system* sys, actor_id aid, node_id nid); void intrusive_ptr_add_ref_impl() override;
local_actor(actor_system* sys, actor_id aid, node_id nid, int init_flags); void intrusive_ptr_release_impl() override;
template <class ActorHandle> template <class ActorHandle>
inline ActorHandle eval_opts(spawn_options opts, ActorHandle res) { inline ActorHandle eval_opts(spawn_options opts, ActorHandle res) {
...@@ -689,18 +714,6 @@ protected: ...@@ -689,18 +714,6 @@ protected:
/// @endcond /// @endcond
private: private:
template <class T, class... Ts>
typename std::enable_if<
! std::is_same<typename std::decay<T>::type, message>::value
>::type
send_impl(message_id mid, abstract_channel* dest, T&& x, Ts&&... xs) const {
if (! dest)
return;
dest->enqueue(address(), mid,
make_message(std::forward<T>(x), std::forward<Ts>(xs)...),
context());
}
template <class T, class... Ts> template <class T, class... Ts>
typename std::enable_if< typename std::enable_if<
! std::is_same<typename std::decay<T>::type, message>::value ! std::is_same<typename std::decay<T>::type, message>::value
...@@ -708,8 +721,7 @@ private: ...@@ -708,8 +721,7 @@ private:
send_impl(message_id mid, abstract_actor* dest, T&& x, Ts&&... xs) const { send_impl(message_id mid, abstract_actor* dest, T&& x, Ts&&... xs) const {
if (! dest) if (! dest)
return; return;
dest->enqueue(mailbox_element::make_joint(address(), dest->enqueue(mailbox_element::make_joint(ctrl(), mid, {},
mid, {},
std::forward<T>(x), std::forward<T>(x),
std::forward<Ts>(xs)...), std::forward<Ts>(xs)...),
context()); context());
...@@ -717,7 +729,7 @@ private: ...@@ -717,7 +729,7 @@ private:
void send_impl(message_id mid, abstract_channel* dest, message what) const; void send_impl(message_id mid, abstract_channel* dest, message what) const;
void delayed_send_impl(message_id mid, const channel& whom, void delayed_send_impl(message_id mid, strong_actor_ptr whom,
const duration& rtime, message data); const duration& rtime, message data);
}; };
......
...@@ -22,9 +22,9 @@ ...@@ -22,9 +22,9 @@
#include <cstddef> #include <cstddef>
#include "caf/actor.hpp"
#include "caf/extend.hpp" #include "caf/extend.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/actor_addr.hpp"
#include "caf/message_id.hpp" #include "caf/message_id.hpp"
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
...@@ -42,7 +42,7 @@ class mailbox_element : public memory_managed { ...@@ -42,7 +42,7 @@ class mailbox_element : public memory_managed {
public: public:
static constexpr auto memory_cache_flag = detail::needs_embedding; static constexpr auto memory_cache_flag = detail::needs_embedding;
using forwarding_stack = std::vector<actor_addr>; using forwarding_stack = std::vector<strong_actor_ptr>;
// intrusive pointer to the next mailbox element // intrusive pointer to the next mailbox element
mailbox_element* next; mailbox_element* next;
...@@ -51,7 +51,7 @@ public: ...@@ -51,7 +51,7 @@ public:
// avoid multi-processing in blocking actors via flagging // avoid multi-processing in blocking actors via flagging
bool marked; bool marked;
// source of this message and receiver of the final response // source of this message and receiver of the final response
actor_addr sender; strong_actor_ptr sender;
// denotes whether this a sync or async message // denotes whether this a sync or async message
message_id mid; message_id mid;
// stages.back() is the next actor in the forwarding chain, // stages.back() is the next actor in the forwarding chain,
...@@ -61,8 +61,11 @@ public: ...@@ -61,8 +61,11 @@ public:
message msg; message msg;
mailbox_element(); mailbox_element();
mailbox_element(actor_addr sender, message_id id, forwarding_stack stages);
mailbox_element(actor_addr sender, message_id id, mailbox_element(strong_actor_ptr sender, message_id id,
forwarding_stack stages);
mailbox_element(strong_actor_ptr sender, message_id id,
forwarding_stack stages, message data); forwarding_stack stages, message data);
~mailbox_element(); ~mailbox_element();
...@@ -74,11 +77,11 @@ public: ...@@ -74,11 +77,11 @@ public:
using unique_ptr = std::unique_ptr<mailbox_element, detail::disposer>; using unique_ptr = std::unique_ptr<mailbox_element, detail::disposer>;
static unique_ptr make(actor_addr sender, message_id id, static unique_ptr make(strong_actor_ptr sender, message_id id,
forwarding_stack stages, message msg); forwarding_stack stages, message msg);
template <class... Ts> template <class... Ts>
static unique_ptr make_joint(actor_addr sender, message_id id, static unique_ptr make_joint(strong_actor_ptr sender, message_id id,
forwarding_stack stages, Ts&&... xs) { forwarding_stack stages, Ts&&... xs) {
using value_storage = using value_storage =
detail::tuple_vals< detail::tuple_vals<
......
...@@ -17,111 +17,27 @@ ...@@ -17,111 +17,27 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#ifndef CAF_CHANNEL_HPP #ifndef CAF_MAKE_ACTOR_HPP
#define CAF_CHANNEL_HPP #define CAF_MAKE_ACTOR_HPP
#include <cstddef>
#include <type_traits> #include <type_traits>
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/ref_counted.hpp"
#include "caf/infer_handle.hpp"
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
#include "caf/abstract_channel.hpp" #include "caf/actor_storage.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/comparable.hpp"
namespace caf { namespace caf {
struct invalid_channel_t { template <class T, class R = infer_handle_from_class_t<T>, class... Ts>
constexpr invalid_channel_t() { R make_actor(actor_id aid, node_id nid, actor_system* sys, Ts&&... xs) {
// nop auto ptr = new actor_storage<T>(aid, std::move(nid), sys,
} std::forward<Ts>(xs)...);
}; return {&(ptr->ctrl), false};
}
/// Identifies an invalid {@link channel}.
/// @relates channel
constexpr invalid_channel_t invalid_channel = invalid_channel_t{};
/// A handle to instances of `abstract_channel`.
class channel : detail::comparable<channel>,
detail::comparable<channel, actor>,
detail::comparable<channel, abstract_channel*> {
public:
template <class>
friend struct actor_cast_access;
channel() = default;
channel(channel&&) = default;
channel(const channel&) = default;
channel& operator=(channel&&) = default;
channel& operator=(const channel&) = default;
channel(const actor&);
channel(const group&);
channel(const scoped_actor&);
channel(const invalid_channel_t&);
template <class T>
channel(intrusive_ptr<T> ptr,
typename std::enable_if<
std::is_base_of<abstract_channel, T>::value
>::type* = 0)
: ptr_(ptr) {
// nop
}
/// Allows actors to create a `channel` handle from `this`.
channel(local_actor*);
channel& operator=(const actor&);
channel& operator=(const group&);
channel& operator=(const scoped_actor&);
channel& operator=(const invalid_channel_t&);
inline explicit operator bool() const noexcept {
return static_cast<bool>(ptr_);
}
inline bool operator!() const noexcept {
return ! ptr_;
}
inline abstract_channel* operator->() const noexcept {
return get();
}
inline abstract_channel& operator*() const noexcept {
return *ptr_;
}
intptr_t compare(const channel& other) const noexcept;
intptr_t compare(const actor& other) const noexcept;
intptr_t compare(const abstract_channel* other) const noexcept;
/// @relates channel
friend void serialize(serializer& sink, channel& x, const unsigned int);
/// @relates channel
friend void serialize(deserializer& source, channel& x, const unsigned int);
private:
channel(abstract_channel*);
channel(abstract_channel*, bool);
inline abstract_channel* get() const noexcept {
return ptr_.get();
}
abstract_channel_ptr ptr_;
};
/// @relates channel
std::string to_string(const channel& x);
} // namespace caf } // namespace caf
#endif // CAF_CHANNEL_HPP #endif // CAF_MAKE_ACTOR_HPP
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#ifndef CAF_MAKE_COUNTED_HPP #ifndef CAF_MAKE_COUNTED_HPP
#define CAF_MAKE_COUNTED_HPP #define CAF_MAKE_COUNTED_HPP
#include <type_traits>
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
......
...@@ -79,10 +79,7 @@ protected: ...@@ -79,10 +79,7 @@ protected:
explicit monitorable_actor(actor_config& cfg); explicit monitorable_actor(actor_config& cfg);
/// Creates a new actor instance. /// Creates a new actor instance.
monitorable_actor(actor_system* sys, actor_id aid, node_id nid); explicit monitorable_actor(int flags);
/// Creates a new actor instance.
monitorable_actor(actor_system* sys, actor_id aid, node_id nid, int flags);
/**************************************************************************** /****************************************************************************
* here be dragons: end of public interface * * here be dragons: end of public interface *
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/node_id.hpp" #include "caf/node_id.hpp"
#include "caf/actor_addr.hpp"
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/actor_proxy.hpp" #include "caf/actor_proxy.hpp"
#include "caf/exit_reason.hpp" #include "caf/exit_reason.hpp"
...@@ -44,7 +45,7 @@ public: ...@@ -44,7 +45,7 @@ public:
virtual ~backend(); virtual ~backend();
/// Creates a new proxy instance. /// Creates a new proxy instance.
virtual actor_proxy_ptr make_proxy(key_type, actor_id) = 0; virtual strong_actor_ptr make_proxy(key_type, actor_id) = 0;
virtual execution_unit* registry_context() = 0; virtual execution_unit* registry_context() = 0;
}; };
...@@ -54,6 +55,8 @@ public: ...@@ -54,6 +55,8 @@ public:
proxy_registry(const proxy_registry&) = delete; proxy_registry(const proxy_registry&) = delete;
proxy_registry& operator=(const proxy_registry&) = delete; proxy_registry& operator=(const proxy_registry&) = delete;
~proxy_registry();
void serialize(serializer& sink, const actor_addr& addr) const; void serialize(serializer& sink, const actor_addr& addr) const;
void serialize(deserializer& source, actor_addr& addr); void serialize(deserializer& source, actor_addr& addr);
...@@ -66,51 +69,21 @@ public: ...@@ -66,51 +69,21 @@ public:
/// addresses for remote actors on the fly if needed. /// addresses for remote actors on the fly if needed.
actor_addr read(deserializer* source); actor_addr read(deserializer* source);
/// Ensures that `kill_proxy` is called for each proxy instance.
class proxy_entry {
public:
proxy_entry();
proxy_entry(actor_proxy::anchor_ptr ptr, backend& ctx);
proxy_entry(proxy_entry&&) = default;
proxy_entry& operator=(proxy_entry&&) = default;
~proxy_entry();
void reset(exit_reason rsn);
void assign(actor_proxy::anchor_ptr ptr, backend& ctx);
inline explicit operator bool() const {
return static_cast<bool>(ptr_);
}
inline actor_proxy::anchor* operator->() const {
return ptr_.get();
}
private:
actor_proxy::anchor_ptr ptr_;
backend* backend_;
};
/// A map that stores all proxies for known remote actors. /// A map that stores all proxies for known remote actors.
using proxy_map = std::map<actor_id, proxy_entry>; using proxy_map = std::map<actor_id, strong_actor_ptr>;
/// Returns the number of proxies for `node`. /// Returns the number of proxies for `node`.
size_t count_proxies(const key_type& node); size_t count_proxies(const key_type& node);
/// Returns all proxies for `node`. /// Returns the proxy instance identified by `node` and `aid`.
std::vector<actor_proxy_ptr> get_all() const; strong_actor_ptr get(const key_type& node, actor_id aid);
/// Returns all proxies for `node`.
std::vector<actor_proxy_ptr> get_all(const key_type& node) const;
/// Returns the proxy instance identified by `node` and `aid`
/// or `nullptr` if the actor either unknown or expired.
actor_proxy_ptr get(const key_type& node, actor_id aid);
/// Returns the proxy instance identified by `node` and `aid` /// Returns the proxy instance identified by `node` and `aid`
/// or creates a new (default) proxy instance. /// or creates a new (default) proxy instance.
actor_proxy_ptr get_or_put(const key_type& node, actor_id aid); strong_actor_ptr get_or_put(const key_type& node, actor_id aid);
/// Returns all known proxies.
std::vector<strong_actor_ptr> get_all(const key_type& node);
/// Deletes all proxies for `node`. /// Deletes all proxies for `node`.
void erase(const key_type& node); void erase(const key_type& node);
...@@ -130,6 +103,8 @@ public: ...@@ -130,6 +103,8 @@ public:
} }
private: private:
void kill_proxy(strong_actor_ptr&, exit_reason);
actor_system& system_; actor_system& system_;
backend& backend_; backend& backend_;
std::unordered_map<node_id, proxy_map> proxies_; std::unordered_map<node_id, proxy_map> proxies_;
......
...@@ -74,12 +74,12 @@ public: ...@@ -74,12 +74,12 @@ public:
/// @endcond /// @endcond
private: private:
using forwarding_stack = std::vector<actor_addr>; using forwarding_stack = std::vector<strong_actor_ptr>;
void deliver_impl(message response_message); void deliver_impl(message response_message);
local_actor* self_; local_actor* self_;
actor_addr source_; strong_actor_ptr source_;
forwarding_stack stages_; forwarding_stack stages_;
message_id id_; message_id id_;
}; };
......
...@@ -63,16 +63,15 @@ public: ...@@ -63,16 +63,15 @@ public:
/// delegate other subtypes to dedicated workers. /// delegate other subtypes to dedicated workers.
virtual subtype_t subtype() const; virtual subtype_t subtype() const;
/// Returns a pointer to this object as `ref_counted`.
virtual ref_counted* as_ref_counted_ptr() = 0;
/// Resume any pending computation until it is either finished /// Resume any pending computation until it is either finished
/// or needs to be re-scheduled later. /// or needs to be re-scheduled later.
virtual resume_result resume(execution_unit*, size_t max_throughput) = 0; virtual resume_result resume(execution_unit*, size_t max_throughput) = 0;
void intrusive_ptr_add_ref_impl(); /// Add a strong reference count to this object.
virtual void intrusive_ptr_add_ref_impl() = 0;
void intrusive_ptr_release_impl(); /// Remove a strong reference count from this object.
virtual void intrusive_ptr_release_impl() = 0;
}; };
// enables intrusive_ptr<resumable> without introducing ambiguity // enables intrusive_ptr<resumable> without introducing ambiguity
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/atom.hpp" #include "caf/atom.hpp"
#include "caf/actor.hpp" #include "caf/actor.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/duration.hpp" #include "caf/duration.hpp"
#include "caf/actor_addr.hpp" #include "caf/actor_addr.hpp"
...@@ -53,12 +52,12 @@ public: ...@@ -53,12 +52,12 @@ public:
virtual void enqueue(resumable* what) = 0; virtual void enqueue(resumable* what) = 0;
template <class Duration, class... Data> template <class Duration, class... Data>
void delayed_send(Duration rel_time, actor_addr from, channel to, void delayed_send(Duration rel_time, strong_actor_ptr from,
message_id mid, message data) { strong_actor_ptr to, message_id mid, message data) {
timer_->enqueue(invalid_actor_addr, invalid_message_id, timer_->enqueue(nullptr, invalid_message_id,
make_message(duration{rel_time}, std::move(from), make_message(duration{rel_time}, std::move(from),
std::move(to), mid, std::move(data)), std::move(to), mid, std::move(data)),
nullptr); nullptr);
} }
inline actor_system& system() { inline actor_system& system() {
......
...@@ -82,8 +82,12 @@ protected: ...@@ -82,8 +82,12 @@ protected:
cv.notify_all(); cv.notify_all();
return resumable::shutdown_execution_unit; return resumable::shutdown_execution_unit;
} }
ref_counted* as_ref_counted_ptr() override { void intrusive_ptr_add_ref_impl() override {
return this; intrusive_ptr_add_ref(this);
}
void intrusive_ptr_release_impl() override {
intrusive_ptr_release(this);
} }
shutdown_helper() : last_worker(nullptr) { shutdown_helper() : last_worker(nullptr) {
// nop // nop
......
...@@ -20,7 +20,9 @@ ...@@ -20,7 +20,9 @@
#ifndef CAF_SCOPED_ACTOR_HPP #ifndef CAF_SCOPED_ACTOR_HPP
#define CAF_SCOPED_ACTOR_HPP #define CAF_SCOPED_ACTOR_HPP
#include "caf/actor_cast.hpp"
#include "caf/actor_system.hpp" #include "caf/actor_system.hpp"
#include "caf/actor_storage.hpp"
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
#include "caf/blocking_actor.hpp" #include "caf/blocking_actor.hpp"
#include "caf/scoped_execution_unit.hpp" #include "caf/scoped_execution_unit.hpp"
...@@ -30,6 +32,13 @@ namespace caf { ...@@ -30,6 +32,13 @@ namespace caf {
/// A scoped handle to a blocking actor. /// A scoped handle to a blocking actor.
class scoped_actor { class scoped_actor {
public: public:
// allow conversion via actor_cast
template <class, class, int>
friend class actor_cast_access;
// tell actor_cast which semantic this type uses
static constexpr bool has_weak_ptr_semantics = false;
scoped_actor(const scoped_actor&) = delete; scoped_actor(const scoped_actor&) = delete;
scoped_actor(actor_system& sys, bool hide_actor = false); scoped_actor(actor_system& sys, bool hide_actor = false);
...@@ -40,25 +49,28 @@ public: ...@@ -40,25 +49,28 @@ public:
~scoped_actor(); ~scoped_actor();
inline blocking_actor* operator->() const { inline blocking_actor* operator->() const {
return self_.get(); return ptr();
} }
inline blocking_actor& operator*() const { inline blocking_actor& operator*() const {
return *self_; return *ptr();
}
inline blocking_actor* get() const {
return self_.get();
} }
inline actor_addr address() const { inline actor_addr address() const {
return self_->address(); return ptr()->address();
} }
blocking_actor* ptr() const;
private: private:
inline actor_control_block* get() const {
return self_.get();
}
actor_id prev_; // used for logging/debugging purposes only actor_id prev_; // used for logging/debugging purposes only
scoped_execution_unit context_; scoped_execution_unit context_;
intrusive_ptr<blocking_actor> self_; strong_actor_ptr self_;
}; };
std::string to_string(const scoped_actor& x); std::string to_string(const scoped_actor& x);
......
...@@ -21,40 +21,22 @@ ...@@ -21,40 +21,22 @@
#define CAF_SEND_HPP #define CAF_SEND_HPP
#include "caf/actor.hpp" #include "caf/actor.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/actor_addr.hpp" #include "caf/actor_addr.hpp"
#include "caf/message_id.hpp" #include "caf/message_id.hpp"
#include "caf/message_priority.hpp"
#include "caf/typed_actor.hpp" #include "caf/typed_actor.hpp"
#include "caf/is_message_sink.hpp"
#include "caf/message_priority.hpp"
#include "caf/system_messages.hpp" #include "caf/system_messages.hpp"
#include "caf/check_typed_input.hpp" #include "caf/check_typed_input.hpp"
namespace caf { namespace caf {
/// Sends `to` a message under the identity of `from` with priority `prio`. /// Sends `to` a message under the identity of `from` with priority `prio`.
template <class... Ts> template <class Dest, class... Ts>
void send_as(const actor& from, message_priority prio, typename std::enable_if<is_message_sink<Dest>::value>::type
const channel& to, Ts&&... xs) { send_as(actor from, message_priority prio, const Dest& to, Ts&&... xs) {
if (! to)
return;
message_id mid;
to->enqueue(from.address(),
prio == message_priority::high ? mid.with_high_priority() : mid,
make_message(std::forward<Ts>(xs)...), nullptr);
}
/// Sends `to` a message under the identity of `from`.
template <class... Ts>
void send_as(const actor& from, const channel& to, Ts&&... xs) {
send_as(from, message_priority::normal, to, std::forward<Ts>(xs)...);
}
/// Sends `to` a message under the identity of `from` with priority `prio`.
template <class... Sigs, class... Ts>
void send_as(const actor& from, message_priority prio,
const typed_actor<Sigs...>& to, Ts&&... xs) {
using token = using token =
detail::type_list< detail::type_list<
typename detail::implicit_conversions< typename detail::implicit_conversions<
...@@ -62,76 +44,48 @@ void send_as(const actor& from, message_priority prio, ...@@ -62,76 +44,48 @@ void send_as(const actor& from, message_priority prio,
>::type...>; >::type...>;
token tk; token tk;
check_typed_input(to, tk); check_typed_input(to, tk);
send_as(from, prio, actor_cast<channel>(to), std::forward<Ts>(xs)...); if (! to)
return;
message_id mid;
to->enqueue(actor_cast<strong_actor_ptr>(std::move(from)),
prio == message_priority::high ? mid.with_high_priority() : mid,
make_message(std::forward<Ts>(xs)...), nullptr);
} }
/// Sends `to` a message under the identity of `from`. /// Sends `to` a message under the identity of `from`.
template <class... Sigs, class... Ts> template <class Dest, class... Ts>
void send_as(const actor& from, const typed_actor<Sigs...>& to, Ts&&... xs) { typename std::enable_if<is_message_sink<Dest>::value>::type
using token = send_as(actor from, const Dest& to, Ts&&... xs) {
detail::type_list< send_as(std::move(from), message_priority::normal,
typename detail::implicit_conversions< to, std::forward<Ts>(xs)...);
typename std::decay<Ts>::type
>::type...>;
token tk;
check_typed_input(to, tk);
send_as(from, message_priority::normal,
actor_cast<channel>(to), std::forward<Ts>(xs)...);
} }
/// Anonymously sends `to` a message with priority `prio`. /// Anonymously sends `to` a message with priority `prio`.
template <class... Ts> template <class Dest, class... Ts>
void anon_send(message_priority prio, const channel& to, Ts&&... xs) { typename std::enable_if<is_message_sink<Dest>::value>::type
anon_send(message_priority prio, const Dest& to, Ts&&... xs) {
send_as(invalid_actor, prio, to, std::forward<Ts>(xs)...); send_as(invalid_actor, prio, to, std::forward<Ts>(xs)...);
} }
/// Anonymously sends `to` a message. /// Anonymously sends `to` a message.
template <class... Ts> template <class Dest, class... Ts>
void anon_send(const channel& to, Ts&&... xs) { typename std::enable_if<is_message_sink<Dest>::value>::type
anon_send(const Dest& to, Ts&&... xs) {
send_as(invalid_actor, message_priority::normal, to, std::forward<Ts>(xs)...); send_as(invalid_actor, message_priority::normal, to, std::forward<Ts>(xs)...);
} }
/// Anonymously sends `to` a message with priority `prio`.
template <class... Sigs, class... Ts>
void anon_send(message_priority prio, const typed_actor<Sigs...>& to,
Ts&&... xs) {
using token =
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>;
token tk;
check_typed_input(to, tk);
anon_send(prio, actor_cast<channel>(to), std::forward<Ts>(xs)...);
}
/// Anonymously sends `to` a message.
template <class... Sigs, class... Ts>
void anon_send(const typed_actor<Sigs...>& to, Ts&&... xs) {
using token =
detail::type_list<
typename detail::implicit_conversions<
typename std::decay<Ts>::type
>::type...>;
token tk;
check_typed_input(to, tk);
anon_send(message_priority::normal, actor_cast<channel>(to),
std::forward<Ts>(xs)...);
}
/// Anonymously sends `to` an exit message. /// Anonymously sends `to` an exit message.
inline void anon_send_exit(const actor_addr& to, exit_reason reason) { template <class ActorHandle>
void anon_send_exit(const ActorHandle& to, exit_reason reason) {
if (! to) if (! to)
return; return;
auto ptr = actor_cast<actor>(to); to->enqueue(nullptr, message_id{}.with_high_priority(),
ptr->enqueue(invalid_actor_addr, message_id{}.with_high_priority(), make_message(exit_msg{invalid_actor_addr, reason}), nullptr);
make_message(exit_msg{invalid_actor_addr, reason}), nullptr);
} }
/// Anonymously sends `to` an exit message. /// Anonymously sends `to` an exit message.
template <class ActorHandle> inline void anon_send_exit(const actor_addr& to, exit_reason reason) {
void anon_send_exit(const ActorHandle& to, exit_reason reason) { anon_send_exit(actor_cast<actor>(to), reason);
anon_send_exit(to.address(), reason);
} }
} // namespace caf } // namespace caf
......
...@@ -23,8 +23,10 @@ ...@@ -23,8 +23,10 @@
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
#include "caf/actor.hpp" #include "caf/actor.hpp"
#include "caf/make_actor.hpp"
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/replies_to.hpp" #include "caf/replies_to.hpp"
#include "caf/actor_system.hpp"
#include "caf/abstract_actor.hpp" #include "caf/abstract_actor.hpp"
#include "caf/stateful_actor.hpp" #include "caf/stateful_actor.hpp"
#include "caf/typed_behavior.hpp" #include "caf/typed_behavior.hpp"
...@@ -56,6 +58,7 @@ class typed_broker; ...@@ -56,6 +58,7 @@ class typed_broker;
template <class... Sigs> template <class... Sigs>
class typed_actor : detail::comparable<typed_actor<Sigs...>>, class typed_actor : detail::comparable<typed_actor<Sigs...>>,
detail::comparable<typed_actor<Sigs...>, actor_addr>, detail::comparable<typed_actor<Sigs...>, actor_addr>,
detail::comparable<typed_actor<Sigs...>, strong_actor_ptr>,
detail::comparable<typed_actor<Sigs...>, invalid_actor_t>, detail::comparable<typed_actor<Sigs...>, invalid_actor_t>,
detail::comparable<typed_actor<Sigs...>, detail::comparable<typed_actor<Sigs...>,
invalid_actor_addr_t> { invalid_actor_addr_t> {
...@@ -70,8 +73,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>, ...@@ -70,8 +73,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
friend class typed_actor; friend class typed_actor;
// allow conversion via actor_cast // allow conversion via actor_cast
template <class> template <class, class, int>
friend struct actor_cast_access; friend class actor_cast_access;
// tell actor_cast which semantic this type uses
static constexpr bool has_weak_ptr_semantics = false;
/// Creates a new `typed_actor` type by extending this one with `Es...`. /// Creates a new `typed_actor` type by extending this one with `Es...`.
template <class... Es> template <class... Es>
...@@ -143,7 +149,7 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>, ...@@ -143,7 +149,7 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
detail::tlf_is_subset(signatures(), detail::tlf_is_subset(signatures(),
typename TypedActor::signatures()) typename TypedActor::signatures())
>::type> >::type>
typed_actor(TypedActor* ptr) : ptr_(ptr) { typed_actor(TypedActor* ptr) : ptr_(ptr->ctrl()) {
// nop // nop
} }
...@@ -176,10 +182,9 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>, ...@@ -176,10 +182,9 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
ptr_.reset(); ptr_.reset();
} }
/// Queries the address of the stored actor. /// Queries the address of the stored actor.
actor_addr address() const noexcept { actor_addr address() const noexcept {
return ptr_ ? ptr_->address() : actor_addr(); return {ptr_.get(), true};
} }
/// Returns `*this != invalid_actor`. /// Returns `*this != invalid_actor`.
...@@ -216,19 +221,20 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>, ...@@ -216,19 +221,20 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
bind(Ts&&... xs) const { bind(Ts&&... xs) const {
if (! ptr_) if (! ptr_)
return invalid_actor; return invalid_actor;
auto ptr = make_counted<decorator::adapter>(ptr_->address(), auto& sys = *(ptr_->home_system);
make_message(xs...)); auto ptr = make_actor<decorator::adapter, strong_actor_ptr>(
sys.next_actor_id(), sys.node(), &sys, ptr_, make_message(xs...));
return {ptr.release(), false}; return {ptr.release(), false};
} }
/// @cond PRIVATE /// @cond PRIVATE
abstract_actor* operator->() const noexcept { abstract_actor* operator->() const noexcept {
return ptr_.get(); return ptr_->get();
} }
abstract_actor& operator*() const noexcept { abstract_actor& operator*() const noexcept {
return *ptr_.get(); return *ptr_->get();
} }
intptr_t compare(const typed_actor& x) const noexcept { intptr_t compare(const typed_actor& x) const noexcept {
...@@ -236,7 +242,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>, ...@@ -236,7 +242,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
} }
intptr_t compare(const actor_addr& x) const noexcept { intptr_t compare(const actor_addr& x) const noexcept {
return actor_addr::compare(get(), actor_cast<abstract_actor*>(x)); return actor_addr::compare(get(), actor_cast<actor_control_block*>(x));
}
intptr_t compare(const strong_actor_ptr& x) const noexcept {
return actor_addr::compare(get(), actor_cast<actor_control_block*>(x));
} }
intptr_t compare(const invalid_actor_t&) const noexcept { intptr_t compare(const invalid_actor_t&) const noexcept {
...@@ -247,34 +257,43 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>, ...@@ -247,34 +257,43 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
return ptr_ ? 1 : 0; return ptr_ ? 1 : 0;
} }
typed_actor(actor_control_block* ptr, bool add_ref) : ptr_(ptr, add_ref) {
// nop
}
template <class Processor>
friend void serialize(Processor& proc, typed_actor& x, const unsigned int v) {
serialize(proc, x.ptr_, v);
}
friend inline std::string to_string(const typed_actor& x) {
return to_string(x.ptr_);
}
/// @endcond /// @endcond
private: private:
abstract_actor* get() const noexcept { actor_control_block* get() const noexcept {
return ptr_.get(); return ptr_.get();
} }
abstract_actor* release() noexcept { actor_control_block* release() noexcept {
return ptr_.release(); return ptr_.release();
} }
typed_actor(abstract_actor* ptr) : ptr_(ptr) { typed_actor(actor_control_block* ptr) : ptr_(ptr) {
// nop // nop
} }
typed_actor(abstract_actor* ptr, bool add_ref) : ptr_(ptr, add_ref) { strong_actor_ptr ptr_;
// nop
}
abstract_actor_ptr ptr_;
}; };
/// @relates typed_actor /// @relates typed_actor
template <class... Xs, class... Ys> template <class... Xs, class... Ys>
bool operator==(const typed_actor<Xs...>& x, bool operator==(const typed_actor<Xs...>& x,
const typed_actor<Ys...>& y) noexcept { const typed_actor<Ys...>& y) noexcept {
return actor_addr::compare(actor_cast<abstract_actor*>(x), return actor_addr::compare(actor_cast<actor_control_block*>(x),
actor_cast<abstract_actor*>(y)) == 0; actor_cast<actor_control_block*>(y)) == 0;
} }
/// @relates typed_actor /// @relates typed_actor
...@@ -301,10 +320,12 @@ operator*(typed_actor<Xs...> f, typed_actor<Ys...> g) { ...@@ -301,10 +320,12 @@ operator*(typed_actor<Xs...> f, typed_actor<Ys...> g) {
>::type; >::type;
if (! f || ! g) if (! f || ! g)
return invalid_actor; return invalid_actor;
auto mts = g->home_system().message_types(result{}); auto& sys = g->home_system();
auto ptr = make_counted<decorator::sequencer>(f.address(), g.address(), auto mts = sys.message_types(result{});
std::move(mts)); return make_actor<decorator::sequencer, result>(
return actor_cast<result>(std::move(ptr)); sys.next_actor_id(), sys.node(), &sys,
actor_cast<strong_actor_ptr>(std::move(f)),
actor_cast<strong_actor_ptr>(std::move(g)), std::move(mts));
} }
template <class... Xs, class... Ts> template <class... Xs, class... Ts>
...@@ -320,30 +341,17 @@ splice(const typed_actor<Xs...>& x, const Ts&... xs) { ...@@ -320,30 +341,17 @@ splice(const typed_actor<Xs...>& x, const Ts&... xs) {
detail::type_list<Xs...>, detail::type_list<Xs...>,
typename Ts::signatures... typename Ts::signatures...
>::type; >::type;
std::vector<actor_addr> tmp{x.address(), xs.address()...}; std::vector<strong_actor_ptr> tmp{actor_cast<strong_actor_ptr>(x),
actor_cast<strong_actor_ptr>(xs)...};
for (auto& addr : tmp) for (auto& addr : tmp)
if (! addr) if (! addr)
return invalid_actor; return invalid_actor;
auto mts = x->home_system().message_types(result{}); auto& sys = x->home_system();
auto ptr = make_counted<decorator::splitter>(std::move(tmp), std::move(mts)); auto mts = sys.message_types(result{});
return actor_cast<result>(std::move(ptr)); return make_actor<decorator::splitter, result>(sys.next_actor_id(),
} sys.node(), &sys,
std::move(tmp),
/// @relates typed_actor std::move(mts));
template <class Processor, class... Ts>
typename std::enable_if<Processor::is_saving::value>::type
serialize(Processor& sink, typed_actor<Ts...>& hdl, const unsigned int) {
auto addr = hdl.address();
sink << addr;
}
/// @relates typed_actor
template <class Processor, class... Ts>
typename std::enable_if<Processor::is_loading::value>::type
serialize(Processor& sink, typed_actor<Ts...>& hdl, const unsigned int) {
actor_addr addr;
sink >> addr;
hdl = actor_cast<typed_actor<Ts...>>(addr);
} }
} // namespace caf } // namespace caf
......
...@@ -51,7 +51,7 @@ public: ...@@ -51,7 +51,7 @@ public:
using value_factory = std::function<type_erased_value_ptr ()>; using value_factory = std::function<type_erased_value_ptr ()>;
using actor_factory_result = std::pair<actor_addr, std::set<std::string>>; using actor_factory_result = std::pair<strong_actor_ptr, std::set<std::string>>;
using actor_factory = std::function<actor_factory_result (actor_config&, message&)>; using actor_factory = std::function<actor_factory_result (actor_config&, message&)>;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_WEAK_INTRUSIVE_PTR_HPP
#define CAF_WEAK_INTRUSIVE_PTR_HPP
#include <cstddef>
#include <algorithm>
#include <stdexcept>
#include <type_traits>
#include "caf/intrusive_ptr.hpp"
#include "caf/detail/comparable.hpp"
namespace caf {
/// An intrusive, reference counting smart pointer implementation.
/// @relates ref_counted
template <class T>
class weak_intrusive_ptr : detail::comparable<weak_intrusive_ptr<T>>,
detail::comparable<weak_intrusive_ptr<T>, const T*>,
detail::comparable<weak_intrusive_ptr<T>, std::nullptr_t> {
public:
using pointer = T*;
using const_pointer = const T*;
using element_type = T;
using reference = T&;
using const_reference = const T&;
// tell actor_cast which semantic this type uses
static constexpr bool has_weak_ptr_semantics = true;
constexpr weak_intrusive_ptr() : ptr_(nullptr) {
// nop
}
weak_intrusive_ptr(pointer raw_ptr, bool add_ref = true) {
set_ptr(raw_ptr, add_ref);
}
weak_intrusive_ptr(weak_intrusive_ptr&& other) : ptr_(other.detach()) {
// nop
}
weak_intrusive_ptr(const weak_intrusive_ptr& other) {
set_ptr(other.get(), true);
}
template <class Y>
weak_intrusive_ptr(weak_intrusive_ptr<Y> other) : ptr_(other.detach()) {
static_assert(std::is_convertible<Y*, T*>::value,
"Y* is not assignable to T*");
}
~weak_intrusive_ptr() {
if (ptr_)
intrusive_ptr_release_weak(ptr_);
}
void swap(weak_intrusive_ptr& other) noexcept {
std::swap(ptr_, other.ptr_);
}
/// Returns the raw pointer without modifying reference
/// count and sets this to `nullptr`.
pointer detach() noexcept {
auto result = ptr_;
if (result)
ptr_ = nullptr;
return result;
}
/// Returns the raw pointer without modifying reference
/// count and sets this to `nullptr`.
pointer release() noexcept {
return detach();
}
void reset(pointer new_value = nullptr, bool add_ref = true) {
auto old = ptr_;
set_ptr(new_value, add_ref);
if (old)
intrusive_ptr_release_weak(old);
}
weak_intrusive_ptr& operator=(pointer ptr) {
reset(ptr);
return *this;
}
weak_intrusive_ptr& operator=(weak_intrusive_ptr other) {
swap(other);
return *this;
}
pointer get() const {
return ptr_;
}
pointer operator->() const {
return ptr_;
}
reference operator*() const {
return *ptr_;
}
bool operator!() const {
return ptr_ == nullptr;
}
explicit operator bool() const {
return ptr_ != nullptr;
}
ptrdiff_t compare(const_pointer ptr) const {
return static_cast<ptrdiff_t>(get() - ptr);
}
ptrdiff_t compare(const weak_intrusive_ptr& other) const {
return compare(other.get());
}
ptrdiff_t compare(std::nullptr_t) const {
return reinterpret_cast<ptrdiff_t>(get());
}
/// Tries to upgrade this weak reference to a strong reference.
intrusive_ptr<T> lock() const {
if (! ptr_ || ! intrusive_ptr_upgrade_weak(ptr_))
return nullptr;
// reference count already increased by intrusive_ptr_upgrade_weak
return {ptr_, false};
}
/// Tries to upgrade this weak reference to a strong reference.
/// Returns a pointer with increased strong reference count
/// on success, `nullptr` otherwise.
pointer get_locked() const {
if (! ptr_ || ! intrusive_ptr_upgrade_weak(ptr_))
return nullptr;
return ptr_;
}
private:
void set_ptr(pointer raw_ptr, bool add_ref) {
ptr_ = raw_ptr;
if (raw_ptr && add_ref)
intrusive_ptr_add_weak_ref(raw_ptr);
}
pointer ptr_;
};
/// @relates weak_intrusive_ptr
template <class X, typename Y>
bool operator==(const weak_intrusive_ptr<X>& lhs, const weak_intrusive_ptr<Y>& rhs) {
return lhs.get() == rhs.get();
}
/// @relates weak_intrusive_ptr
template <class X, typename Y>
bool operator!=(const weak_intrusive_ptr<X>& lhs, const weak_intrusive_ptr<Y>& rhs) {
return !(lhs == rhs);
}
} // namespace caf
#endif // CAF_WEAK_INTRUSIVE_PTR_HPP
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "caf/mailbox_element.hpp" #include "caf/mailbox_element.hpp"
#include "caf/system_messages.hpp" #include "caf/system_messages.hpp"
#include "caf/default_attachable.hpp" #include "caf/default_attachable.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/shared_spinlock.hpp" #include "caf/detail/shared_spinlock.hpp"
...@@ -45,29 +46,30 @@ namespace caf { ...@@ -45,29 +46,30 @@ namespace caf {
// exit_reason_ is guaranteed to be set to 0, i.e., exit_reason::not_exited, // exit_reason_ is guaranteed to be set to 0, i.e., exit_reason::not_exited,
// by std::atomic<> constructor // by std::atomic<> constructor
void abstract_actor::enqueue(const actor_addr& sender, message_id mid, actor_control_block* abstract_actor::ctrl() const {
return actor_control_block::from(this);
}
abstract_actor::~abstract_actor() {
// nop
}
void abstract_actor::enqueue(strong_actor_ptr sender, message_id mid,
message msg, execution_unit* host) { message msg, execution_unit* host) {
enqueue(mailbox_element::make(sender, mid, {}, std::move(msg)), host); enqueue(mailbox_element::make(sender, mid, {}, std::move(msg)), host);
} }
abstract_actor::abstract_actor(actor_config& cfg) abstract_actor::abstract_actor(actor_config& cfg)
: abstract_channel(cfg.flags | abstract_channel::is_abstract_actor_flag, : abstract_channel(cfg.flags) {
cfg.host->system().node()),
id_(cfg.host->system().next_actor_id()),
home_system_(&cfg.host->system()) {
// nop // nop
} }
abstract_actor::abstract_actor(actor_system* sys, actor_id aid, abstract_actor::abstract_actor(int flags) : abstract_channel(flags) {
node_id nid, int flags)
: abstract_channel(flags, std::move(nid)),
id_(aid),
home_system_(sys) {
// nop // nop
} }
actor_addr abstract_actor::address() const { actor_addr abstract_actor::address() const {
return actor_addr{const_cast<abstract_actor*>(this)}; return actor_addr{actor_control_block::from(this)};
} }
std::set<std::string> abstract_actor::message_types() const { std::set<std::string> abstract_actor::message_types() const {
...@@ -75,13 +77,25 @@ std::set<std::string> abstract_actor::message_types() const { ...@@ -75,13 +77,25 @@ std::set<std::string> abstract_actor::message_types() const {
return std::set<std::string>{}; return std::set<std::string>{};
} }
actor_id abstract_actor::id() const noexcept {
return actor_control_block::from(this)->id();
}
node_id abstract_actor::node() const noexcept {
return actor_control_block::from(this)->node();
}
actor_system& abstract_actor::home_system() const noexcept {
return *(actor_control_block::from(this)->home_system);
}
void abstract_actor::is_registered(bool value) { void abstract_actor::is_registered(bool value) {
if (is_registered() == value) if (is_registered() == value)
return; return;
if (value) if (value)
home_system_->registry().inc_running(); home_system().registry().inc_running();
else else
home_system_->registry().dec_running(); home_system().registry().dec_running();
set_flag(value, is_registered_flag); set_flag(value, is_registered_flag);
} }
......
...@@ -24,9 +24,7 @@ ...@@ -24,9 +24,7 @@
namespace caf { namespace caf {
abstract_channel::abstract_channel(int fs, node_id nid) abstract_channel::abstract_channel(int fs) : flags_(fs) {
: flags_(fs),
node_(std::move(nid)) {
// nop // nop
} }
......
...@@ -55,8 +55,8 @@ namespace { ...@@ -55,8 +55,8 @@ namespace {
using hrc = std::chrono::high_resolution_clock; using hrc = std::chrono::high_resolution_clock;
struct delayed_msg { struct delayed_msg {
actor_addr from; strong_actor_ptr from;
channel to; strong_actor_ptr to;
message_id mid; message_id mid;
message msg; message msg;
}; };
...@@ -106,7 +106,7 @@ public: ...@@ -106,7 +106,7 @@ public:
std::multimap<hrc::time_point, delayed_msg> messages; std::multimap<hrc::time_point, delayed_msg> messages;
// message handling rules // message handling rules
message_handler mfun{ message_handler mfun{
[&](const duration& d, actor_addr& from, channel& to, [&](const duration& d, strong_actor_ptr& from, strong_actor_ptr& to,
message_id mid, message& msg) { message_id mid, message& msg) {
insert_dmsg(messages, d, std::move(from), insert_dmsg(messages, d, std::move(from),
std::move(to), mid, std::move(msg)); std::move(to), mid, std::move(msg));
......
...@@ -44,10 +44,11 @@ const std::string& abstract_group::module::name() const { ...@@ -44,10 +44,11 @@ const std::string& abstract_group::module::name() const {
abstract_group::abstract_group(actor_system& sys, abstract_group::abstract_group(actor_system& sys,
abstract_group::module_ptr mod, abstract_group::module_ptr mod,
std::string id, const node_id& nid) std::string id, const node_id& nid)
: abstract_channel(abstract_channel::is_abstract_group_flag, nid), : abstract_channel(abstract_channel::is_abstract_group_flag),
system_(sys), system_(sys),
module_(mod), module_(mod),
identifier_(std::move(id)) { identifier_(std::move(id)),
origin_(nid) {
// nop // nop
} }
......
...@@ -17,12 +17,12 @@ ...@@ -17,12 +17,12 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#include "caf/channel.hpp" #include "caf/actor.hpp"
#include <utility> #include <utility>
#include "caf/actor.hpp"
#include "caf/actor_addr.hpp" #include "caf/actor_addr.hpp"
#include "caf/make_actor.hpp"
#include "caf/serializer.hpp" #include "caf/serializer.hpp"
#include "caf/actor_proxy.hpp" #include "caf/actor_proxy.hpp"
#include "caf/local_actor.hpp" #include "caf/local_actor.hpp"
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
namespace caf { namespace caf {
actor::actor(const scoped_actor& x) : ptr_(x.get()) { actor::actor(const scoped_actor& x) : ptr_(actor_cast<strong_actor_ptr>(x)) {
// nop // nop
} }
...@@ -45,16 +45,16 @@ actor::actor(const invalid_actor_t&) : ptr_(nullptr) { ...@@ -45,16 +45,16 @@ actor::actor(const invalid_actor_t&) : ptr_(nullptr) {
// nop // nop
} }
actor::actor(abstract_actor* ptr) : ptr_(ptr) { actor::actor(actor_control_block* ptr) : ptr_(ptr) {
// nop // nop
} }
actor::actor(abstract_actor* ptr, bool add_ref) : ptr_(ptr, add_ref) { actor::actor(actor_control_block* ptr, bool add_ref) : ptr_(ptr, add_ref) {
// nop // nop
} }
actor& actor::operator=(const scoped_actor& x) { actor& actor::operator=(const scoped_actor& x) {
ptr_.reset(x.get()); ptr_ = actor_cast<strong_actor_ptr>(x);
return *this; return *this;
} }
...@@ -76,7 +76,7 @@ void actor::swap(actor& other) noexcept { ...@@ -76,7 +76,7 @@ void actor::swap(actor& other) noexcept {
} }
actor_addr actor::address() const noexcept { actor_addr actor::address() const noexcept {
return ptr_ ? ptr_->address() : actor_addr{}; return actor_cast<actor_addr>(ptr_);
} }
node_id actor::node() const noexcept { node_id actor::node() const noexcept {
...@@ -90,45 +90,54 @@ actor_id actor::id() const noexcept { ...@@ -90,45 +90,54 @@ actor_id actor::id() const noexcept {
actor actor::bind_impl(message msg) const { actor actor::bind_impl(message msg) const {
if (! ptr_) if (! ptr_)
return invalid_actor; return invalid_actor;
return actor_cast<actor>(make_counted<decorator::adapter>(address(), auto& sys = *(ptr_->home_system);
std::move(msg))); return make_actor<decorator::adapter, actor>(sys.next_actor_id(), sys.node(),
&sys, ptr_, std::move(msg));
} }
actor operator*(actor f, actor g) { actor operator*(actor f, actor g) {
if (! f || ! g) if (! f || ! g)
return invalid_actor; return invalid_actor;
auto ptr = make_counted<decorator::sequencer>(f.address(), auto& sys = f->home_system();
g.address(), return make_actor<decorator::sequencer, actor>(
sys.next_actor_id(), sys.node(), &sys,
actor_cast<strong_actor_ptr>(std::move(f)),
actor_cast<strong_actor_ptr>(std::move(g)), std::set<std::string>{});
}
actor actor::splice_impl(std::initializer_list<actor> xs) {
if (xs.size() < 2)
return invalid_actor;
actor_system* sys = nullptr;
std::vector<strong_actor_ptr> tmp;
for (auto& x : xs)
if (x) {
if (! sys)
sys = &(x->home_system());
tmp.push_back(actor_cast<strong_actor_ptr>(x));
} else {
return invalid_actor;
}
return make_actor<decorator::splitter, actor>(sys->next_actor_id(),
sys->node(), sys,
std::move(tmp),
std::set<std::string>{}); std::set<std::string>{});
return actor_cast<actor>(std::move(ptr));
} }
void serialize(serializer& sink, actor& x, const unsigned int) { bool operator==(const actor& lhs, abstract_actor* rhs) {
sink << x.address(); return actor_cast<abstract_actor*>(lhs) == rhs;
} }
void serialize(deserializer& source, actor& x, const unsigned int) { bool operator==(abstract_actor* lhs, const actor& rhs) {
actor_addr addr; return rhs == lhs;
source >> addr;
x = actor_cast<actor>(addr);
} }
std::string to_string(const actor& x) { bool operator!=(const actor& lhs, abstract_actor* rhs) {
return to_string(x.address()); return !(lhs == rhs);
} }
actor actor::splice_impl(std::initializer_list<actor> xs) { bool operator!=(abstract_actor* lhs, const actor& rhs) {
if (xs.size() < 2) return !(lhs == rhs);
return invalid_actor;
std::vector<actor_addr> tmp;
for (auto& x : xs)
if (x)
tmp.push_back(x.address());
else
return invalid_actor;
auto ptr = make_counted<decorator::splitter>(std::move(tmp),
std::set<std::string>{});
return actor_cast<actor>(std::move(ptr));
} }
} // namespace caf } // namespace caf
...@@ -32,11 +32,12 @@ actor_addr::actor_addr(const invalid_actor_addr_t&) : ptr_(nullptr) { ...@@ -32,11 +32,12 @@ actor_addr::actor_addr(const invalid_actor_addr_t&) : ptr_(nullptr) {
// nop // nop
} }
actor_addr::actor_addr(abstract_actor* ptr) : ptr_(ptr) { actor_addr::actor_addr(actor_control_block* ptr) : ptr_(ptr) {
// nop // nop
} }
actor_addr::actor_addr(abstract_actor* ptr, bool add_ref) : ptr_(ptr, add_ref) { actor_addr::actor_addr(actor_control_block* ptr, bool add_ref)
: ptr_(ptr, add_ref) {
// nop // nop
} }
...@@ -45,8 +46,8 @@ actor_addr actor_addr::operator=(const invalid_actor_addr_t&) { ...@@ -45,8 +46,8 @@ actor_addr actor_addr::operator=(const invalid_actor_addr_t&) {
return *this; return *this;
} }
intptr_t actor_addr::compare(const abstract_actor* lhs, intptr_t actor_addr::compare(const actor_control_block* lhs,
const abstract_actor* rhs) { const actor_control_block* rhs) {
// invalid actors are always "less" than valid actors // invalid actors are always "less" than valid actors
if (! lhs) if (! lhs)
return rhs ? -1 : 0; return rhs ? -1 : 0;
...@@ -68,9 +69,12 @@ intptr_t actor_addr::compare(const actor_addr& other) const noexcept { ...@@ -68,9 +69,12 @@ intptr_t actor_addr::compare(const actor_addr& other) const noexcept {
} }
intptr_t actor_addr::compare(const abstract_actor* other) const noexcept { intptr_t actor_addr::compare(const abstract_actor* other) const noexcept {
return compare(ptr_.get(), other); return compare(ptr_.get(), actor_control_block::from(other));
} }
intptr_t actor_addr::compare(const actor_control_block* other) const noexcept {
return compare(ptr_.get(), other);
}
actor_id actor_addr::id() const noexcept { actor_id actor_addr::id() const noexcept {
return (ptr_) ? ptr_->id() : 0; return (ptr_) ? ptr_->id() : 0;
...@@ -80,33 +84,12 @@ node_id actor_addr::node() const noexcept { ...@@ -80,33 +84,12 @@ node_id actor_addr::node() const noexcept {
return ptr_ ? ptr_->node() : node_id{}; return ptr_ ? ptr_->node() : node_id{};
} }
void actor_addr::swap(actor_addr& other) noexcept { actor_system* actor_addr::home_system() const noexcept {
ptr_.swap(other.ptr_); return ptr_ ? ptr_->home_system : nullptr;
} }
void serialize(serializer& sink, actor_addr& x, const unsigned int) { void actor_addr::swap(actor_addr& other) noexcept {
sink << actor_cast<channel>(x); ptr_.swap(other.ptr_);
}
void serialize(deserializer& source, actor_addr& x, const unsigned int) {
channel y;
source >> y;
if (! y) {
x = invalid_actor_addr;
return;
}
if (! y->is_abstract_actor())
throw std::logic_error("Expected an actor address, found a group address.");
x.ptr_.reset(static_cast<abstract_actor*>(actor_cast<abstract_channel*>(y)));
}
std::string to_string(const actor_addr& x) {
if (! x)
return "<invalid-actor>";
std::string result = std::to_string(x->id());
result += "@";
result += to_string(x->node());
return result;
} }
} // namespace caf } // namespace caf
...@@ -43,8 +43,8 @@ void actor_companion::enqueue(mailbox_element_ptr ptr, execution_unit*) { ...@@ -43,8 +43,8 @@ void actor_companion::enqueue(mailbox_element_ptr ptr, execution_unit*) {
} }
} }
void actor_companion::enqueue(const actor_addr& sender, message_id mid, void actor_companion::enqueue(strong_actor_ptr sender, message_id mid, message content,
message content, execution_unit* eu) { execution_unit* eu) {
using detail::memory; using detail::memory;
auto ptr = mailbox_element::make(sender, mid, {}, std::move(content)); auto ptr = mailbox_element::make(sender, mid, {}, std::move(content));
enqueue(std::move(ptr), eu); enqueue(std::move(ptr), eu);
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/actor_control_block.hpp"
#include "caf/message.hpp"
#include "caf/actor_system.hpp"
#include "caf/proxy_registry.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/mailbox_element.hpp"
namespace caf {
void actor_control_block::enqueue(strong_actor_ptr sender, message_id mid,
message content, execution_unit* host) {
get()->enqueue(std::move(sender), mid, std::move(content), host);
}
void actor_control_block::enqueue(mailbox_element_ptr what,
execution_unit* host) {
get()->enqueue(std::move(what), host);
}
bool intrusive_ptr_upgrade_weak(actor_control_block* x) {
auto count = x->strong_refs.load();
while (count != 0)
if (x->strong_refs.compare_exchange_weak(count, count + 1,
std::memory_order_relaxed))
return true;
return false;
}
void intrusive_ptr_release_weak(actor_control_block* x) {
// destroy object if last weak pointer expires
if (x->weak_refs == 1
|| x->weak_refs.fetch_sub(1, std::memory_order_acq_rel) == 1)
x->block_dtor(x);
}
void intrusive_ptr_release(actor_control_block* x) {
// release implicit weak pointer if the last strong ref expires
// and destroy the data block
if (x->strong_refs.fetch_sub(1, std::memory_order_acq_rel) == 1) {
x->data_dtor(x->get());
intrusive_ptr_release_weak(x);
}
}
template <class T>
void safe_actor(serializer& sink, T& storage) {
CAF_LOG_TRACE(CAF_ARG(storage));
if (! sink.context()) {
CAF_LOG_ERROR("Cannot serialize actors without context.");
throw std::logic_error("Cannot serialize actors without context.");
}
auto& sys = sink.context()->system();
auto ptr = storage.get();
actor_id aid = invalid_actor_id;
node_id nid = invalid_node_id;
if (ptr) {
aid = ptr->aid;
nid = ptr->nid;
// register locally running actors to be able to deserialize them later
if (nid == sys.node())
sys.registry().put(aid, ptr);
}
sink << aid << nid;
}
template <class T>
void load_actor(deserializer& source, T& storage) {
CAF_LOG_TRACE("");
storage.reset();
if (! source.context())
throw std::logic_error("Cannot deserialize actor_addr without context.");
auto& sys = source.context()->system();
actor_id aid;
node_id nid;
source >> aid >> nid;
CAF_LOG_DEBUG(CAF_ARG(aid) << CAF_ARG(nid));
// deal with local actors
if (sys.node() == nid) {
storage = actor_cast<T>(sys.registry().get(aid).first);
CAF_LOG_DEBUG("fetch actor handle from local actor registry: "
<< (storage ? "found" : "not found"));
return;
}
auto prp = source.context()->proxy_registry_ptr();
if (! prp)
throw std::logic_error("Cannot deserialize remote actors "
"without proxy registry.");
// deal with (proxies for) remote actors
storage = actor_cast<T>(prp->get_or_put(nid, aid));
}
void serialize(serializer& sink, strong_actor_ptr& x, const unsigned int) {
CAF_LOG_TRACE("");
safe_actor(sink, x);
}
void serialize(deserializer& source, strong_actor_ptr& x, const unsigned int) {
CAF_LOG_TRACE("");
load_actor(source, x);
}
void serialize(serializer& sink, weak_actor_ptr& x, const unsigned int) {
CAF_LOG_TRACE("");
safe_actor(sink, x);
}
void serialize(deserializer& source, weak_actor_ptr& x, const unsigned int) {
CAF_LOG_TRACE("");
load_actor(source, x);
}
std::string to_string(const actor_control_block* x) {
if (! x)
return "<invalid-actor>";
std::string result = std::to_string(x->id());
result += "@";
result += to_string(x->node());
return result;
}
std::string to_string(const strong_actor_ptr& x) {
return to_string(x.get());
}
std::string to_string(const weak_actor_ptr& x) {
return to_string(x.get());
}
} // namespace caf
...@@ -27,27 +27,32 @@ ...@@ -27,27 +27,32 @@
namespace caf { namespace caf {
actor_ostream::actor_ostream(abstract_actor* self) actor_ostream::actor_ostream(local_actor* self)
: self_(self), : self_(actor_cast<actor>(self)),
printer_(self->home_system().scheduler().printer()) {
// nop
}
actor_ostream::actor_ostream(scoped_actor& self)
: self_(actor_cast<actor>(self)),
printer_(self->home_system().scheduler().printer()) { printer_(self->home_system().scheduler().printer()) {
// nop // nop
} }
actor_ostream& actor_ostream::write(std::string arg) { actor_ostream& actor_ostream::write(std::string arg) {
send_as(actor_cast<actor>(self_), printer_, add_atom::value, std::move(arg)); send_as(self_, printer_, add_atom::value, std::move(arg));
return *this; return *this;
} }
actor_ostream& actor_ostream::flush() { actor_ostream& actor_ostream::flush() {
send_as(actor_cast<actor>(self_), printer_, flush_atom::value); send_as(self_, printer_, flush_atom::value);
return *this; return *this;
} }
void actor_ostream::redirect(abstract_actor* self, std::string fn, int flags) { void actor_ostream::redirect(abstract_actor* self, std::string fn, int flags) {
if (! self) if (! self)
return; return;
intrusive_ptr<abstract_actor> ptr{self}; send_as(actor_cast<actor>(self), self->home_system().scheduler().printer(),
send_as(actor_cast<actor>(ptr), self->home_system().scheduler().printer(),
redirect_atom::value, self->address(), std::move(fn), flags); redirect_atom::value, self->address(), std::move(fn), flags);
} }
...@@ -56,12 +61,12 @@ void actor_ostream::redirect_all(actor_system& sys, std::string fn, int flags) { ...@@ -56,12 +61,12 @@ void actor_ostream::redirect_all(actor_system& sys, std::string fn, int flags) {
redirect_atom::value, std::move(fn), flags); redirect_atom::value, std::move(fn), flags);
} }
actor_ostream aout(abstract_actor* self) { actor_ostream aout(local_actor* self) {
return actor_ostream{self}; return actor_ostream{self};
} }
actor_ostream aout(scoped_actor& self) { actor_ostream aout(scoped_actor& self) {
return actor_ostream{self.get()}; return actor_ostream{self};
} }
} // namespace caf } // namespace caf
......
...@@ -55,9 +55,8 @@ void broadcast_dispatch(actor_system&, actor_pool::uplock&, ...@@ -55,9 +55,8 @@ void broadcast_dispatch(actor_system&, actor_pool::uplock&,
const actor_pool::actor_vec& vec, const actor_pool::actor_vec& vec,
mailbox_element_ptr& ptr, execution_unit* host) { mailbox_element_ptr& ptr, execution_unit* host) {
CAF_ASSERT(!vec.empty()); CAF_ASSERT(!vec.empty());
for (size_t i = 1; i < vec.size(); ++i) { for (size_t i = 1; i < vec.size(); ++i)
vec[i]->enqueue(ptr->sender, ptr->mid, ptr->msg, host); vec[i]->enqueue(ptr->sender, ptr->mid, ptr->msg, host);
}
vec.front()->enqueue(std::move(ptr), host); vec.front()->enqueue(std::move(ptr), host);
} }
...@@ -96,11 +95,19 @@ actor_pool::~actor_pool() { ...@@ -96,11 +95,19 @@ actor_pool::~actor_pool() {
actor actor_pool::make(execution_unit* eu, policy pol) { actor actor_pool::make(execution_unit* eu, policy pol) {
CAF_ASSERT(eu); CAF_ASSERT(eu);
intrusive_ptr<actor_pool> ptr; auto& sys = eu->system();
actor_config cfg{eu}; actor_config cfg{eu};
auto res = make_actor<actor_pool, actor>(sys.next_actor_id(), sys.node(),
&sys, cfg);
auto ptr = static_cast<actor_pool*>(actor_cast<abstract_actor*>(res));
ptr->policy_ = std::move(pol);
return res;
/*
intrusive_ptr<actor_pool> ptr;
ptr = make_counted<actor_pool>(cfg); ptr = make_counted<actor_pool>(cfg);
ptr->policy_ = std::move(pol); ptr->policy_ = std::move(pol);
return actor_cast<actor>(ptr); return actor_cast<actor>(ptr);
*/
} }
actor actor_pool::make(execution_unit* eu, size_t num_workers, actor actor_pool::make(execution_unit* eu, size_t num_workers,
...@@ -116,7 +123,7 @@ actor actor_pool::make(execution_unit* eu, size_t num_workers, ...@@ -116,7 +123,7 @@ actor actor_pool::make(execution_unit* eu, size_t num_workers,
return res; return res;
} }
void actor_pool::enqueue(const actor_addr& sender, message_id mid, void actor_pool::enqueue(strong_actor_ptr sender, message_id mid,
message content, execution_unit* eu) { message content, execution_unit* eu) {
upgrade_lock<detail::shared_spinlock> guard{workers_mtx_}; upgrade_lock<detail::shared_spinlock> guard{workers_mtx_};
if (filter(guard, sender, mid, content, eu)) if (filter(guard, sender, mid, content, eu))
...@@ -139,7 +146,7 @@ actor_pool::actor_pool(actor_config& cfg) ...@@ -139,7 +146,7 @@ actor_pool::actor_pool(actor_config& cfg)
} }
bool actor_pool::filter(upgrade_lock<detail::shared_spinlock>& guard, bool actor_pool::filter(upgrade_lock<detail::shared_spinlock>& guard,
const actor_addr& sender, message_id mid, const strong_actor_ptr& sender, message_id mid,
const message& msg, execution_unit* eu) { const message& msg, execution_unit* eu) {
auto rsn = planned_reason_; auto rsn = planned_reason_;
if (rsn != caf::exit_reason::not_exited) { if (rsn != caf::exit_reason::not_exited) {
...@@ -203,19 +210,16 @@ bool actor_pool::filter(upgrade_lock<detail::shared_spinlock>& guard, ...@@ -203,19 +210,16 @@ bool actor_pool::filter(upgrade_lock<detail::shared_spinlock>& guard,
if (msg.match_elements<sys_atom, get_atom>()) { if (msg.match_elements<sys_atom, get_atom>()) {
auto cpy = workers_; auto cpy = workers_;
guard.unlock(); guard.unlock();
actor_cast<abstract_actor*>(sender)->enqueue(invalid_actor_addr, sender->enqueue(nullptr, mid.response_id(),
mid.response_id(), make_message(std::move(cpy)), eu);
make_message(std::move(cpy)),
eu);
return true; return true;
} }
if (workers_.empty()) { if (workers_.empty()) {
guard.unlock(); guard.unlock();
if (sender != invalid_actor_addr && mid.valid()) { if (sender && mid.valid()) {
// tell client we have ignored this sync message by sending // tell client we have ignored this sync message by sending
// and empty message back // and empty message back
auto ptr = actor_cast<abstract_actor_ptr>(sender); sender->enqueue(nullptr, mid.response_id(), message{}, eu);
ptr->enqueue(invalid_actor_addr, mid.response_id(), message{}, eu);
} }
return true; return true;
} }
......
...@@ -28,59 +28,13 @@ ...@@ -28,59 +28,13 @@
namespace caf { namespace caf {
actor_proxy::anchor::anchor(actor_proxy* instance) : ptr_(instance) { actor_proxy::actor_proxy()
: monitorable_actor(abstract_channel::is_abstract_actor()) {
// nop // nop
} }
actor_proxy::anchor::~anchor() {
// nop
}
bool actor_proxy::anchor::expired() const {
return ! ptr_.load();
}
actor_proxy_ptr actor_proxy::anchor::get() {
actor_proxy_ptr result;
{ // lifetime scope of guard
shared_lock<detail::shared_spinlock> guard{lock_};
auto ptr = ptr_.load();
if (ptr) {
result.reset(ptr);
}
}
return result;
}
bool actor_proxy::anchor::try_expire() noexcept {
std::lock_guard<detail::shared_spinlock> guard{lock_};
// double-check reference count
if (ptr_.load()->get_reference_count() == 0) {
ptr_ = nullptr;
return true;
}
return false;
}
actor_proxy::~actor_proxy() { actor_proxy::~actor_proxy() {
// nop // nop
} }
actor_proxy::actor_proxy(actor_system* sys, actor_id aid, node_id nid)
: monitorable_actor(sys, aid, nid),
anchor_(make_counted<anchor>(this)) {
// nop
}
void actor_proxy::request_deletion(bool decremented_rc) noexcept {
// make sure ref count is 0 because try_expire might leak otherwise
if (! decremented_rc && rc_.fetch_sub(1, std::memory_order_acq_rel) != 1) {
// deletion request canceled due to a weak ptr access
return;
}
if (anchor_->try_expire()) {
delete this;
}
}
} // namespace caf } // namespace caf
...@@ -65,16 +65,20 @@ actor_registry::id_entry actor_registry::get(actor_id key) const { ...@@ -65,16 +65,20 @@ actor_registry::id_entry actor_registry::get(actor_id key) const {
if (i != entries_.end()) if (i != entries_.end())
return i->second; return i->second;
CAF_LOG_DEBUG("key invalid, assume actor no longer exists:" << CAF_ARG(key)); CAF_LOG_DEBUG("key invalid, assume actor no longer exists:" << CAF_ARG(key));
return {invalid_actor_addr, exit_reason::unknown}; return {nullptr, exit_reason::unknown};
} }
void actor_registry::put(actor_id key, const actor_addr& val) { void actor_registry::put(actor_id key, actor_control_block* val) {
if (val == nullptr) if (! val)
return;
auto strong_val = actor_cast<actor>(val);
if (! strong_val)
return; return;
{ // lifetime scope of guard { // lifetime scope of guard
exclusive_guard guard(instances_mtx_); exclusive_guard guard(instances_mtx_);
if (! entries_.emplace(key, if (! entries_.emplace(key,
id_entry{val, exit_reason::not_exited}).second) { id_entry{actor_cast<strong_actor_ptr>(val),
exit_reason::not_exited}).second) {
// already defined // already defined
return; return;
} }
...@@ -82,18 +86,22 @@ void actor_registry::put(actor_id key, const actor_addr& val) { ...@@ -82,18 +86,22 @@ void actor_registry::put(actor_id key, const actor_addr& val) {
// attach functor without lock // attach functor without lock
CAF_LOG_INFO("added actor:" << CAF_ARG(key)); CAF_LOG_INFO("added actor:" << CAF_ARG(key));
actor_registry* reg = this; actor_registry* reg = this;
val->attach_functor([key, reg](exit_reason reason) { strong_val->attach_functor([key, reg](exit_reason reason) {
reg->erase(key, reason); reg->erase(key, reason);
}); });
} }
void actor_registry::put(actor_id key, const strong_actor_ptr& val) {
put(key, actor_cast<actor_control_block*>(val));
}
void actor_registry::erase(actor_id key, exit_reason reason) { void actor_registry::erase(actor_id key, exit_reason reason) {
exclusive_guard guard(instances_mtx_); exclusive_guard guard(instances_mtx_);
auto i = entries_.find(key); auto i = entries_.find(key);
if (i != entries_.end()) { if (i != entries_.end()) {
auto& entry = i->second; auto& entry = i->second;
CAF_LOG_INFO("erased actor:" << CAF_ARG(key) << CAF_ARG(reason)); CAF_LOG_INFO("erased actor:" << CAF_ARG(key) << CAF_ARG(reason));
entry.first = invalid_actor_addr; entry.first = nullptr;
entry.second = reason; entry.second = reason;
} }
} }
...@@ -130,18 +138,18 @@ void actor_registry::await_running_count_equal(size_t expected) const { ...@@ -130,18 +138,18 @@ void actor_registry::await_running_count_equal(size_t expected) const {
} }
} }
actor actor_registry::get(atom_value key) const { strong_actor_ptr actor_registry::get(atom_value key) const {
shared_guard guard{named_entries_mtx_}; shared_guard guard{named_entries_mtx_};
auto i = named_entries_.find(key); auto i = named_entries_.find(key);
if (i == named_entries_.end()) if (i == named_entries_.end())
return invalid_actor; return nullptr;
return i->second; return i->second;
} }
void actor_registry::put(atom_value key, actor value) { void actor_registry::put(atom_value key, strong_actor_ptr value) {
if (value) if (value)
value->attach_functor([=] { value->get()->attach_functor([=] {
system_.registry().put(key, invalid_actor); system_.registry().put(key, nullptr);
}); });
exclusive_guard guard{named_entries_mtx_}; exclusive_guard guard{named_entries_mtx_};
named_entries_.emplace(key, std::move(value)); named_entries_.emplace(key, std::move(value));
...@@ -257,11 +265,11 @@ void actor_registry::start() { ...@@ -257,11 +265,11 @@ void actor_registry::start() {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
return { return {
[=](get_atom, const std::string& name, message& args) [=](get_atom, const std::string& name, message& args)
-> result<ok_atom, actor_addr, std::set<std::string>> { -> result<ok_atom, strong_actor_ptr, std::set<std::string>> {
CAF_LOG_TRACE(CAF_ARG(name) << CAF_ARG(args)); CAF_LOG_TRACE(CAF_ARG(name) << CAF_ARG(args));
actor_config cfg{self->context()}; actor_config cfg{self->context()};
auto res = self->system().types().make_actor(name, cfg, args); auto res = self->system().types().make_actor(name, cfg, args);
if (res.first == invalid_actor_addr) if (! res.first)
return sec::cannot_spawn_actor_from_arguments; return sec::cannot_spawn_actor_from_arguments;
return {ok_atom::value, res.first, res.second}; return {ok_atom::value, res.first, res.second};
}, },
...@@ -277,11 +285,9 @@ void actor_registry::start() { ...@@ -277,11 +285,9 @@ void actor_registry::start() {
// use the lazy_init flag // use the lazy_init flag
//named_entries_.emplace(atom("SpawnServ"), system_.spawn_announce_actor_type_server()); //named_entries_.emplace(atom("SpawnServ"), system_.spawn_announce_actor_type_server());
auto cs = system_.spawn<hidden+lazy_init>(kvstore); auto cs = system_.spawn<hidden+lazy_init>(kvstore);
put(atom("ConfigServ"), cs); put(atom("ConfigServ"), actor_cast<strong_actor_ptr>(std::move(cs)));
named_entries_.emplace(atom("ConfigServ"), std::move(cs));
auto ss = system_.spawn<hidden+lazy_init>(spawn_serv); auto ss = system_.spawn<hidden+lazy_init>(spawn_serv);
put(atom("SpawnServ"), ss); put(atom("SpawnServ"), actor_cast<strong_actor_ptr>(std::move(ss)));
named_entries_.emplace(atom("SpawnServ"), std::move(ss));
} }
void actor_registry::stop() { void actor_registry::stop() {
...@@ -298,7 +304,7 @@ void actor_registry::stop() { ...@@ -298,7 +304,7 @@ void actor_registry::stop() {
// the scheduler is already stopped -> invoke exit messages manually // the scheduler is already stopped -> invoke exit messages manually
dropping_execution_unit dummy{&system_}; dropping_execution_unit dummy{&system_};
for (auto& kvp : named_entries_) { for (auto& kvp : named_entries_) {
auto mp = mailbox_element::make_joint(invalid_actor_addr, auto mp = mailbox_element::make_joint(nullptr,
invalid_message_id, invalid_message_id,
{}, {},
exit_msg{invalid_actor_addr, exit_msg{invalid_actor_addr,
......
...@@ -132,7 +132,7 @@ actor_system::actor_system(actor_system_config&& cfg) ...@@ -132,7 +132,7 @@ actor_system::actor_system(actor_system_config&& cfg)
if (mod) if (mod)
mod->start(); mod->start();
// store config parameters in ConfigServ // store config parameters in ConfigServ
auto cs = registry_.get(atom("ConfigServ")); auto cs = actor_cast<actor>(registry_.get(atom("ConfigServ")));
anon_send(cs, put_atom::value, "middleman.enable-automatic-connections", anon_send(cs, put_atom::value, "middleman.enable-automatic-connections",
make_message(cfg.middleman_enable_automatic_connections)); make_message(cfg.middleman_enable_automatic_connections));
} }
......
...@@ -33,18 +33,15 @@ ...@@ -33,18 +33,15 @@
namespace caf { namespace caf {
namespace decorator { namespace decorator {
adapter::adapter(actor_addr decorated, message msg) adapter::adapter(strong_actor_ptr decorated, message msg)
: monitorable_actor(&decorated->home_system(), : monitorable_actor(is_abstract_actor_flag | is_actor_bind_decorator_flag),
decorated->home_system().next_actor_id(),
decorated->node(),
is_abstract_actor_flag
| is_actor_bind_decorator_flag),
decorated_(std::move(decorated)), decorated_(std::move(decorated)),
merger_(std::move(msg)) { merger_(std::move(msg)) {
// bound actor has dependency on the decorated actor by default; // bound actor has dependency on the decorated actor by default;
// if the decorated actor is already dead upon establishing the // if the decorated actor is already dead upon establishing the
// dependency, the actor is spawned dead // dependency, the actor is spawned dead
decorated_->attach(default_attachable::make_monitor(decorated_, address())); decorated_->get()->attach(
default_attachable::make_monitor(decorated_->get()->address(), address()));
} }
void adapter::enqueue(mailbox_element_ptr what, execution_unit* host) { void adapter::enqueue(mailbox_element_ptr what, execution_unit* host) {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2015 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/channel.hpp"
#include "caf/actor.hpp"
#include "caf/group.hpp"
#include "caf/message.hpp"
#include "caf/actor_addr.hpp"
#include "caf/actor_cast.hpp"
#include "caf/local_actor.hpp"
#include "caf/actor_system.hpp"
#include "caf/scoped_actor.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/abstract_group.hpp"
#include "caf/proxy_registry.hpp"
namespace caf {
namespace {
using ch_pointer = abstract_channel*;
} // namespace <anonymous>
channel::channel(const actor& x) : ptr_(actor_cast<ch_pointer>(x)) {
// nop
}
channel::channel(const group& x) : ptr_(actor_cast<ch_pointer>(x)) {
// nop
}
channel::channel(const scoped_actor& x) : ptr_(actor_cast<ch_pointer>(x)) {
// nop
}
channel::channel(const invalid_channel_t&) {
// nop
}
channel::channel(abstract_channel* ptr) : ptr_(ptr) {
// nop
}
channel::channel(abstract_channel* ptr, bool add_ref) : ptr_(ptr, add_ref) {
// nop
}
channel::channel(local_actor* ptr) : ptr_(ptr) {
// nop
}
channel& channel::operator=(const actor& x) {
ptr_.reset(actor_cast<ch_pointer>(x));
return *this;
}
channel& channel::operator=(const group& x) {
ptr_.reset(actor_cast<ch_pointer>(x));
return *this;
}
channel& channel::operator=(const scoped_actor& x) {
ptr_.reset(actor_cast<ch_pointer>(x));
return *this;
}
channel& channel::operator=(const invalid_channel_t&) {
ptr_.reset();
return *this;
}
intptr_t channel::compare(const channel& other) const noexcept {
return compare(other.ptr_.get());
}
intptr_t channel::compare(const actor& other) const noexcept {
return compare(actor_cast<abstract_channel*>(other));
}
intptr_t channel::compare(const abstract_channel* rhs) const noexcept {
// invalid handles are always "less" than valid handles
if (! ptr_)
return rhs ? -1 : 0;
if (! rhs)
return 1;
// check for identity
if (ptr_ == rhs)
return 0;
// groups are sorted before actors
if (ptr_->is_abstract_group()) {
if (! rhs->is_abstract_group())
return -1;
using gptr = const abstract_group*;
return group::compare(static_cast<gptr>(get()), static_cast<gptr>(rhs));
}
CAF_ASSERT(ptr_->is_abstract_actor());
if (! rhs->is_abstract_actor())
return 1;
using aptr = const abstract_actor*;
return actor_addr::compare(static_cast<aptr>(get()), static_cast<aptr>(rhs));
}
void serialize(serializer& sink, channel& x, const unsigned int) {
if (sink.context() == nullptr)
throw std::logic_error("Cannot serialize channel without context.");
uint8_t flag = ! x ? 0 : (x->is_abstract_actor() ? 1 : 2);
sink << flag;
auto& sys = sink.context()->system();
switch (flag) {
case 1: {
auto ptr = static_cast<abstract_actor*>(x.get());
// register locally running actors to be able to deserialize them later
if (sys.node() == ptr->node())
sys.registry().put(ptr->id(), ptr->address());
// we need lvalue references
auto xid = ptr->id();
auto xn = ptr->node();
sink << xid << xn;
break;
}
case 2: {
auto ptr = static_cast<abstract_group*>(x.get());
sink << ptr->module_name();
ptr->save(sink);
break;
}
default:
; // nop
}
}
void serialize(deserializer& source, channel& x, const unsigned int) {
if (source.context() == nullptr)
throw std::logic_error("Cannot deserialize actor_addr without context.");
uint8_t flag;
source >> flag;
auto& sys = source.context()->system();
switch (flag) {
case 1: {
actor_id aid;
node_id nid;
source >> aid >> nid;
// deal with local actors
if (sys.node() == nid) {
x = actor_cast<channel>(sys.registry().get(aid).first);
return;
}
auto prp = source.context()->proxy_registry_ptr();
if (prp == nullptr)
throw std::logic_error("Cannot deserialize actor_addr of "
"remote node without proxy registry.");
// deal with (proxies for) remote actors
auto ptr = prp->get_or_put(nid, aid);
if (ptr)
x.ptr_ = std::move(ptr);
else
x = invalid_channel;
break;
}
case 2: {
std::string module_name;
source >> module_name;
auto mod = sys.groups().get_module(module_name);
if (! mod)
throw std::logic_error("Cannot deserialize a group for "
"unknown module: " + module_name);
x = mod->load(source);
break;
}
default:
x = invalid_channel;
}
}
std::string to_string(const channel& x) {
if (! x)
return "<invalid-channel>";
auto ptr = actor_cast<abstract_channel*>(x);
if (ptr->is_abstract_actor()) {
intrusive_ptr<abstract_actor> aptr{static_cast<abstract_actor*>(ptr)};
return to_string(actor_cast<actor>(aptr));
}
intrusive_ptr<abstract_group> gptr{static_cast<abstract_group*>(ptr)};
return to_string(actor_cast<group>(gptr));
}
} // namespace caf
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "caf/default_attachable.hpp" #include "caf/default_attachable.hpp"
#include "caf/actor.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/system_messages.hpp" #include "caf/system_messages.hpp"
...@@ -37,15 +38,17 @@ message make(abstract_actor* self, exit_reason reason) { ...@@ -37,15 +38,17 @@ message make(abstract_actor* self, exit_reason reason) {
void default_attachable::actor_exited(exit_reason rsn, execution_unit* host) { void default_attachable::actor_exited(exit_reason rsn, execution_unit* host) {
CAF_ASSERT(observed_ != observer_); CAF_ASSERT(observed_ != observer_);
auto factory = type_ == monitor ? &make<down_msg> : &make<exit_msg>; auto factory = type_ == monitor ? &make<down_msg> : &make<exit_msg>;
auto ptr = actor_cast<abstract_actor_ptr>(observer_); auto observer = actor_cast<strong_actor_ptr>(observer_);
ptr->enqueue(observed_, message_id{}.with_high_priority(), auto observed = actor_cast<strong_actor_ptr>(observed_);
factory(actor_cast<abstract_actor*>(observed_), rsn), host); if (observer)
observer->enqueue(std::move(observed), message_id{}.with_high_priority(),
factory(actor_cast<abstract_actor*>(observed_), rsn),
host);
} }
bool default_attachable::matches(const token& what) { bool default_attachable::matches(const token& what) {
if (what.subtype != attachable::token::observer) { if (what.subtype != attachable::token::observer)
return false; return false;
}
auto& ot = *reinterpret_cast<const observe_token*>(what.ptr); auto& ot = *reinterpret_cast<const observe_token*>(what.ptr);
return ot.observer == observer_ && ot.type == type_; return ot.observer == observer_ && ot.type == type_;
} }
......
...@@ -26,13 +26,8 @@ ...@@ -26,13 +26,8 @@
namespace caf { namespace caf {
forwarding_actor_proxy::forwarding_actor_proxy(actor_system* sys, actor_id aid, forwarding_actor_proxy::forwarding_actor_proxy(actor mgr) : manager_(mgr) {
node_id nid, actor mgr)
: actor_proxy(sys, aid, nid),
manager_(mgr) {
CAF_ASSERT(mgr != invalid_actor); CAF_ASSERT(mgr != invalid_actor);
CAF_PUSH_AID(0);
CAF_LOG_INFO(CAF_ARG(aid) << CAF_ARG(nid));
} }
forwarding_actor_proxy::~forwarding_actor_proxy() { forwarding_actor_proxy::~forwarding_actor_proxy() {
...@@ -53,17 +48,18 @@ void forwarding_actor_proxy::manager(actor new_manager) { ...@@ -53,17 +48,18 @@ void forwarding_actor_proxy::manager(actor new_manager) {
manager_.swap(new_manager); manager_.swap(new_manager);
} }
void forwarding_actor_proxy::forward_msg(const actor_addr& sender, void forwarding_actor_proxy::forward_msg(strong_actor_ptr sender,
message_id mid, message msg, message_id mid, message msg,
const std::vector<actor_addr>* fwd) { const forwarding_stack* fwd) {
CAF_LOG_TRACE(CAF_ARG(id()) << CAF_ARG(sender) CAF_LOG_TRACE(CAF_ARG(id()) << CAF_ARG(sender)
<< CAF_ARG(mid) << CAF_ARG(msg)); << CAF_ARG(mid) << CAF_ARG(msg));
std::vector<actor_addr> tmp; forwarding_stack tmp;
shared_lock<detail::shared_spinlock> guard_(manager_mtx_); shared_lock<detail::shared_spinlock> guard_(manager_mtx_);
if (manager_) if (manager_)
manager_->enqueue(invalid_actor_addr, invalid_message_id, manager_->enqueue(nullptr, invalid_message_id,
make_message(forward_atom::value, sender, make_message(forward_atom::value, std::move(sender),
fwd ? *fwd : tmp, address(), fwd ? *fwd : tmp,
actor_cast<strong_actor_ptr>(this),
mid, std::move(msg)), mid, std::move(msg)),
nullptr); nullptr);
} }
...@@ -73,7 +69,8 @@ void forwarding_actor_proxy::enqueue(mailbox_element_ptr what, ...@@ -73,7 +69,8 @@ void forwarding_actor_proxy::enqueue(mailbox_element_ptr what,
CAF_PUSH_AID(0); CAF_PUSH_AID(0);
if (! what) if (! what)
return; return;
forward_msg(what->sender, what->mid, std::move(what->msg), &what->stages); forward_msg(std::move(what->sender), what->mid,
std::move(what->msg), &what->stages);
} }
...@@ -84,7 +81,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op, ...@@ -84,7 +81,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op,
if (establish_link_impl(other)) { if (establish_link_impl(other)) {
// causes remote actor to link to (proxy of) other // causes remote actor to link to (proxy of) other
// receiving peer will call: this->local_link_to(other) // receiving peer will call: this->local_link_to(other)
forward_msg(address(), invalid_message_id, forward_msg(ctrl(), invalid_message_id,
make_message(link_atom::value, other)); make_message(link_atom::value, other));
return true; return true;
} }
...@@ -92,7 +89,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op, ...@@ -92,7 +89,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op,
case remove_link_op: case remove_link_op:
if (remove_link_impl(other)) { if (remove_link_impl(other)) {
// causes remote actor to unlink from (proxy of) other // causes remote actor to unlink from (proxy of) other
forward_msg(address(), invalid_message_id, forward_msg(ctrl(), invalid_message_id,
make_message(unlink_atom::value, other)); make_message(unlink_atom::value, other));
return true; return true;
} }
...@@ -100,7 +97,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op, ...@@ -100,7 +97,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op,
case establish_backlink_op: case establish_backlink_op:
if (establish_backlink_impl(other)) { if (establish_backlink_impl(other)) {
// causes remote actor to unlink from (proxy of) other // causes remote actor to unlink from (proxy of) other
forward_msg(address(), invalid_message_id, forward_msg(ctrl(), invalid_message_id,
make_message(link_atom::value, other)); make_message(link_atom::value, other));
return true; return true;
} }
...@@ -108,7 +105,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op, ...@@ -108,7 +105,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op,
case remove_backlink_op: case remove_backlink_op:
if (remove_backlink_impl(other)) { if (remove_backlink_impl(other)) {
// causes remote actor to unlink from (proxy of) other // causes remote actor to unlink from (proxy of) other
forward_msg(address(), invalid_message_id, forward_msg(ctrl(), invalid_message_id,
make_message(unlink_atom::value, other)); make_message(unlink_atom::value, other));
return true; return true;
} }
......
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
#include "caf/group.hpp" #include "caf/group.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/actor_system.hpp"
#include "caf/group_manager.hpp" #include "caf/group_manager.hpp"
namespace caf { namespace caf {
...@@ -56,19 +56,31 @@ intptr_t group::compare(const group& other) const noexcept { ...@@ -56,19 +56,31 @@ intptr_t group::compare(const group& other) const noexcept {
} }
void serialize(serializer& sink, const group& x, const unsigned int) { void serialize(serializer& sink, const group& x, const unsigned int) {
sink << actor_cast<channel>(x); auto ptr = x.get();
if (! ptr) {
std::string dummy;
sink << dummy;
} else {
sink << ptr->module_name();
ptr->save(sink);
}
} }
void serialize(deserializer& source, group& x, const unsigned int) { void serialize(deserializer& source, group& x, const unsigned int) {
channel y; std::string module_name;
source >> y; source >> module_name;
if (! y) { if (module_name.empty()) {
x = invalid_group; x = invalid_group;
return; return;
} }
if (! y->is_abstract_group()) if (source.context() == nullptr)
throw std::logic_error("Expected an actor address, found a group address."); throw std::logic_error("Cannot serialize group without context.");
x.ptr_.reset(static_cast<abstract_group*>(actor_cast<abstract_channel*>(y))); auto& sys = source.context()->system();
auto mod = sys.groups().get_module(module_name);
if (! mod)
throw std::logic_error("Cannot deserialize a group for "
"unknown module: " + module_name);
x = mod->load(source);
} }
std::string to_string(const group& x) { std::string to_string(const group& x) {
......
...@@ -69,47 +69,52 @@ void await_all_locals_down(actor_system& sys, std::initializer_list<actor> xs) { ...@@ -69,47 +69,52 @@ void await_all_locals_down(actor_system& sys, std::initializer_list<actor> xs) {
class local_group : public abstract_group { class local_group : public abstract_group {
public: public:
void send_all_subscribers(const actor_addr& sender, const message& msg, void send_all_subscribers(const strong_actor_ptr& sender, const message& msg,
execution_unit* host) { execution_unit* host) {
CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(msg)); CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(msg));
shared_guard guard(mtx_); shared_guard guard(mtx_);
for (auto& s : subscribers_) { for (auto& s : subscribers_)
actor_cast<abstract_actor_ptr>(s)->enqueue(sender, invalid_message_id, s->enqueue(sender, invalid_message_id, msg, host);
msg, host);
}
} }
void enqueue(const actor_addr& sender, message_id, message msg, void enqueue(strong_actor_ptr sender, message_id, message msg,
execution_unit* host) override { execution_unit* host) override {
CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(msg)); CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(msg));
send_all_subscribers(sender, msg, host); send_all_subscribers(sender, msg, host);
broker_->enqueue(sender, invalid_message_id, msg, host); broker_->enqueue(sender, invalid_message_id, msg, host);
} }
std::pair<bool, size_t> add_subscriber(const actor_addr& who) { std::pair<bool, size_t> add_subscriber(strong_actor_ptr who) {
CAF_LOG_TRACE(CAF_ARG(who)); CAF_LOG_TRACE(CAF_ARG(who));
if (! who)
return {false, subscribers_.size()};
exclusive_guard guard(mtx_); exclusive_guard guard(mtx_);
if (who && subscribers_.insert(who).second) { auto res = subscribers_.emplace(std::move(who)).second;
return {true, subscribers_.size()}; return {res, subscribers_.size()};
}
return {false, subscribers_.size()};
} }
std::pair<bool, size_t> erase_subscriber(const actor_addr& who) { std::pair<bool, size_t> erase_subscriber(const actor_control_block* who) {
CAF_LOG_TRACE(""); // serializing who would cause a deadlock CAF_LOG_TRACE(""); // serializing who would cause a deadlock
exclusive_guard guard(mtx_); exclusive_guard guard(mtx_);
auto success = subscribers_.erase(who) > 0; auto cmp = [](const strong_actor_ptr& lhs, const actor_control_block* rhs) {
return {success, subscribers_.size()}; return actor_addr::compare(lhs.get(), rhs) < 0;
};
auto e = subscribers_.end();
auto i = std::lower_bound(subscribers_.begin(), e, who, cmp);
if (i == e || actor_addr::compare(i->get(), who) != 0)
return {false, subscribers_.size()};
subscribers_.erase(i);
return {true, subscribers_.size()};
} }
bool subscribe(const actor_addr& who) override { bool subscribe(strong_actor_ptr who) override {
CAF_LOG_TRACE(""); // serializing who would cause a deadlock CAF_LOG_TRACE(CAF_ARG(who));
if (add_subscriber(who).first) if (add_subscriber(std::move(who)).first)
return true; return true;
return false; return false;
} }
void unsubscribe(const actor_addr& who) override { void unsubscribe(const actor_control_block* who) override {
CAF_LOG_TRACE(CAF_ARG(who)); CAF_LOG_TRACE(CAF_ARG(who));
erase_subscriber(who); erase_subscriber(who);
} }
...@@ -133,7 +138,7 @@ public: ...@@ -133,7 +138,7 @@ public:
protected: protected:
detail::shared_spinlock mtx_; detail::shared_spinlock mtx_;
std::set<actor_addr> subscribers_; std::set<strong_actor_ptr> subscribers_;
actor broker_; actor broker_;
}; };
...@@ -167,13 +172,17 @@ public: ...@@ -167,13 +172,17 @@ public:
}, },
[=](leave_atom, const actor& other) { [=](leave_atom, const actor& other) {
CAF_LOG_TRACE(CAF_ARG(other)); CAF_LOG_TRACE(CAF_ARG(other));
acquaintances_.erase(other);
// TODO
/*
if (other && acquaintances_.erase(other) > 0) if (other && acquaintances_.erase(other) > 0)
demonitor(other); demonitor(other);
*/
}, },
[=](forward_atom, const message& what) { [=](forward_atom, const message& what) {
CAF_LOG_TRACE(CAF_ARG(what)); CAF_LOG_TRACE(CAF_ARG(what));
// local forwarding // local forwarding
group_->send_all_subscribers(current_sender(), what, context()); group_->send_all_subscribers(current_element_->sender, what, context());
// forward to all acquaintances // forward to all acquaintances
send_to_acquaintances(what); send_to_acquaintances(what);
}, },
...@@ -199,7 +208,7 @@ public: ...@@ -199,7 +208,7 @@ public:
private: private:
void send_to_acquaintances(const message& what) { void send_to_acquaintances(const message& what) {
// send to all remote subscribers // send to all remote subscribers
auto sender = current_sender(); auto sender = current_element_->sender;
CAF_LOG_DEBUG(CAF_ARG(acquaintances_.size()) CAF_LOG_DEBUG(CAF_ARG(acquaintances_.size())
<< CAF_ARG(sender) << CAF_ARG(what)); << CAF_ARG(sender) << CAF_ARG(what));
for (auto& acquaintance : acquaintances_) for (auto& acquaintance : acquaintances_)
...@@ -251,9 +260,9 @@ public: ...@@ -251,9 +260,9 @@ public:
monitor_ = system().spawn<hidden>(broker_monitor_actor, this); monitor_ = system().spawn<hidden>(broker_monitor_actor, this);
} }
bool subscribe(const actor_addr& who) override { bool subscribe(strong_actor_ptr who) override {
CAF_LOG_TRACE(CAF_ARG(who)); CAF_LOG_TRACE(CAF_ARG(who));
auto res = add_subscriber(who); auto res = add_subscriber(std::move(who));
if (res.first) { if (res.first) {
// join remote source // join remote source
if (res.second == 1) if (res.second == 1)
...@@ -264,7 +273,7 @@ public: ...@@ -264,7 +273,7 @@ public:
return false; return false;
} }
void unsubscribe(const actor_addr& who) override { void unsubscribe(const actor_control_block* who) override {
CAF_LOG_TRACE(CAF_ARG(who)); CAF_LOG_TRACE(CAF_ARG(who));
auto res = erase_subscriber(who); auto res = erase_subscriber(who);
if (res.first && res.second == 0) { if (res.first && res.second == 0) {
...@@ -274,11 +283,11 @@ public: ...@@ -274,11 +283,11 @@ public:
} }
} }
void enqueue(const actor_addr& sender, message_id mid, message msg, void enqueue(strong_actor_ptr sender, message_id mid,
execution_unit* eu) override { message msg, execution_unit* eu) override {
CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(mid) << CAF_ARG(msg)); CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(mid) << CAF_ARG(msg));
// forward message to the broker // forward message to the broker
broker_->enqueue(sender, mid, broker_->enqueue(std::move(sender), mid,
make_message(forward_atom::value, std::move(msg)), eu); make_message(forward_atom::value, std::move(msg)), eu);
} }
...@@ -299,7 +308,7 @@ private: ...@@ -299,7 +308,7 @@ private:
[=](const down_msg& down) { [=](const down_msg& down) {
CAF_LOG_TRACE(CAF_ARG(down)); CAF_LOG_TRACE(CAF_ARG(down));
auto msg = make_message(group_down_msg{group(grp)}); auto msg = make_message(group_down_msg{group(grp)});
grp->send_all_subscribers(self->address(), std::move(msg), grp->send_all_subscribers(self->ctrl(), std::move(msg),
self->context()); self->context());
self->quit(down.reason); self->quit(down.reason);
} }
...@@ -315,7 +324,7 @@ behavior proxy_broker::make_behavior() { ...@@ -315,7 +324,7 @@ behavior proxy_broker::make_behavior() {
return { return {
others >> [=](const message& msg) { others >> [=](const message& msg) {
CAF_LOG_TRACE(CAF_ARG(msg)); CAF_LOG_TRACE(CAF_ARG(msg));
group_->send_all_subscribers(current_sender(), msg, context()); group_->send_all_subscribers(current_element_->sender, msg, context());
} }
}; };
} }
......
...@@ -52,16 +52,15 @@ local_actor::local_actor(actor_config& cfg) ...@@ -52,16 +52,15 @@ local_actor::local_actor(actor_config& cfg)
join(grp); join(grp);
} }
local_actor::local_actor(actor_system* sys, actor_id aid, node_id nid) local_actor::local_actor()
: monitorable_actor(sys, aid, std::move(nid)), : monitorable_actor(abstract_channel::is_abstract_actor_flag),
planned_exit_reason_(exit_reason::not_exited), planned_exit_reason_(exit_reason::not_exited),
timeout_id_(0) { timeout_id_(0) {
// nop // nop
} }
local_actor::local_actor(actor_system* sys, actor_id aid, local_actor::local_actor(int init_flags)
node_id nid, int init_flags) : monitorable_actor(init_flags),
: monitorable_actor(sys, aid, std::move(nid), init_flags),
planned_exit_reason_(exit_reason::not_exited), planned_exit_reason_(exit_reason::not_exited),
timeout_id_(0) { timeout_id_(0) {
// nop // nop
...@@ -72,33 +71,42 @@ local_actor::~local_actor() { ...@@ -72,33 +71,42 @@ local_actor::~local_actor() {
cleanup(exit_reason::unreachable, nullptr); cleanup(exit_reason::unreachable, nullptr);
} }
void local_actor::monitor(const actor_addr& whom) { void local_actor::intrusive_ptr_add_ref_impl() {
if (whom == invalid_actor_addr) intrusive_ptr_add_ref(ctrl());
}
void local_actor::intrusive_ptr_release_impl() {
intrusive_ptr_release(ctrl());
}
void local_actor::monitor(abstract_actor* ptr) {
if (! ptr)
return; return;
auto ptr = actor_cast<abstract_actor_ptr>(whom); ptr->attach(default_attachable::make_monitor(ptr->address(), address()));
ptr->attach(default_attachable::make_monitor(whom, address()));
} }
void local_actor::demonitor(const actor_addr& whom) { void local_actor::demonitor(const actor_addr& whom) {
/*
if (whom == invalid_actor_addr) if (whom == invalid_actor_addr)
return; return;
auto ptr = actor_cast<abstract_actor_ptr>(whom); auto ptr = actor_cast<abstract_actor_ptr>(whom);
default_attachable::observe_token tk{address(), default_attachable::monitor}; default_attachable::observe_token tk{address(), default_attachable::monitor};
ptr->detach(tk); ptr->detach(tk);
*/
} }
void local_actor::join(const group& what) { void local_actor::join(const group& what) {
CAF_LOG_TRACE(CAF_ARG(what)); CAF_LOG_TRACE(CAF_ARG(what));
if (what == invalid_group) if (what == invalid_group)
return; return;
if (what->subscribe(address())) if (what->subscribe(ctrl()))
subscriptions_.emplace(what); subscriptions_.emplace(what);
} }
void local_actor::leave(const group& what) { void local_actor::leave(const group& what) {
CAF_LOG_TRACE(CAF_ARG(what)); CAF_LOG_TRACE(CAF_ARG(what));
if (subscriptions_.erase(what) > 0) if (subscriptions_.erase(what) > 0)
what->unsubscribe(address()); what->unsubscribe(ctrl());
} }
void local_actor::on_exit() { void local_actor::on_exit() {
...@@ -140,9 +148,10 @@ uint32_t local_actor::request_timeout(const duration& d) { ...@@ -140,9 +148,10 @@ uint32_t local_actor::request_timeout(const duration& d) {
CAF_LOG_TRACE("send new timeout_msg, " << CAF_ARG(timeout_id_)); CAF_LOG_TRACE("send new timeout_msg, " << CAF_ARG(timeout_id_));
if (d.is_zero()) { if (d.is_zero()) {
// immediately enqueue timeout message if duration == 0s // immediately enqueue timeout message if duration == 0s
enqueue(address(), invalid_message_id, std::move(msg), context()); enqueue(ctrl(), invalid_message_id,
std::move(msg), context());
} else { } else {
delayed_send(this, d, std::move(msg)); delayed_send(actor_cast<actor>(this), d, std::move(msg));
} }
return result; return result;
} }
...@@ -151,7 +160,7 @@ void local_actor::request_sync_timeout_msg(const duration& d, message_id mid) { ...@@ -151,7 +160,7 @@ void local_actor::request_sync_timeout_msg(const duration& d, message_id mid) {
CAF_LOG_TRACE(CAF_ARG(d) << CAF_ARG(mid)); CAF_LOG_TRACE(CAF_ARG(d) << CAF_ARG(mid));
if (! d.valid()) if (! d.valid())
return; return;
delayed_send_impl(mid.response_id(), this, d, delayed_send_impl(mid.response_id(), ctrl(), d,
make_message(sec::request_timeout)); make_message(sec::request_timeout));
} }
...@@ -245,7 +254,6 @@ msg_type filter_msg(local_actor* self, mailbox_element& node) { ...@@ -245,7 +254,6 @@ msg_type filter_msg(local_actor* self, mailbox_element& node) {
} }
}); });
}, },
*/
[&](sys_atom, migrate_atom, std::vector<char>& buf) { [&](sys_atom, migrate_atom, std::vector<char>& buf) {
// "replace" this actor with the content of `buf` // "replace" this actor with the content of `buf`
if (! self->is_serializable()) { if (! self->is_serializable()) {
...@@ -267,19 +275,22 @@ msg_type filter_msg(local_actor* self, mailbox_element& node) { ...@@ -267,19 +275,22 @@ msg_type filter_msg(local_actor* self, mailbox_element& node) {
{}, ok_atom::value, self->address()), {}, ok_atom::value, self->address()),
self->context()); self->context());
}, },
*/
[&](sys_atom, get_atom, std::string& what) { [&](sys_atom, get_atom, std::string& what) {
CAF_LOG_TRACE(CAF_ARG(what)); CAF_LOG_TRACE(CAF_ARG(what));
if (what == "info") { if (what == "info") {
CAF_LOG_DEBUG("reply to 'info' message"); CAF_LOG_DEBUG("reply to 'info' message");
node.sender->enqueue( node.sender->enqueue(
mailbox_element::make_joint(self->address(), node.mid.response_id(), mailbox_element::make_joint(self->ctrl(),
node.mid.response_id(),
{}, ok_atom::value, std::move(what), {}, ok_atom::value, std::move(what),
self->address(), self->name()), self->address(), self->name()),
self->context()); self->context());
return; return;
} }
node.sender->enqueue( node.sender->enqueue(
mailbox_element::make_joint(self->address(), node.mid.response_id(), mailbox_element::make_joint(self->ctrl(),
node.mid.response_id(),
{}, sec::invalid_sys_key), {}, sec::invalid_sys_key),
self->context()); self->context());
}, },
...@@ -603,7 +614,7 @@ void local_actor::launch(execution_unit* eu, bool lazy, bool hide) { ...@@ -603,7 +614,7 @@ void local_actor::launch(execution_unit* eu, bool lazy, bool hide) {
scheduler::inc_detached_threads(); scheduler::inc_detached_threads();
//intrusive_ptr<local_actor> mself{this}; //intrusive_ptr<local_actor> mself{this};
actor_system* sys = &eu->system(); actor_system* sys = &eu->system();
std::thread{[hide, sys](intrusive_ptr<local_actor> mself) { std::thread{[hide, sys](strong_actor_ptr mself) {
CAF_SET_LOGGER_SYS(sys); CAF_SET_LOGGER_SYS(sys);
// this extra scope makes sure that the trace logger is // this extra scope makes sure that the trace logger is
// destructed before dec_detached_threads() is called // destructed before dec_detached_threads() is called
...@@ -612,15 +623,16 @@ void local_actor::launch(execution_unit* eu, bool lazy, bool hide) { ...@@ -612,15 +623,16 @@ void local_actor::launch(execution_unit* eu, bool lazy, bool hide) {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
scoped_execution_unit ctx{sys}; scoped_execution_unit ctx{sys};
auto max_throughput = std::numeric_limits<size_t>::max(); auto max_throughput = std::numeric_limits<size_t>::max();
while (mself->resume(&ctx, max_throughput) != resumable::done) { auto ptr = static_cast<local_actor*>(actor_cast<abstract_actor*>(mself));
while (ptr->resume(&ctx, max_throughput) != resumable::done) {
// await new data before resuming actor // await new data before resuming actor
mself->await_data(); ptr->await_data();
CAF_ASSERT(mself->mailbox().blocked() == false); CAF_ASSERT(ptr->mailbox().blocked() == false);
} }
mself.reset(); mself.reset();
} }
scheduler::dec_detached_threads(); scheduler::dec_detached_threads();
}, intrusive_ptr<local_actor>{this}}.detach(); }, strong_actor_ptr{ctrl()}}.detach();
return; return;
} }
CAF_ASSERT(eu != nullptr); CAF_ASSERT(eu != nullptr);
...@@ -631,7 +643,7 @@ void local_actor::launch(execution_unit* eu, bool lazy, bool hide) { ...@@ -631,7 +643,7 @@ void local_actor::launch(execution_unit* eu, bool lazy, bool hide) {
} }
// scheduler has a reference count to the actor as long as // scheduler has a reference count to the actor as long as
// it is waiting to get scheduled // it is waiting to get scheduled
ref(); intrusive_ptr_add_ref(ctrl());
eu->exec_later(this); eu->exec_later(this);
} }
...@@ -658,11 +670,11 @@ void local_actor::enqueue(mailbox_element_ptr ptr, execution_unit* eu) { ...@@ -658,11 +670,11 @@ void local_actor::enqueue(mailbox_element_ptr ptr, execution_unit* eu) {
switch (mailbox().enqueue(ptr.release())) { switch (mailbox().enqueue(ptr.release())) {
case detail::enqueue_result::unblocked_reader: { case detail::enqueue_result::unblocked_reader: {
// add a reference count to this actor and re-schedule it // add a reference count to this actor and re-schedule it
ref(); intrusive_ptr_add_ref(ctrl());
if (eu) if (eu)
eu->exec_later(this); eu->exec_later(this);
else else
home_system_->scheduler().enqueue(this); home_system().scheduler().enqueue(this);
break; break;
} }
case detail::enqueue_result::queue_closed: { case detail::enqueue_result::queue_closed: {
...@@ -682,10 +694,6 @@ resumable::subtype_t local_actor::subtype() const { ...@@ -682,10 +694,6 @@ resumable::subtype_t local_actor::subtype() const {
return scheduled_actor; return scheduled_actor;
} }
ref_counted* local_actor::as_ref_counted_ptr() {
return this;
}
resumable::resume_result local_actor::resume(execution_unit* eu, resumable::resume_result local_actor::resume(execution_unit* eu,
size_t max_throughput) { size_t max_throughput) {
CAF_PUSH_AID(id()); CAF_PUSH_AID(id());
...@@ -972,18 +980,17 @@ void local_actor::send_impl(message_id mid, abstract_channel* dest, ...@@ -972,18 +980,17 @@ void local_actor::send_impl(message_id mid, abstract_channel* dest,
message what) const { message what) const {
if (! dest) if (! dest)
return; return;
dest->enqueue(address(), mid, std::move(what), context()); dest->enqueue(ctrl(), mid, std::move(what), context());
} }
void local_actor::send_exit(const actor_addr& whom, exit_reason reason) { void local_actor::send_exit(const actor_addr& whom, exit_reason reason) {
send(message_priority::high, actor_cast<actor>(whom), send(message_priority::high, actor_cast<actor>(whom),
exit_msg{address(), reason}); exit_msg{address(), reason});
} }
void local_actor::delayed_send_impl(message_id mid, const channel& dest, void local_actor::delayed_send_impl(message_id mid, strong_actor_ptr dest,
const duration& rel_time, message msg) { const duration& rel_time, message msg) {
system().scheduler().delayed_send(rel_time, address(), dest, system().scheduler().delayed_send(rel_time, ctrl(), std::move(dest),
mid, std::move(msg)); mid, std::move(msg));
} }
...@@ -1024,12 +1031,10 @@ void local_actor::cleanup(exit_reason reason, execution_unit* host) { ...@@ -1024,12 +1031,10 @@ void local_actor::cleanup(exit_reason reason, execution_unit* host) {
} }
awaited_responses_.clear(); awaited_responses_.clear();
multiplexed_responses_.clear(); multiplexed_responses_.clear();
{ // lifetime scope of temporary auto me = ctrl();
actor_addr me = address(); for (auto& subscription : subscriptions_)
for (auto& subscription : subscriptions_) subscription->unsubscribe(me);
subscription->unsubscribe(me); subscriptions_.clear();
subscriptions_.clear();
}
monitorable_actor::cleanup(reason, host); monitorable_actor::cleanup(reason, host);
// tell registry we're done // tell registry we're done
is_registered(false); is_registered(false);
......
...@@ -28,7 +28,8 @@ mailbox_element::mailbox_element() ...@@ -28,7 +28,8 @@ mailbox_element::mailbox_element()
// nop // nop
} }
mailbox_element::mailbox_element(actor_addr x, message_id y, forwarding_stack z) mailbox_element::mailbox_element(strong_actor_ptr x, message_id y,
forwarding_stack z)
: next(nullptr), : next(nullptr),
prev(nullptr), prev(nullptr),
marked(false), marked(false),
...@@ -38,7 +39,7 @@ mailbox_element::mailbox_element(actor_addr x, message_id y, forwarding_stack z) ...@@ -38,7 +39,7 @@ mailbox_element::mailbox_element(actor_addr x, message_id y, forwarding_stack z)
// nop // nop
} }
mailbox_element::mailbox_element(actor_addr x, message_id y, mailbox_element::mailbox_element(strong_actor_ptr x, message_id y,
forwarding_stack z, message m) forwarding_stack z, message m)
: next(nullptr), : next(nullptr),
prev(nullptr), prev(nullptr),
...@@ -54,7 +55,8 @@ mailbox_element::~mailbox_element() { ...@@ -54,7 +55,8 @@ mailbox_element::~mailbox_element() {
// nop // nop
} }
mailbox_element_ptr mailbox_element::make(actor_addr sender, message_id id, mailbox_element_ptr mailbox_element::make(strong_actor_ptr sender,
message_id id,
forwarding_stack stages, forwarding_stack stages,
message msg) { message msg) {
auto ptr = detail::memory::create<mailbox_element>(std::move(sender), id, auto ptr = detail::memory::create<mailbox_element>(std::move(sender), id,
......
...@@ -82,17 +82,8 @@ monitorable_actor::monitorable_actor(actor_config& cfg) ...@@ -82,17 +82,8 @@ monitorable_actor::monitorable_actor(actor_config& cfg)
// nop // nop
} }
monitorable_actor::monitorable_actor(actor_system* sys, monitorable_actor::monitorable_actor(int init_flags)
actor_id aid, : abstract_actor(init_flags),
node_id nid)
: abstract_actor(sys, aid, nid),
exit_reason_(exit_reason::not_exited) {
// nop
}
monitorable_actor::monitorable_actor(actor_system* sys, actor_id aid,
node_id nid, int init_flags)
: abstract_actor(sys, aid, nid, init_flags),
exit_reason_(exit_reason::not_exited) { exit_reason_(exit_reason::not_exited) {
// nop // nop
} }
...@@ -131,12 +122,14 @@ bool monitorable_actor::establish_link_impl(const actor_addr& other) { ...@@ -131,12 +122,14 @@ bool monitorable_actor::establish_link_impl(const actor_addr& other) {
CAF_LOG_TRACE(CAF_ARG(other)); CAF_LOG_TRACE(CAF_ARG(other));
if (other && other != this) { if (other && other != this) {
std::unique_lock<std::mutex> guard{mtx_}; std::unique_lock<std::mutex> guard{mtx_};
auto ptr = actor_cast<abstract_actor_ptr>(other); auto ptr = actor_cast<actor>(other);
if (! ptr)
return false;
auto reason = get_exit_reason(); auto reason = get_exit_reason();
// send exit message if already exited // send exit message if already exited
if (reason != exit_reason::not_exited) { if (reason != exit_reason::not_exited) {
guard.unlock(); guard.unlock();
ptr->enqueue(address(), invalid_message_id, ptr->enqueue(ctrl(), invalid_message_id,
make_message(exit_msg{address(), reason}), nullptr); make_message(exit_msg{address(), reason}), nullptr);
} else if (ptr->establish_backlink(address())) { } else if (ptr->establish_backlink(address())) {
// add link if not already linked to other // add link if not already linked to other
...@@ -166,9 +159,10 @@ bool monitorable_actor::establish_backlink_impl(const actor_addr& other) { ...@@ -166,9 +159,10 @@ bool monitorable_actor::establish_backlink_impl(const actor_addr& other) {
} }
// send exit message without lock // send exit message without lock
if (reason != exit_reason::not_exited) { if (reason != exit_reason::not_exited) {
auto ptr = actor_cast<abstract_actor_ptr>(other); auto hdl = actor_cast<actor>(other);
ptr->enqueue(address(), invalid_message_id, if (hdl)
make_message(exit_msg{address(), reason}), nullptr); hdl->enqueue(ctrl(), invalid_message_id,
make_message(exit_msg{address(), reason}), nullptr);
} }
return false; return false;
} }
...@@ -180,11 +174,13 @@ bool monitorable_actor::remove_link_impl(const actor_addr& other) { ...@@ -180,11 +174,13 @@ bool monitorable_actor::remove_link_impl(const actor_addr& other) {
default_attachable::observe_token tk{other, default_attachable::link}; default_attachable::observe_token tk{other, default_attachable::link};
std::unique_lock<std::mutex> guard{mtx_}; std::unique_lock<std::mutex> guard{mtx_};
// remove_backlink returns true if this actor is linked to other // remove_backlink returns true if this actor is linked to other
auto ptr = actor_cast<abstract_actor_ptr>(other); auto hdl = actor_cast<actor>(other);
if (! hdl)
return false;
if (detach_impl(tk, attachables_head_, true) > 0) { if (detach_impl(tk, attachables_head_, true) > 0) {
guard.unlock(); guard.unlock();
// tell remote side to remove link as well // tell remote side to remove link as well
ptr->remove_backlink(address()); hdl->remove_backlink(address());
return true; return true;
} }
return false; return false;
...@@ -243,7 +239,8 @@ bool monitorable_actor::handle_system_message(mailbox_element& node, ...@@ -243,7 +239,8 @@ bool monitorable_actor::handle_system_message(mailbox_element& node,
err = sec::invalid_sys_key; err = sec::invalid_sys_key;
return; return;
} }
res = mailbox_element::make_joint(address(), node.mid.response_id(), {}, res = mailbox_element::make_joint(ctrl(),
node.mid.response_id(), {},
ok_atom::value, std::move(what), ok_atom::value, std::move(what),
address(), name()); address(), name());
}, },
...@@ -252,10 +249,13 @@ bool monitorable_actor::handle_system_message(mailbox_element& node, ...@@ -252,10 +249,13 @@ bool monitorable_actor::handle_system_message(mailbox_element& node,
} }
}); });
if (err && node.mid.is_request()) if (err && node.mid.is_request())
res = mailbox_element::make_joint(address(), node.mid.response_id(), res = mailbox_element::make_joint(ctrl(), node.mid.response_id(),
{}, std::move(err)); {}, std::move(err));
if (res) if (res) {
node.sender->enqueue(std::move(res), context); auto s = actor_cast<actor>(node.sender);
if (s)
s->enqueue(std::move(res), context);
}
return true; return true;
} }
return false; return false;
......
...@@ -36,115 +36,43 @@ proxy_registry::backend::~backend() { ...@@ -36,115 +36,43 @@ proxy_registry::backend::~backend() {
// nop // nop
} }
proxy_registry::proxy_entry::proxy_entry() : backend_(nullptr) {
// nop
}
proxy_registry::proxy_entry::proxy_entry(actor_proxy::anchor_ptr ptr,
backend& ref)
: ptr_(std::move(ptr)),
backend_(&ref) {
// nop
}
proxy_registry::proxy_entry::~proxy_entry() {
reset(exit_reason::remote_link_unreachable);
}
void proxy_registry::proxy_entry::reset(exit_reason rsn) {
if (! ptr_ || ! backend_)
return;
auto ptr = ptr_->get();
ptr_.reset();
if (ptr)
ptr->kill_proxy(backend_->registry_context(), rsn);
}
void proxy_registry::proxy_entry::assign(actor_proxy::anchor_ptr ptr,
backend& ctx) {
using std::swap;
swap(ptr_, ptr);
backend_ = &ctx;
}
proxy_registry::proxy_registry(actor_system& sys, backend& be) proxy_registry::proxy_registry(actor_system& sys, backend& be)
: system_(sys), : system_(sys),
backend_(be) { backend_(be) {
// nop // nop
} }
size_t proxy_registry::count_proxies(const key_type& node) { proxy_registry::~proxy_registry() {
auto i = proxies_.find(node); clear();
return (i != proxies_.end()) ? i->second.size() : 0;
} }
std::vector<actor_proxy_ptr> proxy_registry::get_all() const { size_t proxy_registry::count_proxies(const key_type& node) {
std::vector<actor_proxy_ptr> result;
for (auto& outer : proxies_) {
for (auto& inner : outer.second) {
if (inner.second) {
auto ptr = inner.second->get();
if (ptr)
result.push_back(std::move(ptr));
}
}
}
return result;
}
std::vector<actor_proxy_ptr>
proxy_registry::get_all(const key_type& node) const {
std::vector<actor_proxy_ptr> result;
auto i = proxies_.find(node); auto i = proxies_.find(node);
if (i == proxies_.end()) return (i != proxies_.end()) ? i->second.size() : 0;
return result;
auto& submap = i->second;
for (auto& kvp : submap) {
if (kvp.second) {
auto ptr = kvp.second->get();
if (ptr)
result.push_back(std::move(ptr));
}
}
return result;
} }
actor_proxy_ptr proxy_registry::get(const key_type& node, actor_id aid) { strong_actor_ptr proxy_registry::get(const key_type& node, actor_id aid) {
auto& submap = proxies_[node]; auto& submap = proxies_[node];
auto i = submap.find(aid); auto i = submap.find(aid);
if (i != submap.end()) { if (i != submap.end())
auto res = i->second->get(); return i->second;
if (! res) {
submap.erase(i); // instance is expired
}
return res;
}
return nullptr; return nullptr;
} }
actor_proxy_ptr proxy_registry::get_or_put(const key_type& node, actor_id aid) { strong_actor_ptr proxy_registry::get_or_put(const key_type& nid, actor_id aid) {
CAF_LOG_TRACE(CAF_ARG(node) << CAF_ARG(aid)); CAF_LOG_TRACE(CAF_ARG(nid) << CAF_ARG(aid));
auto& submap = proxies_[node]; auto& result = proxies_[nid][aid];
auto& anchor = submap[aid]; if (! result)
actor_proxy_ptr result; result = backend_.make_proxy(nid, aid);
CAF_LOG_DEBUG_IF(! anchor, "found no anchor in submap"); return result;
if (anchor) { }
result = anchor->get();
CAF_LOG_DEBUG_IF(result, "found valid anchor in submap"); std::vector<strong_actor_ptr> proxy_registry::get_all(const key_type& node) {
CAF_LOG_DEBUG_IF(! result, "found expired anchor in submap"); std::vector<strong_actor_ptr> result;
} auto i = proxies_.find(node);
// replace anchor if we've created one using the default ctor if (i != proxies_.end())
// or if we've found an expired one in the map for (auto& kvp : i->second)
if (! anchor || ! result) { result.push_back(kvp.second);
result = backend_.make_proxy(node, aid);
CAF_LOG_WARNING_IF(! result, "backend could not create a proxy:"
<< CAF_ARG(node) << CAF_ARG(aid));
if (result)
anchor.assign(result->get_anchor(), backend_);
}
CAF_LOG_DEBUG_IF(result, CAF_ARG(result->address()));
CAF_LOG_DEBUG_IF(! result, "result = nullptr");
return result; return result;
} }
...@@ -152,9 +80,14 @@ bool proxy_registry::empty() const { ...@@ -152,9 +80,14 @@ bool proxy_registry::empty() const {
return proxies_.empty(); return proxies_.empty();
} }
void proxy_registry::erase(const key_type& inf) { void proxy_registry::erase(const key_type& nid) {
CAF_LOG_TRACE(CAF_ARG(inf)); CAF_LOG_TRACE(CAF_ARG(nid));
proxies_.erase(inf); auto i = proxies_.find(nid);
if (i == proxies_.end())
return;
for (auto& kvp : i->second)
kill_proxy(kvp.second, exit_reason::remote_link_unreachable);
proxies_.erase(i);
} }
void proxy_registry::erase(const key_type& inf, actor_id aid, exit_reason rsn) { void proxy_registry::erase(const key_type& inf, actor_id aid, exit_reason rsn) {
...@@ -165,7 +98,7 @@ void proxy_registry::erase(const key_type& inf, actor_id aid, exit_reason rsn) { ...@@ -165,7 +98,7 @@ void proxy_registry::erase(const key_type& inf, actor_id aid, exit_reason rsn) {
auto j = submap.find(aid); auto j = submap.find(aid);
if (j == submap.end()) if (j == submap.end())
return; return;
j->second.reset(rsn); kill_proxy(j->second, rsn);
submap.erase(j); submap.erase(j);
if (submap.empty()) if (submap.empty())
proxies_.erase(i); proxies_.erase(i);
...@@ -173,7 +106,17 @@ void proxy_registry::erase(const key_type& inf, actor_id aid, exit_reason rsn) { ...@@ -173,7 +106,17 @@ void proxy_registry::erase(const key_type& inf, actor_id aid, exit_reason rsn) {
} }
void proxy_registry::clear() { void proxy_registry::clear() {
for (auto& kvp : proxies_)
for (auto& sub_kvp : kvp.second)
kill_proxy(sub_kvp.second, exit_reason::remote_link_unreachable);
proxies_.clear(); proxies_.clear();
} }
void proxy_registry::kill_proxy(strong_actor_ptr& ptr, exit_reason rsn) {
if (! ptr)
return;
auto pptr = static_cast<actor_proxy*>(actor_cast<abstract_actor*>(ptr));
pptr->kill_proxy(backend_.registry_context(), rsn);
}
} // namespace caf } // namespace caf
...@@ -60,9 +60,9 @@ void response_promise::deliver_impl(message msg) { ...@@ -60,9 +60,9 @@ void response_promise::deliver_impl(message msg) {
return; return;
} }
if (source_) { if (source_) {
source_->enqueue(self_->address(), id_.response_id(), source_->enqueue(self_->ctrl(), id_.response_id(),
std::move(msg), self_->context()); std::move(msg), self_->context());
source_ = invalid_actor_addr; source_.reset();
return; return;
} }
if (self_) if (self_)
......
...@@ -31,12 +31,4 @@ resumable::subtype_t resumable::subtype() const { ...@@ -31,12 +31,4 @@ resumable::subtype_t resumable::subtype() const {
return unspecified; return unspecified;
} }
void resumable::intrusive_ptr_add_ref_impl() {
intrusive_ptr_add_ref(as_ref_counted_ptr());
}
void resumable::intrusive_ptr_release_impl() {
intrusive_ptr_release(as_ref_counted_ptr());
}
} // namespace caf } // namespace caf
...@@ -39,26 +39,31 @@ struct impl : blocking_actor { ...@@ -39,26 +39,31 @@ struct impl : blocking_actor {
} // namespace <anonymous> } // namespace <anonymous>
scoped_actor::scoped_actor(actor_system& as, bool hide_actor) : context_{&as} { scoped_actor::scoped_actor(actor_system& sys, bool hidden) : context_{&sys} {
actor_config cfg{&context_}; actor_config cfg{&context_};
self_.reset(new impl(cfg), false); self_ = make_actor<impl, strong_actor_ptr>(sys.next_actor_id(), sys.node(),
if (! hide_actor) { &sys, cfg);
if (! hidden) {
prev_ = CAF_SET_AID(self_->id()); prev_ = CAF_SET_AID(self_->id());
} }
CAF_LOG_TRACE(CAF_ARG(hide_actor)); CAF_LOG_TRACE(CAF_ARG(hidden));
self_->is_registered(! hide_actor); ptr()->is_registered(! hidden);
} }
scoped_actor::~scoped_actor() { scoped_actor::~scoped_actor() {
CAF_LOG_TRACE(""); CAF_LOG_TRACE("");
if (! self_) if (! self_)
return; return;
if (self_->is_registered()) { if (ptr()->is_registered()) {
CAF_SET_AID(prev_); CAF_SET_AID(prev_);
} }
auto r = self_->planned_exit_reason(); auto r = ptr()->planned_exit_reason();
self_->cleanup(r == exit_reason::not_exited ? exit_reason::normal : r, ptr()->cleanup(r == exit_reason::not_exited ? exit_reason::normal : r,
&context_); &context_);
}
blocking_actor* scoped_actor::ptr() const {
return static_cast<blocking_actor*>(actor_cast<abstract_actor*>(self_));
} }
std::string to_string(const scoped_actor& x) { std::string to_string(const scoped_actor& x) {
......
...@@ -28,20 +28,20 @@ ...@@ -28,20 +28,20 @@
namespace caf { namespace caf {
namespace decorator { namespace decorator {
sequencer::sequencer(actor_addr f, actor_addr g, message_types_set msg_types) sequencer::sequencer(strong_actor_ptr f, strong_actor_ptr g,
: monitorable_actor(&g->home_system(), message_types_set msg_types)
g->home_system().next_actor_id(), : monitorable_actor(is_abstract_actor_flag | is_actor_dot_decorator_flag),
g->node(),
is_abstract_actor_flag | is_actor_dot_decorator_flag),
f_(std::move(f)), f_(std::move(f)),
g_(std::move(g)), g_(std::move(g)),
msg_types_(std::move(msg_types)) { msg_types_(std::move(msg_types)) {
// composed actor has dependency on constituent actors by default; // composed actor has dependency on constituent actors by default;
// if either constituent actor is already dead upon establishing // if either constituent actor is already dead upon establishing
// the dependency, the actor is spawned dead // the dependency, the actor is spawned dead
f_->attach(default_attachable::make_monitor(f_, address())); f_->get()->attach(default_attachable::make_monitor(actor_cast<actor_addr>(f_),
address()));
if (g_ != f_) if (g_ != f_)
g_->attach(default_attachable::make_monitor(g_, address())); g_->get()->attach(default_attachable::make_monitor(actor_cast<actor_addr>(g_),
address()));
} }
void sequencer::enqueue(mailbox_element_ptr what, execution_unit* context) { void sequencer::enqueue(mailbox_element_ptr what, execution_unit* context) {
......
...@@ -40,7 +40,7 @@ struct splitter_state { ...@@ -40,7 +40,7 @@ struct splitter_state {
}; };
behavior fan_out_fan_in(stateful_actor<splitter_state>* self, behavior fan_out_fan_in(stateful_actor<splitter_state>* self,
const std::vector<actor_addr>& workers) { const std::vector<strong_actor_ptr>& workers) {
return { return {
others >> [=](const message& msg) { others >> [=](const message& msg) {
self->state.rp = self->make_response_promise(); self->state.rp = self->make_response_promise();
...@@ -67,11 +67,9 @@ behavior fan_out_fan_in(stateful_actor<splitter_state>* self, ...@@ -67,11 +67,9 @@ behavior fan_out_fan_in(stateful_actor<splitter_state>* self,
} // namespace <anonymous> } // namespace <anonymous>
splitter::splitter(std::vector<actor_addr> workers, message_types_set msg_types) splitter::splitter(std::vector<strong_actor_ptr> workers,
: monitorable_actor(&workers.front()->home_system(), message_types_set msg_types)
workers.front()->home_system().next_actor_id(), : monitorable_actor(is_abstract_actor_flag | is_actor_dot_decorator_flag),
workers.front()->node(),
is_abstract_actor_flag | is_actor_dot_decorator_flag),
workers_(std::move(workers)), workers_(std::move(workers)),
msg_types_(std::move(msg_types)) { msg_types_(std::move(msg_types)) {
// composed actor has dependency on constituent actors by default; // composed actor has dependency on constituent actors by default;
...@@ -79,7 +77,8 @@ splitter::splitter(std::vector<actor_addr> workers, message_types_set msg_types) ...@@ -79,7 +77,8 @@ splitter::splitter(std::vector<actor_addr> workers, message_types_set msg_types)
// the dependency, the actor is spawned dead // the dependency, the actor is spawned dead
auto addr = address(); auto addr = address();
for (auto& worker : workers_) for (auto& worker : workers_)
worker->attach(default_attachable::make_monitor(worker, addr)); worker->get()->attach(
default_attachable::make_monitor(actor_cast<actor_addr>(worker), addr));
} }
void splitter::enqueue(mailbox_element_ptr what, execution_unit* context) { void splitter::enqueue(mailbox_element_ptr what, execution_unit* context) {
...@@ -100,7 +99,10 @@ void splitter::enqueue(mailbox_element_ptr what, execution_unit* context) { ...@@ -100,7 +99,10 @@ void splitter::enqueue(mailbox_element_ptr what, execution_unit* context) {
} }
auto down_msg_handler = [&](const down_msg& dm) { auto down_msg_handler = [&](const down_msg& dm) {
// quit if either `f` or `g` are no longer available // quit if either `f` or `g` are no longer available
auto pred = [&](const actor_addr& x) { return x == dm.source; }; auto pred = [&](const strong_actor_ptr& x) {
return actor_addr::compare(
x.get(), actor_cast<actor_control_block*>(dm.source)) == 0;
};
if (std::any_of(workers_.begin(), workers_.end(), pred)) if (std::any_of(workers_.begin(), workers_.end(), pred))
monitorable_actor::cleanup(dm.reason, context); monitorable_actor::cleanup(dm.reason, context);
}; };
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "caf/sec.hpp" #include "caf/sec.hpp"
#include "caf/atom.hpp" #include "caf/atom.hpp"
#include "caf/actor.hpp"
#include "caf/config.hpp" #include "caf/config.hpp"
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
#include "caf/message_id.hpp" #include "caf/message_id.hpp"
...@@ -36,15 +37,14 @@ sync_request_bouncer::sync_request_bouncer(exit_reason r) ...@@ -36,15 +37,14 @@ sync_request_bouncer::sync_request_bouncer(exit_reason r)
// nop // nop
} }
void sync_request_bouncer::operator()(const actor_addr& sender, void sync_request_bouncer::operator()(const strong_actor_ptr& sender,
const message_id& mid) const { const message_id& mid) const {
CAF_ASSERT(rsn != exit_reason::not_exited); CAF_ASSERT(rsn != exit_reason::not_exited);
if (sender && mid.is_request()) { if (sender && mid.is_request()) {
auto ptr = actor_cast<abstract_actor_ptr>(sender); sender->enqueue(nullptr, mid.response_id(),
ptr->enqueue(invalid_actor_addr, mid.response_id(), make_message(make_error(sec::request_receiver_down)),
make_message(make_error(sec::request_receiver_down)), // TODO: this breaks out of the execution unit
// TODO: this breaks out of the execution unit nullptr);
nullptr);
} }
} }
......
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include "caf/group.hpp" #include "caf/group.hpp"
#include "caf/logger.hpp" #include "caf/logger.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp" #include "caf/message.hpp"
#include "caf/duration.hpp" #include "caf/duration.hpp"
#include "caf/actor_cast.hpp" #include "caf/actor_cast.hpp"
...@@ -59,7 +58,6 @@ const char* numbered_type_names[] = { ...@@ -59,7 +58,6 @@ const char* numbered_type_names[] = {
"@addr", "@addr",
"@addrvec", "@addrvec",
"@atom", "@atom",
"@channel",
"@charbuf", "@charbuf",
"@down", "@down",
"@duration", "@duration",
...@@ -77,6 +75,7 @@ const char* numbered_type_names[] = { ...@@ -77,6 +75,7 @@ const char* numbered_type_names[] = {
"@node", "@node",
"@str", "@str",
"@strmap", "@strmap",
"@strong_actor_ptr",
"@strset", "@strset",
"@strvec", "@strvec",
"@timeout", "@timeout",
...@@ -87,6 +86,7 @@ const char* numbered_type_names[] = { ...@@ -87,6 +86,7 @@ const char* numbered_type_names[] = {
"@u64", "@u64",
"@u8", "@u8",
"@unit", "@unit",
"@weak_actor_ptr",
"bool", "bool",
"double", "double",
"float" "float"
...@@ -165,7 +165,7 @@ uniform_type_info_map::renderer(atom_value x) const { ...@@ -165,7 +165,7 @@ uniform_type_info_map::renderer(atom_value x) const {
actor_factory_result uniform_type_info_map::make_actor(const std::string& name, actor_factory_result uniform_type_info_map::make_actor(const std::string& name,
actor_config& cfg, actor_config& cfg,
message& msg) const { message& msg) const {
actor_addr res; strong_actor_ptr res;
std::set<std::string> ifs; std::set<std::string> ifs;
auto i = factories_.find(name); auto i = factories_.find(name);
if (i != factories_.end()) if (i != factories_.end())
......
...@@ -39,16 +39,16 @@ struct fixture { ...@@ -39,16 +39,16 @@ struct fixture {
actor_system system{cfg}; actor_system system{cfg};
scoped_actor self{system}; scoped_actor self{system};
CAF_MESSAGE("set aut"); CAF_MESSAGE("set aut");
actor_addr res; strong_actor_ptr res;
std::set<std::string> ifs; std::set<std::string> ifs;
scoped_execution_unit context{&system}; scoped_execution_unit context{&system};
actor_config actor_cfg{&context}; actor_config actor_cfg{&context};
std::tie(res, ifs) = system.types().make_actor("test_actor", actor_cfg, args); std::tie(res, ifs) = system.types().make_actor("test_actor", actor_cfg, args);
if (expect_fail) { if (expect_fail) {
CAF_REQUIRE(res == invalid_actor_addr); CAF_REQUIRE(! res);
return; return;
} }
CAF_REQUIRE(res != invalid_actor_addr); CAF_REQUIRE(res);
CAF_CHECK(ifs.empty()); CAF_CHECK(ifs.empty());
auto aut = actor_cast<actor>(res); auto aut = actor_cast<actor>(res);
CAF_REQUIRE(aut != invalid_actor); CAF_REQUIRE(aut != invalid_actor);
......
...@@ -71,7 +71,7 @@ struct send_to_self { ...@@ -71,7 +71,7 @@ struct send_to_self {
CAF_TEST(receive_atoms) { CAF_TEST(receive_atoms) {
scoped_actor self{system}; scoped_actor self{system};
send_to_self f{self.get()}; send_to_self f{self.ptr()};
f(foo_atom::value, static_cast<uint32_t>(42)); f(foo_atom::value, static_cast<uint32_t>(42));
f(abc_atom::value, def_atom::value, "cstring"); f(abc_atom::value, def_atom::value, "cstring");
f(1.f); f(1.f);
......
...@@ -516,7 +516,7 @@ CAF_TEST(requests) { ...@@ -516,7 +516,7 @@ CAF_TEST(requests) {
on("hi", arg_match) >> [&](actor from) { on("hi", arg_match) >> [&](actor from) {
s->request(from, chrono::minutes(1), "whassup?", s).receive( s->request(from, chrono::minutes(1), "whassup?", s).receive(
[&](const string& str) { [&](const string& str) {
CAF_CHECK(s->current_sender() != nullptr); CAF_CHECK(s->current_sender());
CAF_CHECK_EQUAL(str, "nothing"); CAF_CHECK_EQUAL(str, "nothing");
s->send(from, "goodbye!"); s->send(from, "goodbye!");
} }
......
...@@ -107,7 +107,7 @@ struct fixture { ...@@ -107,7 +107,7 @@ struct fixture {
} }
void load_to_config_server(const char* str) { void load_to_config_server(const char* str) {
config_server = system.registry().get(atom("ConfigServ")); config_server = actor_cast<actor>(system.registry().get(atom("ConfigServ")));
CAF_REQUIRE(config_server != invalid_actor); CAF_REQUIRE(config_server != invalid_actor);
// clear config // clear config
scoped_actor self{system}; scoped_actor self{system};
......
...@@ -123,6 +123,7 @@ struct fixture { ...@@ -123,6 +123,7 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(dynamic_stateful_actor_tests, fixture) CAF_TEST_FIXTURE_SCOPE(dynamic_stateful_actor_tests, fixture)
CAF_TEST(dynamic_stateful_actor) { CAF_TEST(dynamic_stateful_actor) {
CAF_REQUIRE(monitored + monitored == monitored);
test_adder(system.spawn(adder)); test_adder(system.spawn(adder));
} }
......
...@@ -83,8 +83,7 @@ public: ...@@ -83,8 +83,7 @@ public:
friend class scribe; friend class scribe;
friend class doorman; friend class doorman;
void enqueue(const actor_addr&, message_id, void enqueue(strong_actor_ptr, message_id, message, execution_unit*) override;
message, execution_unit*) override;
void enqueue(mailbox_element_ptr, execution_unit*) override; void enqueue(mailbox_element_ptr, execution_unit*) override;
......
...@@ -71,7 +71,7 @@ public: ...@@ -71,7 +71,7 @@ public:
virtual void deliver(const node_id& source_node, actor_id source_actor, virtual void deliver(const node_id& source_node, actor_id source_actor,
const node_id& dest_node, actor_id dest_actor, const node_id& dest_node, actor_id dest_actor,
message_id mid, message_id mid,
std::vector<actor_addr>& forwarding_stack, std::vector<strong_actor_ptr>& forwarding_stack,
message& msg) = 0; message& msg) = 0;
/// Called whenever BASP learns the ID of a remote node /// Called whenever BASP learns the ID of a remote node
...@@ -104,7 +104,7 @@ public: ...@@ -104,7 +104,7 @@ public:
using payload_writer = callback<serializer&>; using payload_writer = callback<serializer&>;
/// Describes a callback function object for `remove_published_actor`. /// Describes a callback function object for `remove_published_actor`.
using removed_published_actor = callback<const actor_addr&, uint16_t>; using removed_published_actor = callback<const strong_actor_ptr&, uint16_t>;
instance(abstract_broker* parent, callee& lstnr); instance(abstract_broker* parent, callee& lstnr);
...@@ -133,7 +133,7 @@ public: ...@@ -133,7 +133,7 @@ public:
/// Adds a new actor to the map of published actors. /// Adds a new actor to the map of published actors.
void add_published_actor(uint16_t port, void add_published_actor(uint16_t port,
actor_addr published_actor, strong_actor_ptr published_actor,
std::set<std::string> published_interface); std::set<std::string> published_interface);
/// Removes the actor currently assigned to `port`. /// Removes the actor currently assigned to `port`.
...@@ -146,9 +146,10 @@ public: ...@@ -146,9 +146,10 @@ public:
removed_published_actor* cb = nullptr); removed_published_actor* cb = nullptr);
/// Returns `true` if a path to destination existed, `false` otherwise. /// Returns `true` if a path to destination existed, `false` otherwise.
bool dispatch(execution_unit* ctx, const actor_addr& sender, bool dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
const std::vector<actor_addr>& forwarding_stack, const std::vector<strong_actor_ptr>& forwarding_stack,
const actor_addr& receiver, message_id mid, const message& msg); const strong_actor_ptr& receiver,
message_id mid, const message& msg);
/// Returns the actor namespace associated to this BASP protocol instance. /// Returns the actor namespace associated to this BASP protocol instance.
proxy_registry& proxies() { proxy_registry& proxies() {
...@@ -162,7 +163,7 @@ public: ...@@ -162,7 +163,7 @@ public:
/// Stores the address of a published actor along with its publicly /// Stores the address of a published actor along with its publicly
/// visible messaging interface. /// visible messaging interface.
using published_actor = std::pair<actor_addr, std::set<std::string>>; using published_actor = std::pair<strong_actor_ptr, std::set<std::string>>;
/// Maps ports to addresses and interfaces of published actors. /// Maps ports to addresses and interfaces of published actors.
using published_actor_map = std::unordered_map<uint16_t, published_actor>; using published_actor_map = std::unordered_map<uint16_t, published_actor>;
......
...@@ -47,7 +47,7 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee { ...@@ -47,7 +47,7 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee {
~basp_broker_state(); ~basp_broker_state();
// inherited from proxy_registry::backend // inherited from proxy_registry::backend
actor_proxy_ptr make_proxy(node_id nid, actor_id aid) override; strong_actor_ptr make_proxy(node_id nid, actor_id aid) override;
// inherited from proxy_registry::backend // inherited from proxy_registry::backend
execution_unit* registry_context() override; execution_unit* registry_context() override;
...@@ -68,7 +68,7 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee { ...@@ -68,7 +68,7 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee {
// inherited from basp::instance::listener // inherited from basp::instance::listener
void deliver(const node_id& source_node, actor_id source_actor, void deliver(const node_id& source_node, actor_id source_actor,
const node_id& dest_node, actor_id dest_actor, const node_id& dest_node, actor_id dest_actor,
message_id mid, std::vector<actor_addr>& stages, message_id mid, std::vector<strong_actor_ptr>& stages,
message& msg) override; message& msg) override;
// performs bookkeeping such as managing `spawn_servers` // performs bookkeeping such as managing `spawn_servers`
...@@ -115,10 +115,6 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee { ...@@ -115,10 +115,6 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee {
// points to the current context for callbacks such as `make_proxy` // points to the current context for callbacks such as `make_proxy`
connection_context* this_context = nullptr; connection_context* this_context = nullptr;
// stores all published actors we know from other nodes, this primarily
// keeps the associated proxies alive to work around subtle bugs
std::unordered_map<node_id, std::pair<uint16_t, actor_addr>> known_remotes;
// stores handles to spawn servers for other nodes; these servers // stores handles to spawn servers for other nodes; these servers
// are spawned whenever the broker learns a new node ID and try to // are spawned whenever the broker learns a new node ID and try to
// get a 'SpawnServ' instance on the remote side // get a 'SpawnServ' instance on the remote side
......
...@@ -69,8 +69,6 @@ protected: ...@@ -69,8 +69,6 @@ protected:
virtual behavior make_behavior(); virtual behavior make_behavior();
}; };
using broker_ptr = intrusive_ptr<broker>;
/// Convenience template alias for declaring state-based brokers. /// Convenience template alias for declaring state-based brokers.
template <class State> template <class State>
using stateful_broker = stateful_actor<State, broker>; using stateful_broker = stateful_actor<State, broker>;
......
...@@ -68,8 +68,7 @@ protected: ...@@ -68,8 +68,7 @@ protected:
void reset_mailbox_element() { void reset_mailbox_element() {
SysMsgType tmp; SysMsgType tmp;
set_hdl(tmp, hdl_); set_hdl(tmp, hdl_);
mailbox_elem_ptr_ = mailbox_element::make_joint(invalid_actor_addr, mailbox_elem_ptr_ = mailbox_element::make_joint(nullptr, invalid_message_id,
invalid_message_id,
{}, tmp); {}, tmp);
} }
......
...@@ -48,8 +48,8 @@ public: ...@@ -48,8 +48,8 @@ public:
/// Called whenever a message has arrived via the network. /// Called whenever a message has arrived via the network.
virtual void message_received_cb(const node_id& source, virtual void message_received_cb(const node_id& source,
const actor_addr& from, const strong_actor_ptr& from,
const actor_addr& dest, const strong_actor_ptr& dest,
message_id mid, message_id mid,
const message& msg); const message& msg);
...@@ -61,13 +61,13 @@ public: ...@@ -61,13 +61,13 @@ public:
/// have a direct connection to `dest_node`. /// have a direct connection to `dest_node`.
/// @param mid The ID of the message. /// @param mid The ID of the message.
/// @param payload The message we've sent. /// @param payload The message we've sent.
virtual void message_sent_cb(const actor_addr& from, const node_id& hop, virtual void message_sent_cb(const strong_actor_ptr& from, const node_id& hop,
const actor_addr& dest, message_id mid, const strong_actor_ptr& dest, message_id mid,
const message& payload); const message& payload);
/// Called whenever no route for sending a message exists. /// Called whenever no route for sending a message exists.
virtual void message_sending_failed_cb(const actor_addr& from, virtual void message_sending_failed_cb(const strong_actor_ptr& from,
const actor_addr& dest, const strong_actor_ptr& dest,
message_id mid, message_id mid,
const message& payload); const message& payload);
...@@ -80,12 +80,12 @@ public: ...@@ -80,12 +80,12 @@ public:
const std::vector<char>* payload); const std::vector<char>* payload);
/// Called whenever an actor has been published. /// Called whenever an actor has been published.
virtual void actor_published_cb(const actor_addr& addr, virtual void actor_published_cb(const strong_actor_ptr& addr,
const std::set<std::string>& ifs, const std::set<std::string>& ifs,
uint16_t port); uint16_t port);
/// Called whenever a new remote actor appeared. /// Called whenever a new remote actor appeared.
virtual void new_remote_actor_cb(const actor_addr& addr); virtual void new_remote_actor_cb(const strong_actor_ptr& addr);
/// Called whenever a handshake via a direct TCP connection succeeded. /// Called whenever a handshake via a direct TCP connection succeeded.
virtual void new_connection_established_cb(const node_id& node); virtual void new_connection_established_cb(const node_id& node);
...@@ -108,7 +108,7 @@ public: ...@@ -108,7 +108,7 @@ public:
/// tried to send a message to an actor ID that could not be found /// tried to send a message to an actor ID that could not be found
/// in the registry. /// in the registry.
virtual void invalid_message_received_cb(const node_id& source, virtual void invalid_message_received_cb(const node_id& source,
const actor_addr& sender, const strong_actor_ptr& sender,
actor_id invalid_dest, actor_id invalid_dest,
message_id mid, const message& msg); message_id mid, const message& msg);
......
...@@ -52,10 +52,10 @@ public: ...@@ -52,10 +52,10 @@ public:
/// @returns The actual port the OS uses after `bind()`. If `port == 0` the OS /// @returns The actual port the OS uses after `bind()`. If `port == 0` the OS
/// chooses a random high-level port. /// chooses a random high-level port.
template <class Handle> template <class Handle>
uint16_t publish(const Handle& whom, uint16_t port, uint16_t publish(Handle&& whom, uint16_t port,
const char* in = nullptr, bool reuse_addr = false) { const char* in = nullptr, bool reuse_addr = false) {
return publish(whom.address(), system().message_types(whom), return publish(actor_cast<strong_actor_ptr>(std::forward<Handle>(whom)),
port, in, reuse_addr); system().message_types(whom), port, in, reuse_addr);
} }
/// Makes *all* local groups accessible via network /// Makes *all* local groups accessible via network
...@@ -127,9 +127,6 @@ public: ...@@ -127,9 +127,6 @@ public:
return result; return result;
} }
/// Adds `bptr` to the list of known brokers.
void add_broker(broker_ptr bptr);
/// Runs `fun` in the event loop of the middleman. /// Runs `fun` in the event loop of the middleman.
/// @note This member function is thread-safe. /// @note This member function is thread-safe.
template <class F> template <class F>
...@@ -301,13 +298,13 @@ private: ...@@ -301,13 +298,13 @@ private:
return system().spawn_class<Impl, Os>(cfg); return system().spawn_class<Impl, Os>(cfg);
} }
uint16_t publish(const actor_addr& whom, std::set<std::string> sigs, uint16_t publish(const strong_actor_ptr& whom, std::set<std::string> sigs,
uint16_t port, const char* in, bool ru); uint16_t port, const char* in, bool ru);
void unpublish(const actor_addr& whom, uint16_t port); void unpublish(const actor_addr& whom, uint16_t port);
actor_addr remote_actor(std::set<std::string> ifs, strong_actor_ptr remote_actor(std::set<std::string> ifs,
std::string host, uint16_t port); std::string host, uint16_t port);
// environment // environment
actor_system& system_; actor_system& system_;
...@@ -317,8 +314,6 @@ private: ...@@ -317,8 +314,6 @@ private:
std::thread thread_; std::thread thread_;
// keeps track of "singleton-like" brokers // keeps track of "singleton-like" brokers
std::map<atom_value, actor> named_brokers_; std::map<atom_value, actor> named_brokers_;
// keeps track of anonymous brokers
std::set<broker_ptr> brokers_;
// user-defined hooks // user-defined hooks
hook_uptr hooks_; hook_uptr hooks_;
// actor offering asyncronous IO by managing this singleton instance // actor offering asyncronous IO by managing this singleton instance
......
This diff is collapsed.
...@@ -104,7 +104,8 @@ public: ...@@ -104,7 +104,8 @@ public:
class runnable : public resumable, public ref_counted { class runnable : public resumable, public ref_counted {
public: public:
subtype_t subtype() const override; subtype_t subtype() const override;
ref_counted* as_ref_counted_ptr() override; void intrusive_ptr_add_ref_impl() override;
void intrusive_ptr_release_impl() override;
}; };
/// Makes sure the multipler does not exit its event loop until /// Makes sure the multipler does not exit its event loop until
......
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
namespace caf { namespace caf {
namespace io { namespace io {
void abstract_broker::enqueue(strong_actor_ptr src, message_id mid,
message msg, execution_unit* eu) {
enqueue(mailbox_element::make(std::move(src), mid, {}, std::move(msg)), eu);
}
void abstract_broker::enqueue(mailbox_element_ptr ptr, execution_unit*) { void abstract_broker::enqueue(mailbox_element_ptr ptr, execution_unit*) {
CAF_PUSH_AID(id()); CAF_PUSH_AID(id());
CAF_LOG_TRACE("enqueue " << CAF_ARG(ptr->msg)); CAF_LOG_TRACE("enqueue " << CAF_ARG(ptr->msg));
...@@ -62,16 +67,11 @@ void abstract_broker::enqueue(mailbox_element_ptr ptr, execution_unit*) { ...@@ -62,16 +67,11 @@ void abstract_broker::enqueue(mailbox_element_ptr ptr, execution_unit*) {
} }
} }
void abstract_broker::enqueue(const actor_addr& sender, message_id mid,
message msg, execution_unit* eu) {
enqueue(mailbox_element::make(sender, mid, {}, std::move(msg)), eu);
}
void abstract_broker::launch(execution_unit* eu, bool is_lazy, bool is_hidden) { void abstract_broker::launch(execution_unit* eu, bool is_lazy, bool is_hidden) {
CAF_ASSERT(eu != nullptr); CAF_ASSERT(eu != nullptr);
CAF_ASSERT(eu == &backend()); CAF_ASSERT(eu == &backend());
// add implicit reference count held by middleman/multiplexer // add implicit reference count held by middleman/multiplexer
ref(); intrusive_ptr_add_ref(ctrl());
is_registered(! is_hidden); is_registered(! is_hidden);
CAF_PUSH_AID(id()); CAF_PUSH_AID(id());
CAF_LOG_TRACE("init and launch broker:" << CAF_ARG(id())); CAF_LOG_TRACE("init and launch broker:" << CAF_ARG(id()));
......
This diff is collapsed.
...@@ -709,7 +709,6 @@ default_multiplexer::~default_multiplexer() { ...@@ -709,7 +709,6 @@ default_multiplexer::~default_multiplexer() {
void default_multiplexer::exec_later(resumable* ptr) { void default_multiplexer::exec_later(resumable* ptr) {
CAF_ASSERT(ptr); CAF_ASSERT(ptr);
CAF_ASSERT(ptr->as_ref_counted_ptr()->get_reference_count() > 0);
switch (ptr->subtype()) { switch (ptr->subtype()) {
case resumable::io_actor: case resumable::io_actor:
case resumable::function_object: case resumable::function_object:
......
This diff is collapsed.
This diff is collapsed.
...@@ -48,7 +48,7 @@ void manager::detach(execution_unit* ctx, bool invoke_disconnect_message) { ...@@ -48,7 +48,7 @@ void manager::detach(execution_unit* ctx, bool invoke_disconnect_message) {
set_parent(nullptr); set_parent(nullptr);
detach_from(ptr); detach_from(ptr);
if (invoke_disconnect_message) { if (invoke_disconnect_message) {
auto mptr = mailbox_element::make(invalid_actor_addr, invalid_message_id, auto mptr = mailbox_element::make(nullptr, invalid_message_id,
{}, detach_message()); {}, detach_message());
ptr->exec_single_event(ctx, mptr); ptr->exec_single_event(ctx, mptr);
} }
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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