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()
if(NOT CAF_ENABLE_RUNTIME_CHECKS)
set(CAF_ENABLE_RUNTIME_CHECKS no)
endif()
if(NOT CAF_NO_MEM_MANAGEMENT)
set(CAF_NO_MEM_MANAGEMENT no)
endif()
if(NOT CAF_BUILD_STATIC_ONLY)
set(CAF_BUILD_STATIC_ONLY no)
endif()
if(NOT CAF_BUILD_STATIC)
set(CAF_BUILD_STATIC no)
endif()
if(NOT CAF_NO_OPENCL)
set(CAF_NO_OPENCL no)
endif()
if(NOT CAF_NO_TOOLS)
set(CAF_NO_TOOLS no)
endif()
if(NOT CAF_NO_SUMMARY)
set(CAF_NO_SUMMARY no)
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 #
......@@ -429,7 +441,7 @@ endmacro()
# build core and I/O library
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
if(NOT CAF_NO_OPENCL)
......@@ -570,6 +582,7 @@ macro(invertYesNo in out)
endif()
endmacro()
# invert CAF_NO_* variables for nicer output
invertYesNo(CAF_NO_IO CAF_BUILD_IO)
invertYesNo(CAF_NO_EXAMPLES CAF_BUILD_EXAMPLES)
invertYesNo(CAF_NO_TOOLS CAF_BUILD_TOOLS)
invertYesNo(CAF_NO_UNIT_TESTS CAF_BUILD_UNIT_TESTS)
......@@ -596,6 +609,7 @@ if(NOT CAF_NO_SUMMARY)
"\nLog level: ${LOG_LEVEL_STR}"
"\nWith mem. mgmt.: ${CAF_BUILD_MEM_MANAGEMENT}"
"\n"
"\nBuild I/O module: ${CAF_BUILD_IO}"
"\nBuild tools: ${CAF_BUILD_TOOLS}"
"\nBuild examples: ${CAF_BUILD_EXAMPLES}"
"\nBuild unit tests: ${CAF_BUILD_UNIT_TESTS}"
......
......@@ -60,12 +60,13 @@ Usage: $0 [OPTION]... [VAR=VALUE]...
--no-protobuf-examples build without Google Protobuf examples
--no-curl-examples build without libcurl examples
--no-unit-tests build without unit tests
--no-opencl build without opencl
--no-opencl build without OpenCL module
--no-nexus build without nexus
--no-cash build without cash
--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-io build without I/O module
--no-summary do not print configuration before building
Testing:
......@@ -354,6 +355,9 @@ while [ $# -ne 0 ]; do
--no-tools)
append_cache_entry CAF_NO_TOOLS BOOL yes
;;
--no-io)
append_cache_entry CAF_NO_IO BOOL yes
;;
--no-summary)
append_cache_entry CAF_NO_SUMMARY BOOL yes
;;
......
......@@ -19,6 +19,7 @@ set (LIBCAF_CORE_SRCS
src/actor.cpp
src/actor_addr.cpp
src/actor_config.cpp
src/actor_control_block.cpp
src/actor_companion.cpp
src/actor_ostream.cpp
src/actor_pool.cpp
......@@ -35,7 +36,6 @@ set (LIBCAF_CORE_SRCS
src/binary_deserializer.cpp
src/binary_serializer.cpp
src/blocking_actor.cpp
src/channel.cpp
src/concatenated_tuple.cpp
src/continue_helper.cpp
src/decorated_tuple.cpp
......
......@@ -52,12 +52,19 @@ using actor_id = uint64_t;
/// Denotes an ID that is never used by an actor.
constexpr actor_id invalid_actor_id = 0;
using abstract_actor_ptr = intrusive_ptr<abstract_actor>;
/// Base class for all actor implementations.
class abstract_actor : public abstract_channel {
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;
/// Enqueues a new message wrapped in a `mailbox_element` to the actor.
......@@ -115,20 +122,18 @@ public:
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
/// an empty set if this actor is untyped.
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).
actor_system& home_system() {
CAF_ASSERT(home_system_ != nullptr);
return *home_system_;
}
actor_system& home_system() const noexcept;
/****************************************************************************
* here be dragons: end of public interface *
......@@ -143,7 +148,7 @@ public:
remove_backlink_op
};
// used by ...
// flags storing runtime information used by ...
static constexpr int trap_exit_flag = 0x01; // local_actor
static constexpr int has_timeout_flag = 0x02; // single_timeout
static constexpr int is_registered_flag = 0x04; // (several actors)
......@@ -225,13 +230,11 @@ public:
void is_registered(bool value);
virtual bool link_impl(linking_operation op, const actor_addr& other) = 0;
// cannot be changed after construction
const actor_id id_;
inline bool is_actor_decorator() const {
return static_cast<bool>(flags() & is_actor_decorator_mask);
}
// points to the actor system that created this actor
actor_system* home_system_;
virtual bool link_impl(linking_operation op, const actor_addr& other) = 0;
/// @endcond
......@@ -240,8 +243,14 @@ protected:
explicit abstract_actor(actor_config& cfg);
/// Creates a new actor instance.
abstract_actor(actor_system* sys, actor_id aid, node_id nid,
int flags = abstract_channel::is_abstract_actor_flag);
explicit abstract_actor(int flags = 0);
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);
......
......@@ -23,16 +23,14 @@
#include <atomic>
#include "caf/fwd.hpp"
#include "caf/node_id.hpp"
#include "caf/message_id.hpp"
#include "caf/ref_counted.hpp"
namespace caf {
/// Interface for all message receivers. * This interface describes an
/// entity that can receive messages and is implemented by {@link actor}
/// and {@link group}.
class abstract_channel : public ref_counted {
class abstract_channel {
public:
friend class abstract_actor;
friend class abstract_group;
......@@ -40,13 +38,8 @@ public:
virtual ~abstract_channel();
/// Enqueues a new message without forwarding stack to the channel.
virtual void enqueue(const actor_addr& sender, message_id mid,
message content, execution_unit* host) = 0;
/// Returns the ID of the node this actor is running on.
inline node_id node() const {
return node_;
}
virtual void enqueue(strong_actor_ptr sender, message_id mid, message content,
execution_unit* host = nullptr) = 0;
static constexpr int is_abstract_actor_flag = 0x100000;
......@@ -87,21 +80,14 @@ protected:
private:
// 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
// first 20 bits, i.e., the bitmask 0xFFF00000 is reserved for
// channel-related 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
#endif // CAF_ABSTRACT_CHANNEL_HPP
......@@ -32,7 +32,7 @@
namespace caf {
/// A multicast group.
class abstract_group : public abstract_channel {
class abstract_group : public ref_counted, public abstract_channel {
public:
friend class local_actor;
friend class subscription;
......@@ -85,7 +85,7 @@ public:
/// Subscribes `who` to this group and returns `true` on success
/// 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.
virtual void stop() = 0;
......@@ -99,11 +99,12 @@ protected:
std::string group_id, const node_id& nid);
// called by local_actor
virtual void unsubscribe(const actor_addr& who) = 0;
virtual void unsubscribe(const actor_control_block* who) = 0;
actor_system& system_;
module_ptr module_;
std::string identifier_;
node_id origin_;
};
/// A smart pointer type that manages instances of {@link group}.
......
......@@ -29,8 +29,8 @@
#include "caf/fwd.hpp"
#include "caf/actor_marker.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/comparable.hpp"
#include "caf/detail/type_traits.hpp"
......@@ -71,8 +71,11 @@ public:
friend class local_actor;
// allow conversion via actor_cast
template <class>
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 = false;
actor() = default;
actor(actor&&) = default;
......@@ -80,27 +83,17 @@ public:
actor& operator=(actor&&) = default;
actor& operator=(const actor&) = default;
template <class T,
class Enable =
typename std::enable_if<
is_convertible_to_actor<T>::value
>::type>
actor(intrusive_ptr<T> ptr) : ptr_(std::move(ptr)) {
// nop
}
actor(const scoped_actor&);
actor(const invalid_actor_t&);
template <class T,
class Enable =
typename std::enable_if<
is_convertible_to_actor<T>::value
>::type>
actor(T* ptr) : ptr_(ptr) {
class = typename std::enable_if<
std::is_base_of<dynamically_typed_actor_base, T>::value
>::type>
actor(T* ptr) : ptr_(ptr->ctrl()) {
// nop
}
actor(const scoped_actor&);
actor(const invalid_actor_t&);
template <class T>
typename std::enable_if<is_convertible_to_actor<T>::value, actor&>::type
operator=(intrusive_ptr<T> ptr) {
......@@ -151,7 +144,8 @@ public:
/// @cond PRIVATE
inline abstract_actor* operator->() const noexcept {
return ptr_.get();
CAF_ASSERT(ptr_);
return ptr_->get();
}
intptr_t compare(const actor&) const noexcept;
......@@ -168,24 +162,33 @@ public:
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
private:
actor bind_impl(message msg) const;
inline abstract_actor* get() const noexcept {
inline actor_control_block* get() const noexcept {
return ptr_.get();
}
inline abstract_actor* release() noexcept {
inline actor_control_block* release() noexcept {
return ptr_.release();
}
actor(abstract_actor*);
actor(abstract_actor*, bool);
actor(actor_control_block*);
abstract_actor_ptr ptr_;
strong_actor_ptr ptr_;
};
/// 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) {
}
/// @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
void serialize(deserializer&, actor&, const unsigned int);
bool operator!=(const actor& lhs, abstract_actor* rhs);
/// @relates actor
std::string to_string(const actor& x);
bool operator!=(abstract_actor* lhs, const actor& rhs);
} // namespace caf
......
......@@ -25,10 +25,9 @@
#include <functional>
#include <type_traits>
#include "caf/intrusive_ptr.hpp"
#include "caf/fwd.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/comparable.hpp"
......@@ -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.
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_ptr> {
detail::comparable<actor_addr, actor_control_block*> {
public:
// grant access to private ctor
friend class actor;
friend class abstract_actor;
template <class>
friend struct actor_cast_access;
// 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 = true;
actor_addr() = default;
actor_addr(actor_addr&&) = default;
......@@ -81,49 +86,62 @@ public:
/// Returns the origin node of this actor.
node_id node() const noexcept;
/// Returns the hosting actor system.
actor_system* home_system() const noexcept;
/// Exchange content of `*this` and `other`.
void swap(actor_addr& other) noexcept;
/// @cond PRIVATE
inline abstract_actor* operator->() const noexcept {
return ptr_.get();
}
static intptr_t compare(const abstract_actor* lhs, const abstract_actor* rhs);
static intptr_t compare(const actor_control_block* lhs,
const actor_control_block* rhs);
intptr_t compare(const actor_addr& 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());
}
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
private:
inline abstract_actor* get() const noexcept {
inline actor_control_block* get() const noexcept {
return ptr_.get();
}
inline abstract_actor* release() noexcept {
inline actor_control_block* release() noexcept {
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
......@@ -134,7 +152,6 @@ struct hash<caf::actor_addr> {
inline size_t operator()(const caf::actor_addr& ref) const {
return static_cast<size_t>(ref.id());
}
};
} // namespace std
......
......@@ -22,35 +22,118 @@
#include <type_traits>
#include "caf/fwd.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
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>
struct actor_cast_access {
constexpr actor_cast_access() {
// nop
struct is_weak_ptr<T*> {
static constexpr bool value = false;
};
} // 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>
T operator()(U& y) const {
return {y.get(), true};
To operator()(abstract_actor* x) const {
return x ? x->ctrl() : nullptr;
}
template<class U>
typename std::enable_if<std::is_rvalue_reference<U&&>::value, T>::type
operator()(U&& y) const {
return {y.release(), false};
template <class T,
class = typename std::enable_if<! std::is_pointer<T>::value>::type>
To operator()(const T& x) const {
return x.get();
}
};
template <class T>
struct actor_cast_access<T*> {
constexpr actor_cast_access() {
// nop
template <class From>
class actor_cast_access<abstract_actor*, From, raw_ptr_cast> {
public:
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>
T* operator()(const U& y) const {
return y.get();
To operator()(From&& x) const {
return {x.release(), false};
}
};
......@@ -58,7 +141,12 @@ struct actor_cast_access<T*> {
/// handle or raw pointer of type `T`.
template <class T, class U>
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));
}
......
......@@ -54,8 +54,8 @@ public:
void enqueue(mailbox_element_ptr what, execution_unit* host) override;
void enqueue(const actor_addr& sender, message_id mid,
message content, execution_unit* host) override;
void enqueue(strong_actor_ptr sender, message_id mid, message content,
execution_unit* host) 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 @@
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&)>;
......@@ -155,7 +155,8 @@ actor_factory make_actor_factory(F fun) {
return result;
};
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) {
msg.apply(factory);
if (hdl == invalid_actor)
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>
actor_factory make_actor_factory() {
/*
static_assert(std::is_same<T*, decltype(new T(std::declval<actor_config&>(),
std::declval<Ts>()...))>::value,
"no constructor for T(Ts...) exists");
*/
static_assert(detail::conjunction<
std::is_lvalue_reference<Ts>::value...
>::value,
......
......@@ -42,7 +42,9 @@ public:
/// Open redirection file in append mode.
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.
actor_ostream& write(std::string arg);
......@@ -81,12 +83,12 @@ public:
}
private:
intrusive_ptr<abstract_actor> self_;
actor self_;
actor printer_;
};
/// 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.
actor_ostream aout(scoped_actor& self);
......
......@@ -98,16 +98,17 @@ public:
/// function `fac` using the dispatch policy `pol`.
static actor make(execution_unit* ptr, size_t n, factory fac, policy pol);
void enqueue(const actor_addr& sender, message_id mid,
message content, execution_unit* host) override;
void enqueue(strong_actor_ptr sender, message_id mid, message content,
execution_unit* host) override;
void enqueue(mailbox_element_ptr what, execution_unit* host) override;
actor_pool(actor_config& cfg);
private:
bool filter(upgrade_lock<detail::shared_spinlock>&, const actor_addr& sender,
message_id mid, const message& content, execution_unit* host);
bool filter(upgrade_lock<detail::shared_spinlock>&,
const strong_actor_ptr& sender, message_id mid,
const message& content, execution_unit* host);
// call without workers_mtx_ held
void quit(execution_unit* host);
......
......@@ -30,44 +30,11 @@
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,
/// or different hardware, or in a separate process.
class actor_proxy : public monitorable_actor {
public:
/// An anchor points to a proxy instance without sharing
/// 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:
/// Invokes cleanup code.
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
......
......@@ -29,8 +29,8 @@
#include "caf/fwd.hpp"
#include "caf/actor.hpp"
#include "caf/actor_addr.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/shared_spinlock.hpp"
#include "caf/detail/singleton_mixin.hpp"
......@@ -52,13 +52,13 @@ public:
/// A registry entry consists of a pointer to the actor and an
/// exit reason. An entry with a nullptr means the actor has finished
/// 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`.
id_entry get(actor_id key) const;
/// 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,
/// leaving `reason` for future reference.
......@@ -78,15 +78,21 @@ public:
void await_running_count_equal(size_t expected) const;
/// 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`.
void put(atom_value key, actor value);
void put(atom_value key, strong_actor_ptr value);
/// Removes a name mapping.
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;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 @@
#include "caf/fwd.hpp"
#include "caf/logger.hpp"
#include "caf/actor_cast.hpp"
#include "caf/make_actor.hpp"
#include "caf/infer_handle.hpp"
#include "caf/actor_config.hpp"
#include "caf/make_counted.hpp"
#include "caf/spawn_options.hpp"
#include "caf/group_manager.hpp"
#include "caf/abstract_actor.hpp"
......@@ -412,12 +413,14 @@ private:
cfg.flags |= abstract_actor::is_detached_flag;
if (! cfg.host)
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_LOG_DEBUG("spawned actor:" << CAF_ARG(ptr->id()));
CAF_PUSH_AID(ptr->id());
CAF_LOG_DEBUG("spawned actor:" << CAF_ARG(res.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));
return ptr;
return res;
}
std::atomic<size_t> ids_;
......
......@@ -33,7 +33,6 @@
#include "caf/extend.hpp"
#include "caf/logger.hpp"
#include "caf/result.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp"
#include "caf/node_id.hpp"
#include "caf/anything.hpp"
......
......@@ -31,6 +31,7 @@
#include "caf/local_actor.hpp"
#include "caf/typed_actor.hpp"
#include "caf/actor_config.hpp"
#include "caf/actor_marker.hpp"
#include "caf/mailbox_element.hpp"
#include "caf/response_handle.hpp"
......@@ -45,7 +46,8 @@ namespace caf {
/// @extends local_actor
class 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:
using behavior_type = behavior;
......
......@@ -20,6 +20,7 @@
#ifndef CAF_CHECK_TYPED_INPUT_HPP
#define CAF_CHECK_TYPED_INPUT_HPP
#include "caf/fwd.hpp"
#include "caf/typed_actor.hpp"
#include "caf/detail/type_list.hpp"
......@@ -27,8 +28,8 @@
namespace caf {
/// Checks whether `R` does support an input of type `{Ts...}` via a
/// static assertion (always returns 0).
/// Checks whether `R` does support an input of type `{Ts...}`
/// via static assertion.
template <class... Sigs, class... Ts>
void check_typed_input(const typed_actor<Sigs...>&,
const detail::type_list<Ts...>&) {
......@@ -45,6 +46,16 @@ void check_typed_input(const typed_actor<Sigs...>&,
"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
#endif // CAF_CHECK_TYPED_INPUT_HPP
......@@ -23,6 +23,9 @@
// this header must be generated by the build system (may be empty)
#include "caf/detail/build_config.hpp"
// Platform-specific adjustments.
#define CAF_CACHE_LINE_SIZE 64
// Config pararameters defined by the build system (usually CMake):
//
// CAF_ENABLE_RUNTIME_CHECKS:
......
......@@ -20,8 +20,8 @@
#ifndef CAF_DECORATOR_ADAPTER_HPP
#define CAF_DECORATOR_ADAPTER_HPP
#include "caf/actor.hpp"
#include "caf/message.hpp"
#include "caf/actor_addr.hpp"
#include "caf/attachable.hpp"
#include "caf/monitorable_actor.hpp"
......@@ -36,7 +36,7 @@ namespace decorator {
/// the same actor system and node as decorated actors.
class adapter : public monitorable_actor {
public:
adapter(actor_addr decorated, message msg);
adapter(strong_actor_ptr decorated, message msg);
// non-system messages are processed and then forwarded;
// system messages are handled and consumed on the spot;
......@@ -44,7 +44,7 @@ public:
void enqueue(mailbox_element_ptr what, execution_unit* host) override;
private:
actor_addr decorated_;
strong_actor_ptr decorated_;
message merger_;
};
......
......@@ -38,7 +38,8 @@ class sequencer : public monitorable_actor {
public:
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;
// system messages are handled and consumed on the spot;
......@@ -48,8 +49,8 @@ public:
message_types_set message_types() const override;
private:
actor_addr f_;
actor_addr g_;
strong_actor_ptr f_;
strong_actor_ptr g_;
message_types_set msg_types_;
};
......
......@@ -40,7 +40,7 @@ class splitter : public monitorable_actor {
public:
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;
// system messages are handled and consumed on the spot;
......@@ -50,7 +50,7 @@ public:
message_types_set message_types() const override;
private:
std::vector<actor_addr> workers_;
std::vector<strong_actor_ptr> workers_;
message_types_set msg_types_;
};
......
......@@ -22,8 +22,6 @@
#include "caf/config.hpp"
#define CAF_CACHE_LINE_SIZE 64
#include <chrono>
#include <thread>
#include <atomic>
......
......@@ -103,7 +103,7 @@ public:
const std::vector<actor>& workers,
mailbox_element_ptr& ptr,
execution_unit* host) {
if (ptr->sender == invalid_actor_addr)
if (! ptr->sender)
return;
actor_msg_vec xs(workers.size());
for (size_t i = 0; i < workers.size(); ++i)
......
......@@ -22,6 +22,7 @@
#include <cstdint>
#include "caf/fwd.hpp"
#include "caf/exit_reason.hpp"
namespace caf {
......@@ -39,7 +40,7 @@ namespace detail {
struct sync_request_bouncer {
exit_reason rsn;
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;
};
......
......@@ -44,7 +44,6 @@ using sorted_builtin_types =
actor_addr, // @addr
std::vector<actor_addr>, // @addrvec
atom_value, // @atom
channel, // @channel
std::vector<char>, // @charbuf
down_msg, // @down
duration, // @duration
......@@ -62,6 +61,7 @@ using sorted_builtin_types =
node_id, // @node
std::string, // @str
strmap, // @strmap
strong_actor_ptr, // @strong_actor_ptr
std::set<std::string>, // @strset
std::vector<std::string>, // @strvec
timeout_msg, // @timeout
......@@ -72,6 +72,7 @@ using sorted_builtin_types =
uint64_t, // @u64
uint8_t, // @u8
unit_t, // @unit
weak_actor_ptr, // @weak_actor_ptr
bool, // bool
double, // double
float // float
......
......@@ -120,7 +120,7 @@ struct is_builtin {
|| is_one_of<T, anything, std::string,
std::u16string, std::u32string,
atom_value, message, actor, group,
channel, node_id>::value;
node_id>::value;
};
/// Chekcs wheter `T` is primitive, i.e., either an arithmetic
......
......@@ -30,8 +30,9 @@ namespace caf {
/// Implements a simple proxy forwarding all operations to a manager.
class forwarding_actor_proxy : public actor_proxy {
public:
forwarding_actor_proxy(actor_system* sys, actor_id mid,
node_id pinfo, actor parent);
using forwarding_stack = std::vector<strong_actor_ptr>;
forwarding_actor_proxy(actor parent);
~forwarding_actor_proxy();
......@@ -50,8 +51,8 @@ public:
void manager(actor new_manager);
private:
void forward_msg(const actor_addr& sender, message_id mid, message msg,
const std::vector<actor_addr>* fwd_stack = nullptr);
void forward_msg(strong_actor_ptr sender, message_id mid, message msg,
const forwarding_stack* fwd_stack = nullptr);
mutable detail::shared_spinlock manager_mtx_;
actor manager_;
......
......@@ -25,15 +25,19 @@
namespace caf {
// templates
// 1-class templates
template <class> class maybe;
template <class> class optional;
template <class> class intrusive_ptr;
template <class> struct actor_cast_access;
template <class> class weak_intrusive_ptr;
template <class> class typed_continue_helper;
// 2-class templates
template <class, class, int> class actor_cast_access;
// variadic templates
template <class...> class delegated;
template <class...> class typed_actor;
template <class...> class typed_response_promise;
// classes
......@@ -41,7 +45,6 @@ class actor;
class group;
class error;
class message;
class channel;
class node_id;
class duration;
class behavior;
......@@ -69,6 +72,7 @@ class message_handler;
class response_promise;
class event_based_actor;
class binary_serializer;
class actor_control_block;
class binary_deserializer;
class actor_system_config;
class uniform_type_info_map;
......@@ -133,6 +137,8 @@ class dynamic_message_data;
} // 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>;
} // namespace caf
......
......@@ -31,9 +31,6 @@
namespace caf {
class channel;
class message;
struct invalid_group_t {
constexpr invalid_group_t() {}
};
......@@ -45,8 +42,8 @@ constexpr invalid_group_t invalid_group = invalid_group_t{};
class group : detail::comparable<group>,
detail::comparable<group, invalid_group_t> {
public:
template <class>
friend struct actor_cast_access;
template <class, class, int>
friend class actor_cast_access;
group() = default;
......@@ -95,11 +92,11 @@ public:
friend void serialize(deserializer& sink, group& x, const unsigned int);
private:
inline abstract_group* get() const noexcept {
return ptr_.get();
}
private:
inline abstract_group* release() noexcept {
return ptr_.release();
}
......
......@@ -25,7 +25,6 @@
#include <stdexcept>
#include <type_traits>
#include "caf/ref_counted.hpp"
#include "caf/detail/comparable.hpp"
namespace caf {
......@@ -43,6 +42,9 @@ public:
using reference = 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) {
// nop
}
......@@ -78,7 +80,8 @@ public:
/// count and sets this to `nullptr`.
pointer detach() noexcept {
auto result = ptr_;
ptr_ = nullptr;
if (result)
ptr_ = nullptr;
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 @@
#include "caf/extend.hpp"
#include "caf/logger.hpp"
#include "caf/message.hpp"
#include "caf/channel.hpp"
#include "caf/duration.hpp"
#include "caf/behavior.hpp"
#include "caf/delegated.hpp"
......@@ -92,7 +91,7 @@ public:
using mailbox_type = detail::single_reader_queue<mailbox_element,
detail::disposer>;
static constexpr auto memory_cache_flag = detail::needs_embedding;
//static constexpr auto memory_cache_flag = detail::needs_embedding;
~local_actor();
......@@ -159,19 +158,34 @@ public:
/// Sends `{xs...}` to `dest` using the priority `mp`.
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");
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)...);
}
/// Sends `{xs...}` to `dest` using normal priority.
template <class... Ts>
void send(const channel& dest, Ts&&... xs) {
send_impl(message_id::make(), actor_cast<abstract_channel*>(dest),
void send(const actor& dest, Ts&&... xs) {
send_impl(message_id::make(), actor_cast<abstract_actor*>(dest),
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`.
template <class... Sigs, class... Ts>
void send(message_priority mp, const typed_actor<Sigs...>& dest, Ts&&... xs) {
......@@ -200,6 +214,12 @@ public:
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`.
void send_exit(const actor_addr& dest, exit_reason reason);
......@@ -212,7 +232,7 @@ public:
/// Sends a message to `dest` that is delayed by `rel_time`
/// using the priority `mp`.
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) {
delayed_send_impl(message_id::make(mp), dest, rtime,
make_message(std::forward<Ts>(xs)...));
......@@ -220,9 +240,9 @@ public:
/// Sends a message to `dest` that is delayed by `rel_time`.
template <class... Ts>
void delayed_send(const channel& dest, const duration& rtime, Ts&&... xs) {
delayed_send_impl(message_id::make(), dest, rtime,
make_message(std::forward<Ts>(xs)...));
void delayed_send(const actor& dest, const duration& rtime, Ts&&... xs) {
delayed_send_impl(message_id::make(), actor_cast<strong_actor_ptr>(dest),
rtime, make_message(std::forward<Ts>(xs)...));
}
/// Sends `{xs...}` delayed by `rtime` to `dest` using the priority `mp`.
......@@ -236,7 +256,7 @@ public:
>::type...>;
token 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)...));
}
......@@ -252,10 +272,17 @@ public:
>::type...>;
token 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)...));
}
/// 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 *
****************************************************************************/
......@@ -314,6 +341,7 @@ public:
}
/// @cond PRIVATE
/// Returns the currently processed message.
/// @warning Only set during callback invocation. Calling this member function
/// is undefined behavior (dereferencing a `nullptr`) when not in a
......@@ -321,29 +349,24 @@ public:
inline message& current_message() {
return current_element_->msg;
}
void monitor(abstract_actor* whom);
/// @endcond
/// Returns the address of the sender of the current message.
/// @warning Only set during callback invocation. Calling this member function
/// is undefined behavior (dereferencing a `nullptr`) when not in a
/// callback or `forward_to` has been called previously.
inline actor_addr& current_sender() {
return current_element_->sender;
inline actor_addr current_sender() {
return actor_cast<actor_addr>(current_element_->sender);
}
/// Adds a unidirectional `monitor` to `whom`.
/// @note Each call to `monitor` creates a new, independent monitor.
void monitor(const actor_addr& whom);
/// @copydoc monitor(const actor_addr&)
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());
template <class Handle>
void monitor(const Handle& whom) {
monitor(actor_cast<abstract_actor*>(whom));
}
/// Removes a monitor from `whom`.
......@@ -429,8 +452,6 @@ public:
subtype_t subtype() const override;
ref_counted* as_ref_counted_ptr() override;
resume_result resume(execution_unit*, size_t) override;
/****************************************************************************
......@@ -446,11 +467,15 @@ public:
// 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);
local_actor();
local_actor(int init_flags);
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>
inline ActorHandle eval_opts(spawn_options opts, ActorHandle res) {
......@@ -689,18 +714,6 @@ protected:
/// @endcond
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>
typename std::enable_if<
! std::is_same<typename std::decay<T>::type, message>::value
......@@ -708,8 +721,7 @@ private:
send_impl(message_id mid, abstract_actor* dest, T&& x, Ts&&... xs) const {
if (! dest)
return;
dest->enqueue(mailbox_element::make_joint(address(),
mid, {},
dest->enqueue(mailbox_element::make_joint(ctrl(), mid, {},
std::forward<T>(x),
std::forward<Ts>(xs)...),
context());
......@@ -717,7 +729,7 @@ private:
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);
};
......
......@@ -22,9 +22,9 @@
#include <cstddef>
#include "caf/actor.hpp"
#include "caf/extend.hpp"
#include "caf/message.hpp"
#include "caf/actor_addr.hpp"
#include "caf/message_id.hpp"
#include "caf/ref_counted.hpp"
......@@ -42,7 +42,7 @@ class mailbox_element : public memory_managed {
public:
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
mailbox_element* next;
......@@ -51,7 +51,7 @@ public:
// avoid multi-processing in blocking actors via flagging
bool marked;
// 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
message_id mid;
// stages.back() is the next actor in the forwarding chain,
......@@ -61,8 +61,11 @@ public:
message msg;
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);
~mailbox_element();
......@@ -74,11 +77,11 @@ public:
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);
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) {
using value_storage =
detail::tuple_vals<
......
......@@ -17,111 +17,27 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_CHANNEL_HPP
#define CAF_CHANNEL_HPP
#ifndef CAF_MAKE_ACTOR_HPP
#define CAF_MAKE_ACTOR_HPP
#include <cstddef>
#include <type_traits>
#include "caf/fwd.hpp"
#include "caf/ref_counted.hpp"
#include "caf/infer_handle.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/abstract_channel.hpp"
#include "caf/detail/comparable.hpp"
#include "caf/actor_storage.hpp"
#include "caf/actor_control_block.hpp"
namespace caf {
struct invalid_channel_t {
constexpr invalid_channel_t() {
// nop
}
};
/// 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);
template <class T, class R = infer_handle_from_class_t<T>, class... Ts>
R make_actor(actor_id aid, node_id nid, actor_system* sys, Ts&&... xs) {
auto ptr = new actor_storage<T>(aid, std::move(nid), sys,
std::forward<Ts>(xs)...);
return {&(ptr->ctrl), false};
}
} // namespace caf
#endif // CAF_CHANNEL_HPP
#endif // CAF_MAKE_ACTOR_HPP
......@@ -20,6 +20,8 @@
#ifndef CAF_MAKE_COUNTED_HPP
#define CAF_MAKE_COUNTED_HPP
#include <type_traits>
#include "caf/ref_counted.hpp"
#include "caf/intrusive_ptr.hpp"
......
......@@ -79,10 +79,7 @@ protected:
explicit monitorable_actor(actor_config& cfg);
/// Creates a new actor instance.
monitorable_actor(actor_system* sys, actor_id aid, node_id nid);
/// Creates a new actor instance.
monitorable_actor(actor_system* sys, actor_id aid, node_id nid, int flags);
explicit monitorable_actor(int flags);
/****************************************************************************
* here be dragons: end of public interface *
......
......@@ -26,6 +26,7 @@
#include "caf/fwd.hpp"
#include "caf/node_id.hpp"
#include "caf/actor_addr.hpp"
#include "caf/actor_cast.hpp"
#include "caf/actor_proxy.hpp"
#include "caf/exit_reason.hpp"
......@@ -44,7 +45,7 @@ public:
virtual ~backend();
/// 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;
};
......@@ -54,6 +55,8 @@ public:
proxy_registry(const proxy_registry&) = delete;
proxy_registry& operator=(const proxy_registry&) = delete;
~proxy_registry();
void serialize(serializer& sink, const actor_addr& addr) const;
void serialize(deserializer& source, actor_addr& addr);
......@@ -66,51 +69,21 @@ public:
/// addresses for remote actors on the fly if needed.
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.
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`.
size_t count_proxies(const key_type& node);
/// Returns all proxies for `node`.
std::vector<actor_proxy_ptr> get_all() const;
/// 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`.
strong_actor_ptr get(const key_type& node, actor_id aid);
/// Returns the proxy instance identified by `node` and `aid`
/// 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`.
void erase(const key_type& node);
......@@ -130,6 +103,8 @@ public:
}
private:
void kill_proxy(strong_actor_ptr&, exit_reason);
actor_system& system_;
backend& backend_;
std::unordered_map<node_id, proxy_map> proxies_;
......
......@@ -74,12 +74,12 @@ public:
/// @endcond
private:
using forwarding_stack = std::vector<actor_addr>;
using forwarding_stack = std::vector<strong_actor_ptr>;
void deliver_impl(message response_message);
local_actor* self_;
actor_addr source_;
strong_actor_ptr source_;
forwarding_stack stages_;
message_id id_;
};
......
......@@ -63,16 +63,15 @@ public:
/// delegate other subtypes to dedicated workers.
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
/// or needs to be re-scheduled later.
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
......
......@@ -27,7 +27,6 @@
#include "caf/fwd.hpp"
#include "caf/atom.hpp"
#include "caf/actor.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp"
#include "caf/duration.hpp"
#include "caf/actor_addr.hpp"
......@@ -53,12 +52,12 @@ public:
virtual void enqueue(resumable* what) = 0;
template <class Duration, class... Data>
void delayed_send(Duration rel_time, actor_addr from, channel to,
message_id mid, message data) {
timer_->enqueue(invalid_actor_addr, invalid_message_id,
make_message(duration{rel_time}, std::move(from),
std::move(to), mid, std::move(data)),
nullptr);
void delayed_send(Duration rel_time, strong_actor_ptr from,
strong_actor_ptr to, message_id mid, message data) {
timer_->enqueue(nullptr, invalid_message_id,
make_message(duration{rel_time}, std::move(from),
std::move(to), mid, std::move(data)),
nullptr);
}
inline actor_system& system() {
......
......@@ -82,8 +82,12 @@ protected:
cv.notify_all();
return resumable::shutdown_execution_unit;
}
ref_counted* as_ref_counted_ptr() override {
return this;
void intrusive_ptr_add_ref_impl() override {
intrusive_ptr_add_ref(this);
}
void intrusive_ptr_release_impl() override {
intrusive_ptr_release(this);
}
shutdown_helper() : last_worker(nullptr) {
// nop
......
......@@ -20,7 +20,9 @@
#ifndef CAF_SCOPED_ACTOR_HPP
#define CAF_SCOPED_ACTOR_HPP
#include "caf/actor_cast.hpp"
#include "caf/actor_system.hpp"
#include "caf/actor_storage.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/blocking_actor.hpp"
#include "caf/scoped_execution_unit.hpp"
......@@ -30,6 +32,13 @@ namespace caf {
/// A scoped handle to a blocking actor.
class scoped_actor {
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(actor_system& sys, bool hide_actor = false);
......@@ -40,25 +49,28 @@ public:
~scoped_actor();
inline blocking_actor* operator->() const {
return self_.get();
return ptr();
}
inline blocking_actor& operator*() const {
return *self_;
}
inline blocking_actor* get() const {
return self_.get();
return *ptr();
}
inline actor_addr address() const {
return self_->address();
return ptr()->address();
}
blocking_actor* ptr() const;
private:
inline actor_control_block* get() const {
return self_.get();
}
actor_id prev_; // used for logging/debugging purposes only
scoped_execution_unit context_;
intrusive_ptr<blocking_actor> self_;
strong_actor_ptr self_;
};
std::string to_string(const scoped_actor& x);
......
......@@ -21,40 +21,22 @@
#define CAF_SEND_HPP
#include "caf/actor.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp"
#include "caf/actor_cast.hpp"
#include "caf/actor_addr.hpp"
#include "caf/message_id.hpp"
#include "caf/message_priority.hpp"
#include "caf/typed_actor.hpp"
#include "caf/is_message_sink.hpp"
#include "caf/message_priority.hpp"
#include "caf/system_messages.hpp"
#include "caf/check_typed_input.hpp"
namespace caf {
/// Sends `to` a message under the identity of `from` with priority `prio`.
template <class... Ts>
void send_as(const actor& from, message_priority prio,
const channel& 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) {
template <class Dest, class... Ts>
typename std::enable_if<is_message_sink<Dest>::value>::type
send_as(actor from, message_priority prio, const Dest& to, Ts&&... xs) {
using token =
detail::type_list<
typename detail::implicit_conversions<
......@@ -62,76 +44,48 @@ void send_as(const actor& from, message_priority prio,
>::type...>;
token 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`.
template <class... Sigs, class... Ts>
void send_as(const actor& from, 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);
send_as(from, message_priority::normal,
actor_cast<channel>(to), std::forward<Ts>(xs)...);
template <class Dest, class... Ts>
typename std::enable_if<is_message_sink<Dest>::value>::type
send_as(actor from, const Dest& to, Ts&&... xs) {
send_as(std::move(from), message_priority::normal,
to, std::forward<Ts>(xs)...);
}
/// Anonymously sends `to` a message with priority `prio`.
template <class... Ts>
void anon_send(message_priority prio, const channel& to, Ts&&... xs) {
template <class Dest, class... Ts>
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)...);
}
/// Anonymously sends `to` a message.
template <class... Ts>
void anon_send(const channel& to, Ts&&... xs) {
template <class Dest, class... Ts>
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)...);
}
/// 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.
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)
return;
auto ptr = actor_cast<actor>(to);
ptr->enqueue(invalid_actor_addr, message_id{}.with_high_priority(),
make_message(exit_msg{invalid_actor_addr, reason}), nullptr);
to->enqueue(nullptr, message_id{}.with_high_priority(),
make_message(exit_msg{invalid_actor_addr, reason}), nullptr);
}
/// Anonymously sends `to` an exit message.
template <class ActorHandle>
void anon_send_exit(const ActorHandle& to, exit_reason reason) {
anon_send_exit(to.address(), reason);
inline void anon_send_exit(const actor_addr& to, exit_reason reason) {
anon_send_exit(actor_cast<actor>(to), reason);
}
} // namespace caf
......
......@@ -23,8 +23,10 @@
#include "caf/intrusive_ptr.hpp"
#include "caf/actor.hpp"
#include "caf/make_actor.hpp"
#include "caf/actor_cast.hpp"
#include "caf/replies_to.hpp"
#include "caf/actor_system.hpp"
#include "caf/abstract_actor.hpp"
#include "caf/stateful_actor.hpp"
#include "caf/typed_behavior.hpp"
......@@ -56,6 +58,7 @@ class typed_broker;
template <class... Sigs>
class typed_actor : detail::comparable<typed_actor<Sigs...>>,
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_addr_t> {
......@@ -70,8 +73,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
friend class typed_actor;
// allow conversion via actor_cast
template <class>
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 = false;
/// Creates a new `typed_actor` type by extending this one with `Es...`.
template <class... Es>
......@@ -143,7 +149,7 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
detail::tlf_is_subset(signatures(),
typename TypedActor::signatures())
>::type>
typed_actor(TypedActor* ptr) : ptr_(ptr) {
typed_actor(TypedActor* ptr) : ptr_(ptr->ctrl()) {
// nop
}
......@@ -176,10 +182,9 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
ptr_.reset();
}
/// Queries the address of the stored actor.
actor_addr address() const noexcept {
return ptr_ ? ptr_->address() : actor_addr();
return {ptr_.get(), true};
}
/// Returns `*this != invalid_actor`.
......@@ -216,19 +221,20 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
bind(Ts&&... xs) const {
if (! ptr_)
return invalid_actor;
auto ptr = make_counted<decorator::adapter>(ptr_->address(),
make_message(xs...));
auto& sys = *(ptr_->home_system);
auto ptr = make_actor<decorator::adapter, strong_actor_ptr>(
sys.next_actor_id(), sys.node(), &sys, ptr_, make_message(xs...));
return {ptr.release(), false};
}
/// @cond PRIVATE
abstract_actor* operator->() const noexcept {
return ptr_.get();
return ptr_->get();
}
abstract_actor& operator*() const noexcept {
return *ptr_.get();
return *ptr_->get();
}
intptr_t compare(const typed_actor& x) const noexcept {
......@@ -236,7 +242,11 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
}
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 {
......@@ -247,34 +257,43 @@ class typed_actor : detail::comparable<typed_actor<Sigs...>>,
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
private:
abstract_actor* get() const noexcept {
actor_control_block* get() const noexcept {
return ptr_.get();
}
abstract_actor* release() noexcept {
actor_control_block* release() noexcept {
return ptr_.release();
}
typed_actor(abstract_actor* ptr) : ptr_(ptr) {
typed_actor(actor_control_block* ptr) : ptr_(ptr) {
// nop
}
typed_actor(abstract_actor* ptr, bool add_ref) : ptr_(ptr, add_ref) {
// nop
}
abstract_actor_ptr ptr_;
strong_actor_ptr ptr_;
};
/// @relates typed_actor
template <class... Xs, class... Ys>
bool operator==(const typed_actor<Xs...>& x,
const typed_actor<Ys...>& y) noexcept {
return actor_addr::compare(actor_cast<abstract_actor*>(x),
actor_cast<abstract_actor*>(y)) == 0;
return actor_addr::compare(actor_cast<actor_control_block*>(x),
actor_cast<actor_control_block*>(y)) == 0;
}
/// @relates typed_actor
......@@ -301,10 +320,12 @@ operator*(typed_actor<Xs...> f, typed_actor<Ys...> g) {
>::type;
if (! f || ! g)
return invalid_actor;
auto mts = g->home_system().message_types(result{});
auto ptr = make_counted<decorator::sequencer>(f.address(), g.address(),
std::move(mts));
return actor_cast<result>(std::move(ptr));
auto& sys = g->home_system();
auto mts = sys.message_types(result{});
return make_actor<decorator::sequencer, result>(
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>
......@@ -320,30 +341,17 @@ splice(const typed_actor<Xs...>& x, const Ts&... xs) {
detail::type_list<Xs...>,
typename Ts::signatures...
>::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)
if (! addr)
return invalid_actor;
auto mts = x->home_system().message_types(result{});
auto ptr = make_counted<decorator::splitter>(std::move(tmp), std::move(mts));
return actor_cast<result>(std::move(ptr));
}
/// @relates typed_actor
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);
auto& sys = x->home_system();
auto mts = sys.message_types(result{});
return make_actor<decorator::splitter, result>(sys.next_actor_id(),
sys.node(), &sys,
std::move(tmp),
std::move(mts));
}
} // namespace caf
......
......@@ -51,7 +51,7 @@ public:
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&)>;
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 @@
#include "caf/mailbox_element.hpp"
#include "caf/system_messages.hpp"
#include "caf/default_attachable.hpp"
#include "caf/actor_control_block.hpp"
#include "caf/detail/shared_spinlock.hpp"
......@@ -45,29 +46,30 @@ namespace caf {
// exit_reason_ is guaranteed to be set to 0, i.e., exit_reason::not_exited,
// 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) {
enqueue(mailbox_element::make(sender, mid, {}, std::move(msg)), host);
}
abstract_actor::abstract_actor(actor_config& cfg)
: abstract_channel(cfg.flags | abstract_channel::is_abstract_actor_flag,
cfg.host->system().node()),
id_(cfg.host->system().next_actor_id()),
home_system_(&cfg.host->system()) {
: abstract_channel(cfg.flags) {
// nop
}
abstract_actor::abstract_actor(actor_system* sys, actor_id aid,
node_id nid, int flags)
: abstract_channel(flags, std::move(nid)),
id_(aid),
home_system_(sys) {
abstract_actor::abstract_actor(int flags) : abstract_channel(flags) {
// nop
}
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 {
......@@ -75,13 +77,25 @@ std::set<std::string> abstract_actor::message_types() const {
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) {
if (is_registered() == value)
return;
if (value)
home_system_->registry().inc_running();
home_system().registry().inc_running();
else
home_system_->registry().dec_running();
home_system().registry().dec_running();
set_flag(value, is_registered_flag);
}
......
......@@ -24,9 +24,7 @@
namespace caf {
abstract_channel::abstract_channel(int fs, node_id nid)
: flags_(fs),
node_(std::move(nid)) {
abstract_channel::abstract_channel(int fs) : flags_(fs) {
// nop
}
......
......@@ -55,8 +55,8 @@ namespace {
using hrc = std::chrono::high_resolution_clock;
struct delayed_msg {
actor_addr from;
channel to;
strong_actor_ptr from;
strong_actor_ptr to;
message_id mid;
message msg;
};
......@@ -106,7 +106,7 @@ public:
std::multimap<hrc::time_point, delayed_msg> messages;
// message handling rules
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) {
insert_dmsg(messages, d, std::move(from),
std::move(to), mid, std::move(msg));
......
......@@ -44,10 +44,11 @@ const std::string& abstract_group::module::name() const {
abstract_group::abstract_group(actor_system& sys,
abstract_group::module_ptr mod,
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),
module_(mod),
identifier_(std::move(id)) {
identifier_(std::move(id)),
origin_(nid) {
// nop
}
......
......@@ -17,12 +17,12 @@
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include "caf/channel.hpp"
#include "caf/actor.hpp"
#include <utility>
#include "caf/actor.hpp"
#include "caf/actor_addr.hpp"
#include "caf/make_actor.hpp"
#include "caf/serializer.hpp"
#include "caf/actor_proxy.hpp"
#include "caf/local_actor.hpp"
......@@ -37,7 +37,7 @@
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
}
......@@ -45,16 +45,16 @@ actor::actor(const invalid_actor_t&) : ptr_(nullptr) {
// nop
}
actor::actor(abstract_actor* ptr) : ptr_(ptr) {
actor::actor(actor_control_block* ptr) : ptr_(ptr) {
// 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
}
actor& actor::operator=(const scoped_actor& x) {
ptr_.reset(x.get());
ptr_ = actor_cast<strong_actor_ptr>(x);
return *this;
}
......@@ -76,7 +76,7 @@ void actor::swap(actor& other) 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 {
......@@ -90,45 +90,54 @@ actor_id actor::id() const noexcept {
actor actor::bind_impl(message msg) const {
if (! ptr_)
return invalid_actor;
return actor_cast<actor>(make_counted<decorator::adapter>(address(),
std::move(msg)));
auto& sys = *(ptr_->home_system);
return make_actor<decorator::adapter, actor>(sys.next_actor_id(), sys.node(),
&sys, ptr_, std::move(msg));
}
actor operator*(actor f, actor g) {
if (! f || ! g)
return invalid_actor;
auto ptr = make_counted<decorator::sequencer>(f.address(),
g.address(),
auto& sys = f->home_system();
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>{});
return actor_cast<actor>(std::move(ptr));
}
void serialize(serializer& sink, actor& x, const unsigned int) {
sink << x.address();
bool operator==(const actor& lhs, abstract_actor* rhs) {
return actor_cast<abstract_actor*>(lhs) == rhs;
}
void serialize(deserializer& source, actor& x, const unsigned int) {
actor_addr addr;
source >> addr;
x = actor_cast<actor>(addr);
bool operator==(abstract_actor* lhs, const actor& rhs) {
return rhs == lhs;
}
std::string to_string(const actor& x) {
return to_string(x.address());
bool operator!=(const actor& lhs, abstract_actor* rhs) {
return !(lhs == rhs);
}
actor actor::splice_impl(std::initializer_list<actor> xs) {
if (xs.size() < 2)
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));
bool operator!=(abstract_actor* lhs, const actor& rhs) {
return !(lhs == rhs);
}
} // namespace caf
......@@ -32,11 +32,12 @@ actor_addr::actor_addr(const invalid_actor_addr_t&) : ptr_(nullptr) {
// nop
}
actor_addr::actor_addr(abstract_actor* ptr) : ptr_(ptr) {
actor_addr::actor_addr(actor_control_block* ptr) : ptr_(ptr) {
// 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
}
......@@ -45,8 +46,8 @@ actor_addr actor_addr::operator=(const invalid_actor_addr_t&) {
return *this;
}
intptr_t actor_addr::compare(const abstract_actor* lhs,
const abstract_actor* rhs) {
intptr_t actor_addr::compare(const actor_control_block* lhs,
const actor_control_block* rhs) {
// invalid actors are always "less" than valid actors
if (! lhs)
return rhs ? -1 : 0;
......@@ -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 {
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 {
return (ptr_) ? ptr_->id() : 0;
......@@ -80,33 +84,12 @@ node_id actor_addr::node() const noexcept {
return ptr_ ? ptr_->node() : node_id{};
}
void actor_addr::swap(actor_addr& other) noexcept {
ptr_.swap(other.ptr_);
actor_system* actor_addr::home_system() const noexcept {
return ptr_ ? ptr_->home_system : nullptr;
}
void serialize(serializer& sink, actor_addr& x, const unsigned int) {
sink << actor_cast<channel>(x);
}
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;
void actor_addr::swap(actor_addr& other) noexcept {
ptr_.swap(other.ptr_);
}
} // namespace caf
......@@ -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,
message content, execution_unit* eu) {
void actor_companion::enqueue(strong_actor_ptr sender, message_id mid, message content,
execution_unit* eu) {
using detail::memory;
auto ptr = mailbox_element::make(sender, mid, {}, std::move(content));
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 @@
namespace caf {
actor_ostream::actor_ostream(abstract_actor* self)
: self_(self),
actor_ostream::actor_ostream(local_actor* 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()) {
// nop
}
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;
}
actor_ostream& actor_ostream::flush() {
send_as(actor_cast<actor>(self_), printer_, flush_atom::value);
send_as(self_, printer_, flush_atom::value);
return *this;
}
void actor_ostream::redirect(abstract_actor* self, std::string fn, int flags) {
if (! self)
return;
intrusive_ptr<abstract_actor> ptr{self};
send_as(actor_cast<actor>(ptr), self->home_system().scheduler().printer(),
send_as(actor_cast<actor>(self), self->home_system().scheduler().printer(),
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) {
redirect_atom::value, std::move(fn), flags);
}
actor_ostream aout(abstract_actor* self) {
actor_ostream aout(local_actor* self) {
return actor_ostream{self};
}
actor_ostream aout(scoped_actor& self) {
return actor_ostream{self.get()};
return actor_ostream{self};
}
} // namespace caf
......
......@@ -55,9 +55,8 @@ void broadcast_dispatch(actor_system&, actor_pool::uplock&,
const actor_pool::actor_vec& vec,
mailbox_element_ptr& ptr, execution_unit* host) {
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.front()->enqueue(std::move(ptr), host);
}
......@@ -96,11 +95,19 @@ actor_pool::~actor_pool() {
actor actor_pool::make(execution_unit* eu, policy pol) {
CAF_ASSERT(eu);
intrusive_ptr<actor_pool> ptr;
auto& sys = eu->system();
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->policy_ = std::move(pol);
return actor_cast<actor>(ptr);
*/
}
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;
}
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) {
upgrade_lock<detail::shared_spinlock> guard{workers_mtx_};
if (filter(guard, sender, mid, content, eu))
......@@ -139,7 +146,7 @@ actor_pool::actor_pool(actor_config& cfg)
}
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) {
auto rsn = planned_reason_;
if (rsn != caf::exit_reason::not_exited) {
......@@ -203,19 +210,16 @@ bool actor_pool::filter(upgrade_lock<detail::shared_spinlock>& guard,
if (msg.match_elements<sys_atom, get_atom>()) {
auto cpy = workers_;
guard.unlock();
actor_cast<abstract_actor*>(sender)->enqueue(invalid_actor_addr,
mid.response_id(),
make_message(std::move(cpy)),
eu);
sender->enqueue(nullptr, mid.response_id(),
make_message(std::move(cpy)), eu);
return true;
}
if (workers_.empty()) {
guard.unlock();
if (sender != invalid_actor_addr && mid.valid()) {
if (sender && mid.valid()) {
// tell client we have ignored this sync message by sending
// and empty message back
auto ptr = actor_cast<abstract_actor_ptr>(sender);
ptr->enqueue(invalid_actor_addr, mid.response_id(), message{}, eu);
sender->enqueue(nullptr, mid.response_id(), message{}, eu);
}
return true;
}
......
......@@ -28,59 +28,13 @@
namespace caf {
actor_proxy::anchor::anchor(actor_proxy* instance) : ptr_(instance) {
actor_proxy::actor_proxy()
: monitorable_actor(abstract_channel::is_abstract_actor()) {
// 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() {
// 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
......@@ -65,16 +65,20 @@ actor_registry::id_entry actor_registry::get(actor_id key) const {
if (i != entries_.end())
return i->second;
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) {
if (val == nullptr)
void actor_registry::put(actor_id key, actor_control_block* val) {
if (! val)
return;
auto strong_val = actor_cast<actor>(val);
if (! strong_val)
return;
{ // lifetime scope of guard
exclusive_guard guard(instances_mtx_);
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
return;
}
......@@ -82,18 +86,22 @@ void actor_registry::put(actor_id key, const actor_addr& val) {
// attach functor without lock
CAF_LOG_INFO("added actor:" << CAF_ARG(key));
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);
});
}
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) {
exclusive_guard guard(instances_mtx_);
auto i = entries_.find(key);
if (i != entries_.end()) {
auto& entry = i->second;
CAF_LOG_INFO("erased actor:" << CAF_ARG(key) << CAF_ARG(reason));
entry.first = invalid_actor_addr;
entry.first = nullptr;
entry.second = reason;
}
}
......@@ -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_};
auto i = named_entries_.find(key);
if (i == named_entries_.end())
return invalid_actor;
return nullptr;
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)
value->attach_functor([=] {
system_.registry().put(key, invalid_actor);
value->get()->attach_functor([=] {
system_.registry().put(key, nullptr);
});
exclusive_guard guard{named_entries_mtx_};
named_entries_.emplace(key, std::move(value));
......@@ -257,11 +265,11 @@ void actor_registry::start() {
CAF_LOG_TRACE("");
return {
[=](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));
actor_config cfg{self->context()};
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 {ok_atom::value, res.first, res.second};
},
......@@ -277,11 +285,9 @@ void actor_registry::start() {
// use the lazy_init flag
//named_entries_.emplace(atom("SpawnServ"), system_.spawn_announce_actor_type_server());
auto cs = system_.spawn<hidden+lazy_init>(kvstore);
put(atom("ConfigServ"), cs);
named_entries_.emplace(atom("ConfigServ"), std::move(cs));
put(atom("ConfigServ"), actor_cast<strong_actor_ptr>(std::move(cs)));
auto ss = system_.spawn<hidden+lazy_init>(spawn_serv);
put(atom("SpawnServ"), ss);
named_entries_.emplace(atom("SpawnServ"), std::move(ss));
put(atom("SpawnServ"), actor_cast<strong_actor_ptr>(std::move(ss)));
}
void actor_registry::stop() {
......@@ -298,7 +304,7 @@ void actor_registry::stop() {
// the scheduler is already stopped -> invoke exit messages manually
dropping_execution_unit dummy{&system_};
for (auto& kvp : named_entries_) {
auto mp = mailbox_element::make_joint(invalid_actor_addr,
auto mp = mailbox_element::make_joint(nullptr,
invalid_message_id,
{},
exit_msg{invalid_actor_addr,
......
......@@ -132,7 +132,7 @@ actor_system::actor_system(actor_system_config&& cfg)
if (mod)
mod->start();
// 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",
make_message(cfg.middleman_enable_automatic_connections));
}
......
......@@ -33,18 +33,15 @@
namespace caf {
namespace decorator {
adapter::adapter(actor_addr decorated, message msg)
: monitorable_actor(&decorated->home_system(),
decorated->home_system().next_actor_id(),
decorated->node(),
is_abstract_actor_flag
| is_actor_bind_decorator_flag),
adapter::adapter(strong_actor_ptr decorated, message msg)
: monitorable_actor(is_abstract_actor_flag | is_actor_bind_decorator_flag),
decorated_(std::move(decorated)),
merger_(std::move(msg)) {
// bound actor has dependency on the decorated actor by default;
// if the decorated actor is already dead upon establishing the
// 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) {
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| 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 @@
#include "caf/default_attachable.hpp"
#include "caf/actor.hpp"
#include "caf/message.hpp"
#include "caf/actor_cast.hpp"
#include "caf/system_messages.hpp"
......@@ -37,15 +38,17 @@ message make(abstract_actor* self, exit_reason reason) {
void default_attachable::actor_exited(exit_reason rsn, execution_unit* host) {
CAF_ASSERT(observed_ != observer_);
auto factory = type_ == monitor ? &make<down_msg> : &make<exit_msg>;
auto ptr = actor_cast<abstract_actor_ptr>(observer_);
ptr->enqueue(observed_, message_id{}.with_high_priority(),
factory(actor_cast<abstract_actor*>(observed_), rsn), host);
auto observer = actor_cast<strong_actor_ptr>(observer_);
auto observed = actor_cast<strong_actor_ptr>(observed_);
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) {
if (what.subtype != attachable::token::observer) {
if (what.subtype != attachable::token::observer)
return false;
}
auto& ot = *reinterpret_cast<const observe_token*>(what.ptr);
return ot.observer == observer_ && ot.type == type_;
}
......
......@@ -26,13 +26,8 @@
namespace caf {
forwarding_actor_proxy::forwarding_actor_proxy(actor_system* sys, actor_id aid,
node_id nid, actor mgr)
: actor_proxy(sys, aid, nid),
manager_(mgr) {
forwarding_actor_proxy::forwarding_actor_proxy(actor mgr) : manager_(mgr) {
CAF_ASSERT(mgr != invalid_actor);
CAF_PUSH_AID(0);
CAF_LOG_INFO(CAF_ARG(aid) << CAF_ARG(nid));
}
forwarding_actor_proxy::~forwarding_actor_proxy() {
......@@ -53,17 +48,18 @@ void forwarding_actor_proxy::manager(actor 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,
const std::vector<actor_addr>* fwd) {
const forwarding_stack* fwd) {
CAF_LOG_TRACE(CAF_ARG(id()) << CAF_ARG(sender)
<< CAF_ARG(mid) << CAF_ARG(msg));
std::vector<actor_addr> tmp;
forwarding_stack tmp;
shared_lock<detail::shared_spinlock> guard_(manager_mtx_);
if (manager_)
manager_->enqueue(invalid_actor_addr, invalid_message_id,
make_message(forward_atom::value, sender,
fwd ? *fwd : tmp, address(),
manager_->enqueue(nullptr, invalid_message_id,
make_message(forward_atom::value, std::move(sender),
fwd ? *fwd : tmp,
actor_cast<strong_actor_ptr>(this),
mid, std::move(msg)),
nullptr);
}
......@@ -73,7 +69,8 @@ void forwarding_actor_proxy::enqueue(mailbox_element_ptr what,
CAF_PUSH_AID(0);
if (! what)
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,
if (establish_link_impl(other)) {
// causes remote actor to link to (proxy of) 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));
return true;
}
......@@ -92,7 +89,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op,
case remove_link_op:
if (remove_link_impl(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));
return true;
}
......@@ -100,7 +97,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op,
case establish_backlink_op:
if (establish_backlink_impl(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));
return true;
}
......@@ -108,7 +105,7 @@ bool forwarding_actor_proxy::link_impl(linking_operation op,
case remove_backlink_op:
if (remove_backlink_impl(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));
return true;
}
......
......@@ -19,9 +19,9 @@
#include "caf/group.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp"
#include "caf/actor_cast.hpp"
#include "caf/actor_system.hpp"
#include "caf/group_manager.hpp"
namespace caf {
......@@ -56,19 +56,31 @@ intptr_t group::compare(const group& other) const noexcept {
}
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) {
channel y;
source >> y;
if (! y) {
std::string module_name;
source >> module_name;
if (module_name.empty()) {
x = invalid_group;
return;
}
if (! y->is_abstract_group())
throw std::logic_error("Expected an actor address, found a group address.");
x.ptr_.reset(static_cast<abstract_group*>(actor_cast<abstract_channel*>(y)));
if (source.context() == nullptr)
throw std::logic_error("Cannot serialize group without context.");
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) {
......
......@@ -69,47 +69,52 @@ void await_all_locals_down(actor_system& sys, std::initializer_list<actor> xs) {
class local_group : public abstract_group {
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) {
CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(msg));
shared_guard guard(mtx_);
for (auto& s : subscribers_) {
actor_cast<abstract_actor_ptr>(s)->enqueue(sender, invalid_message_id,
msg, host);
}
for (auto& s : subscribers_)
s->enqueue(sender, invalid_message_id, 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 {
CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(msg));
send_all_subscribers(sender, 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));
if (! who)
return {false, subscribers_.size()};
exclusive_guard guard(mtx_);
if (who && subscribers_.insert(who).second) {
return {true, subscribers_.size()};
}
return {false, subscribers_.size()};
auto res = subscribers_.emplace(std::move(who)).second;
return {res, 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
exclusive_guard guard(mtx_);
auto success = subscribers_.erase(who) > 0;
return {success, subscribers_.size()};
auto cmp = [](const strong_actor_ptr& lhs, const actor_control_block* rhs) {
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 {
CAF_LOG_TRACE(""); // serializing who would cause a deadlock
if (add_subscriber(who).first)
bool subscribe(strong_actor_ptr who) override {
CAF_LOG_TRACE(CAF_ARG(who));
if (add_subscriber(std::move(who)).first)
return true;
return false;
}
void unsubscribe(const actor_addr& who) override {
void unsubscribe(const actor_control_block* who) override {
CAF_LOG_TRACE(CAF_ARG(who));
erase_subscriber(who);
}
......@@ -133,7 +138,7 @@ public:
protected:
detail::shared_spinlock mtx_;
std::set<actor_addr> subscribers_;
std::set<strong_actor_ptr> subscribers_;
actor broker_;
};
......@@ -167,13 +172,17 @@ public:
},
[=](leave_atom, const actor& other) {
CAF_LOG_TRACE(CAF_ARG(other));
acquaintances_.erase(other);
// TODO
/*
if (other && acquaintances_.erase(other) > 0)
demonitor(other);
*/
},
[=](forward_atom, const message& what) {
CAF_LOG_TRACE(CAF_ARG(what));
// local forwarding
group_->send_all_subscribers(current_sender(), what, context());
group_->send_all_subscribers(current_element_->sender, what, context());
// forward to all acquaintances
send_to_acquaintances(what);
},
......@@ -199,7 +208,7 @@ public:
private:
void send_to_acquaintances(const message& what) {
// send to all remote subscribers
auto sender = current_sender();
auto sender = current_element_->sender;
CAF_LOG_DEBUG(CAF_ARG(acquaintances_.size())
<< CAF_ARG(sender) << CAF_ARG(what));
for (auto& acquaintance : acquaintances_)
......@@ -251,9 +260,9 @@ public:
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));
auto res = add_subscriber(who);
auto res = add_subscriber(std::move(who));
if (res.first) {
// join remote source
if (res.second == 1)
......@@ -264,7 +273,7 @@ public:
return false;
}
void unsubscribe(const actor_addr& who) override {
void unsubscribe(const actor_control_block* who) override {
CAF_LOG_TRACE(CAF_ARG(who));
auto res = erase_subscriber(who);
if (res.first && res.second == 0) {
......@@ -274,11 +283,11 @@ public:
}
}
void enqueue(const actor_addr& sender, message_id mid, message msg,
execution_unit* eu) override {
void enqueue(strong_actor_ptr sender, message_id mid,
message msg, execution_unit* eu) override {
CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(mid) << CAF_ARG(msg));
// forward message to the broker
broker_->enqueue(sender, mid,
broker_->enqueue(std::move(sender), mid,
make_message(forward_atom::value, std::move(msg)), eu);
}
......@@ -299,7 +308,7 @@ private:
[=](const down_msg& down) {
CAF_LOG_TRACE(CAF_ARG(down));
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->quit(down.reason);
}
......@@ -315,7 +324,7 @@ behavior proxy_broker::make_behavior() {
return {
others >> [=](const message& 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)
join(grp);
}
local_actor::local_actor(actor_system* sys, actor_id aid, node_id nid)
: monitorable_actor(sys, aid, std::move(nid)),
local_actor::local_actor()
: monitorable_actor(abstract_channel::is_abstract_actor_flag),
planned_exit_reason_(exit_reason::not_exited),
timeout_id_(0) {
// nop
}
local_actor::local_actor(actor_system* sys, actor_id aid,
node_id nid, int init_flags)
: monitorable_actor(sys, aid, std::move(nid), init_flags),
local_actor::local_actor(int init_flags)
: monitorable_actor(init_flags),
planned_exit_reason_(exit_reason::not_exited),
timeout_id_(0) {
// nop
......@@ -72,33 +71,42 @@ local_actor::~local_actor() {
cleanup(exit_reason::unreachable, nullptr);
}
void local_actor::monitor(const actor_addr& whom) {
if (whom == invalid_actor_addr)
void local_actor::intrusive_ptr_add_ref_impl() {
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;
auto ptr = actor_cast<abstract_actor_ptr>(whom);
ptr->attach(default_attachable::make_monitor(whom, address()));
ptr->attach(default_attachable::make_monitor(ptr->address(), address()));
}
void local_actor::demonitor(const actor_addr& whom) {
/*
if (whom == invalid_actor_addr)
return;
auto ptr = actor_cast<abstract_actor_ptr>(whom);
default_attachable::observe_token tk{address(), default_attachable::monitor};
ptr->detach(tk);
*/
}
void local_actor::join(const group& what) {
CAF_LOG_TRACE(CAF_ARG(what));
if (what == invalid_group)
return;
if (what->subscribe(address()))
if (what->subscribe(ctrl()))
subscriptions_.emplace(what);
}
void local_actor::leave(const group& what) {
CAF_LOG_TRACE(CAF_ARG(what));
if (subscriptions_.erase(what) > 0)
what->unsubscribe(address());
what->unsubscribe(ctrl());
}
void local_actor::on_exit() {
......@@ -140,9 +148,10 @@ uint32_t local_actor::request_timeout(const duration& d) {
CAF_LOG_TRACE("send new timeout_msg, " << CAF_ARG(timeout_id_));
if (d.is_zero()) {
// 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 {
delayed_send(this, d, std::move(msg));
delayed_send(actor_cast<actor>(this), d, std::move(msg));
}
return result;
}
......@@ -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));
if (! d.valid())
return;
delayed_send_impl(mid.response_id(), this, d,
delayed_send_impl(mid.response_id(), ctrl(), d,
make_message(sec::request_timeout));
}
......@@ -245,7 +254,6 @@ msg_type filter_msg(local_actor* self, mailbox_element& node) {
}
});
},
*/
[&](sys_atom, migrate_atom, std::vector<char>& buf) {
// "replace" this actor with the content of `buf`
if (! self->is_serializable()) {
......@@ -267,19 +275,22 @@ msg_type filter_msg(local_actor* self, mailbox_element& node) {
{}, ok_atom::value, self->address()),
self->context());
},
*/
[&](sys_atom, get_atom, std::string& what) {
CAF_LOG_TRACE(CAF_ARG(what));
if (what == "info") {
CAF_LOG_DEBUG("reply to 'info' message");
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),
self->address(), self->name()),
self->context());
return;
}
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),
self->context());
},
......@@ -603,7 +614,7 @@ void local_actor::launch(execution_unit* eu, bool lazy, bool hide) {
scheduler::inc_detached_threads();
//intrusive_ptr<local_actor> mself{this};
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);
// this extra scope makes sure that the trace logger is
// destructed before dec_detached_threads() is called
......@@ -612,15 +623,16 @@ void local_actor::launch(execution_unit* eu, bool lazy, bool hide) {
CAF_LOG_TRACE("");
scoped_execution_unit ctx{sys};
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
mself->await_data();
CAF_ASSERT(mself->mailbox().blocked() == false);
ptr->await_data();
CAF_ASSERT(ptr->mailbox().blocked() == false);
}
mself.reset();
}
scheduler::dec_detached_threads();
}, intrusive_ptr<local_actor>{this}}.detach();
}, strong_actor_ptr{ctrl()}}.detach();
return;
}
CAF_ASSERT(eu != nullptr);
......@@ -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
// it is waiting to get scheduled
ref();
intrusive_ptr_add_ref(ctrl());
eu->exec_later(this);
}
......@@ -658,11 +670,11 @@ void local_actor::enqueue(mailbox_element_ptr ptr, execution_unit* eu) {
switch (mailbox().enqueue(ptr.release())) {
case detail::enqueue_result::unblocked_reader: {
// add a reference count to this actor and re-schedule it
ref();
intrusive_ptr_add_ref(ctrl());
if (eu)
eu->exec_later(this);
else
home_system_->scheduler().enqueue(this);
home_system().scheduler().enqueue(this);
break;
}
case detail::enqueue_result::queue_closed: {
......@@ -682,10 +694,6 @@ resumable::subtype_t local_actor::subtype() const {
return scheduled_actor;
}
ref_counted* local_actor::as_ref_counted_ptr() {
return this;
}
resumable::resume_result local_actor::resume(execution_unit* eu,
size_t max_throughput) {
CAF_PUSH_AID(id());
......@@ -972,18 +980,17 @@ void local_actor::send_impl(message_id mid, abstract_channel* dest,
message what) const {
if (! dest)
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) {
send(message_priority::high, actor_cast<actor>(whom),
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) {
system().scheduler().delayed_send(rel_time, address(), dest,
system().scheduler().delayed_send(rel_time, ctrl(), std::move(dest),
mid, std::move(msg));
}
......@@ -1024,12 +1031,10 @@ void local_actor::cleanup(exit_reason reason, execution_unit* host) {
}
awaited_responses_.clear();
multiplexed_responses_.clear();
{ // lifetime scope of temporary
actor_addr me = address();
for (auto& subscription : subscriptions_)
subscription->unsubscribe(me);
subscriptions_.clear();
}
auto me = ctrl();
for (auto& subscription : subscriptions_)
subscription->unsubscribe(me);
subscriptions_.clear();
monitorable_actor::cleanup(reason, host);
// tell registry we're done
is_registered(false);
......
......@@ -28,7 +28,8 @@ mailbox_element::mailbox_element()
// 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),
prev(nullptr),
marked(false),
......@@ -38,7 +39,7 @@ mailbox_element::mailbox_element(actor_addr x, message_id y, forwarding_stack z)
// 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)
: next(nullptr),
prev(nullptr),
......@@ -54,7 +55,8 @@ mailbox_element::~mailbox_element() {
// 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,
message msg) {
auto ptr = detail::memory::create<mailbox_element>(std::move(sender), id,
......
......@@ -82,17 +82,8 @@ monitorable_actor::monitorable_actor(actor_config& cfg)
// nop
}
monitorable_actor::monitorable_actor(actor_system* sys,
actor_id aid,
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),
monitorable_actor::monitorable_actor(int init_flags)
: abstract_actor(init_flags),
exit_reason_(exit_reason::not_exited) {
// nop
}
......@@ -131,12 +122,14 @@ bool monitorable_actor::establish_link_impl(const actor_addr& other) {
CAF_LOG_TRACE(CAF_ARG(other));
if (other && other != this) {
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();
// send exit message if already exited
if (reason != exit_reason::not_exited) {
guard.unlock();
ptr->enqueue(address(), invalid_message_id,
ptr->enqueue(ctrl(), invalid_message_id,
make_message(exit_msg{address(), reason}), nullptr);
} else if (ptr->establish_backlink(address())) {
// add link if not already linked to other
......@@ -166,9 +159,10 @@ bool monitorable_actor::establish_backlink_impl(const actor_addr& other) {
}
// send exit message without lock
if (reason != exit_reason::not_exited) {
auto ptr = actor_cast<abstract_actor_ptr>(other);
ptr->enqueue(address(), invalid_message_id,
make_message(exit_msg{address(), reason}), nullptr);
auto hdl = actor_cast<actor>(other);
if (hdl)
hdl->enqueue(ctrl(), invalid_message_id,
make_message(exit_msg{address(), reason}), nullptr);
}
return false;
}
......@@ -180,11 +174,13 @@ bool monitorable_actor::remove_link_impl(const actor_addr& other) {
default_attachable::observe_token tk{other, default_attachable::link};
std::unique_lock<std::mutex> guard{mtx_};
// 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) {
guard.unlock();
// tell remote side to remove link as well
ptr->remove_backlink(address());
hdl->remove_backlink(address());
return true;
}
return false;
......@@ -243,7 +239,8 @@ bool monitorable_actor::handle_system_message(mailbox_element& node,
err = sec::invalid_sys_key;
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),
address(), name());
},
......@@ -252,10 +249,13 @@ bool monitorable_actor::handle_system_message(mailbox_element& node,
}
});
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));
if (res)
node.sender->enqueue(std::move(res), context);
if (res) {
auto s = actor_cast<actor>(node.sender);
if (s)
s->enqueue(std::move(res), context);
}
return true;
}
return false;
......
......@@ -36,115 +36,43 @@ proxy_registry::backend::~backend() {
// 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)
: system_(sys),
backend_(be) {
// nop
}
size_t proxy_registry::count_proxies(const key_type& node) {
auto i = proxies_.find(node);
return (i != proxies_.end()) ? i->second.size() : 0;
proxy_registry::~proxy_registry() {
clear();
}
std::vector<actor_proxy_ptr> proxy_registry::get_all() const {
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;
size_t proxy_registry::count_proxies(const key_type& node) {
auto i = proxies_.find(node);
if (i == proxies_.end())
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;
return (i != proxies_.end()) ? i->second.size() : 0;
}
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 i = submap.find(aid);
if (i != submap.end()) {
auto res = i->second->get();
if (! res) {
submap.erase(i); // instance is expired
}
return res;
}
if (i != submap.end())
return i->second;
return nullptr;
}
actor_proxy_ptr proxy_registry::get_or_put(const key_type& node, actor_id aid) {
CAF_LOG_TRACE(CAF_ARG(node) << CAF_ARG(aid));
auto& submap = proxies_[node];
auto& anchor = submap[aid];
actor_proxy_ptr result;
CAF_LOG_DEBUG_IF(! anchor, "found no anchor in submap");
if (anchor) {
result = anchor->get();
CAF_LOG_DEBUG_IF(result, "found valid anchor in submap");
CAF_LOG_DEBUG_IF(! result, "found expired anchor in submap");
}
// replace anchor if we've created one using the default ctor
// or if we've found an expired one in the map
if (! anchor || ! result) {
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");
strong_actor_ptr proxy_registry::get_or_put(const key_type& nid, actor_id aid) {
CAF_LOG_TRACE(CAF_ARG(nid) << CAF_ARG(aid));
auto& result = proxies_[nid][aid];
if (! result)
result = backend_.make_proxy(nid, aid);
return result;
}
std::vector<strong_actor_ptr> proxy_registry::get_all(const key_type& node) {
std::vector<strong_actor_ptr> result;
auto i = proxies_.find(node);
if (i != proxies_.end())
for (auto& kvp : i->second)
result.push_back(kvp.second);
return result;
}
......@@ -152,9 +80,14 @@ bool proxy_registry::empty() const {
return proxies_.empty();
}
void proxy_registry::erase(const key_type& inf) {
CAF_LOG_TRACE(CAF_ARG(inf));
proxies_.erase(inf);
void proxy_registry::erase(const key_type& nid) {
CAF_LOG_TRACE(CAF_ARG(nid));
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) {
......@@ -165,7 +98,7 @@ void proxy_registry::erase(const key_type& inf, actor_id aid, exit_reason rsn) {
auto j = submap.find(aid);
if (j == submap.end())
return;
j->second.reset(rsn);
kill_proxy(j->second, rsn);
submap.erase(j);
if (submap.empty())
proxies_.erase(i);
......@@ -173,7 +106,17 @@ void proxy_registry::erase(const key_type& inf, actor_id aid, exit_reason rsn) {
}
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();
}
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
......@@ -60,9 +60,9 @@ void response_promise::deliver_impl(message msg) {
return;
}
if (source_) {
source_->enqueue(self_->address(), id_.response_id(),
source_->enqueue(self_->ctrl(), id_.response_id(),
std::move(msg), self_->context());
source_ = invalid_actor_addr;
source_.reset();
return;
}
if (self_)
......
......@@ -31,12 +31,4 @@ resumable::subtype_t resumable::subtype() const {
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
......@@ -39,26 +39,31 @@ struct impl : blocking_actor {
} // 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_};
self_.reset(new impl(cfg), false);
if (! hide_actor) {
self_ = make_actor<impl, strong_actor_ptr>(sys.next_actor_id(), sys.node(),
&sys, cfg);
if (! hidden) {
prev_ = CAF_SET_AID(self_->id());
}
CAF_LOG_TRACE(CAF_ARG(hide_actor));
self_->is_registered(! hide_actor);
CAF_LOG_TRACE(CAF_ARG(hidden));
ptr()->is_registered(! hidden);
}
scoped_actor::~scoped_actor() {
CAF_LOG_TRACE("");
if (! self_)
return;
if (self_->is_registered()) {
if (ptr()->is_registered()) {
CAF_SET_AID(prev_);
}
auto r = self_->planned_exit_reason();
self_->cleanup(r == exit_reason::not_exited ? exit_reason::normal : r,
&context_);
auto r = ptr()->planned_exit_reason();
ptr()->cleanup(r == exit_reason::not_exited ? exit_reason::normal : r,
&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) {
......
......@@ -28,20 +28,20 @@
namespace caf {
namespace decorator {
sequencer::sequencer(actor_addr f, actor_addr g, message_types_set msg_types)
: monitorable_actor(&g->home_system(),
g->home_system().next_actor_id(),
g->node(),
is_abstract_actor_flag | is_actor_dot_decorator_flag),
sequencer::sequencer(strong_actor_ptr f, strong_actor_ptr g,
message_types_set msg_types)
: monitorable_actor(is_abstract_actor_flag | is_actor_dot_decorator_flag),
f_(std::move(f)),
g_(std::move(g)),
msg_types_(std::move(msg_types)) {
// composed actor has dependency on constituent actors by default;
// if either constituent actor is already dead upon establishing
// 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_)
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) {
......
......@@ -40,7 +40,7 @@ struct splitter_state {
};
behavior fan_out_fan_in(stateful_actor<splitter_state>* self,
const std::vector<actor_addr>& workers) {
const std::vector<strong_actor_ptr>& workers) {
return {
others >> [=](const message& msg) {
self->state.rp = self->make_response_promise();
......@@ -67,11 +67,9 @@ behavior fan_out_fan_in(stateful_actor<splitter_state>* self,
} // namespace <anonymous>
splitter::splitter(std::vector<actor_addr> workers, message_types_set msg_types)
: monitorable_actor(&workers.front()->home_system(),
workers.front()->home_system().next_actor_id(),
workers.front()->node(),
is_abstract_actor_flag | is_actor_dot_decorator_flag),
splitter::splitter(std::vector<strong_actor_ptr> workers,
message_types_set msg_types)
: monitorable_actor(is_abstract_actor_flag | is_actor_dot_decorator_flag),
workers_(std::move(workers)),
msg_types_(std::move(msg_types)) {
// 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)
// the dependency, the actor is spawned dead
auto addr = address();
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) {
......@@ -100,7 +99,10 @@ void splitter::enqueue(mailbox_element_ptr what, execution_unit* context) {
}
auto down_msg_handler = [&](const down_msg& dm) {
// 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))
monitorable_actor::cleanup(dm.reason, context);
};
......
......@@ -19,6 +19,7 @@
#include "caf/sec.hpp"
#include "caf/atom.hpp"
#include "caf/actor.hpp"
#include "caf/config.hpp"
#include "caf/actor_cast.hpp"
#include "caf/message_id.hpp"
......@@ -36,15 +37,14 @@ sync_request_bouncer::sync_request_bouncer(exit_reason r)
// 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 {
CAF_ASSERT(rsn != exit_reason::not_exited);
if (sender && mid.is_request()) {
auto ptr = actor_cast<abstract_actor_ptr>(sender);
ptr->enqueue(invalid_actor_addr, mid.response_id(),
make_message(make_error(sec::request_receiver_down)),
// TODO: this breaks out of the execution unit
nullptr);
sender->enqueue(nullptr, mid.response_id(),
make_message(make_error(sec::request_receiver_down)),
// TODO: this breaks out of the execution unit
nullptr);
}
}
......
......@@ -34,7 +34,6 @@
#include "caf/group.hpp"
#include "caf/logger.hpp"
#include "caf/channel.hpp"
#include "caf/message.hpp"
#include "caf/duration.hpp"
#include "caf/actor_cast.hpp"
......@@ -59,7 +58,6 @@ const char* numbered_type_names[] = {
"@addr",
"@addrvec",
"@atom",
"@channel",
"@charbuf",
"@down",
"@duration",
......@@ -77,6 +75,7 @@ const char* numbered_type_names[] = {
"@node",
"@str",
"@strmap",
"@strong_actor_ptr",
"@strset",
"@strvec",
"@timeout",
......@@ -87,6 +86,7 @@ const char* numbered_type_names[] = {
"@u64",
"@u8",
"@unit",
"@weak_actor_ptr",
"bool",
"double",
"float"
......@@ -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_config& cfg,
message& msg) const {
actor_addr res;
strong_actor_ptr res;
std::set<std::string> ifs;
auto i = factories_.find(name);
if (i != factories_.end())
......
......@@ -39,16 +39,16 @@ struct fixture {
actor_system system{cfg};
scoped_actor self{system};
CAF_MESSAGE("set aut");
actor_addr res;
strong_actor_ptr res;
std::set<std::string> ifs;
scoped_execution_unit context{&system};
actor_config actor_cfg{&context};
std::tie(res, ifs) = system.types().make_actor("test_actor", actor_cfg, args);
if (expect_fail) {
CAF_REQUIRE(res == invalid_actor_addr);
CAF_REQUIRE(! res);
return;
}
CAF_REQUIRE(res != invalid_actor_addr);
CAF_REQUIRE(res);
CAF_CHECK(ifs.empty());
auto aut = actor_cast<actor>(res);
CAF_REQUIRE(aut != invalid_actor);
......
......@@ -71,7 +71,7 @@ struct send_to_self {
CAF_TEST(receive_atoms) {
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(abc_atom::value, def_atom::value, "cstring");
f(1.f);
......
......@@ -516,7 +516,7 @@ CAF_TEST(requests) {
on("hi", arg_match) >> [&](actor from) {
s->request(from, chrono::minutes(1), "whassup?", s).receive(
[&](const string& str) {
CAF_CHECK(s->current_sender() != nullptr);
CAF_CHECK(s->current_sender());
CAF_CHECK_EQUAL(str, "nothing");
s->send(from, "goodbye!");
}
......
......@@ -107,7 +107,7 @@ struct fixture {
}
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);
// clear config
scoped_actor self{system};
......
......@@ -123,6 +123,7 @@ struct fixture {
CAF_TEST_FIXTURE_SCOPE(dynamic_stateful_actor_tests, fixture)
CAF_TEST(dynamic_stateful_actor) {
CAF_REQUIRE(monitored + monitored == monitored);
test_adder(system.spawn(adder));
}
......
......@@ -83,8 +83,7 @@ public:
friend class scribe;
friend class doorman;
void enqueue(const actor_addr&, message_id,
message, execution_unit*) override;
void enqueue(strong_actor_ptr, message_id, message, execution_unit*) override;
void enqueue(mailbox_element_ptr, execution_unit*) override;
......
......@@ -71,7 +71,7 @@ public:
virtual void deliver(const node_id& source_node, actor_id source_actor,
const node_id& dest_node, actor_id dest_actor,
message_id mid,
std::vector<actor_addr>& forwarding_stack,
std::vector<strong_actor_ptr>& forwarding_stack,
message& msg) = 0;
/// Called whenever BASP learns the ID of a remote node
......@@ -104,7 +104,7 @@ public:
using payload_writer = callback<serializer&>;
/// 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);
......@@ -133,7 +133,7 @@ public:
/// Adds a new actor to the map of published actors.
void add_published_actor(uint16_t port,
actor_addr published_actor,
strong_actor_ptr published_actor,
std::set<std::string> published_interface);
/// Removes the actor currently assigned to `port`.
......@@ -146,9 +146,10 @@ public:
removed_published_actor* cb = nullptr);
/// Returns `true` if a path to destination existed, `false` otherwise.
bool dispatch(execution_unit* ctx, const actor_addr& sender,
const std::vector<actor_addr>& forwarding_stack,
const actor_addr& receiver, message_id mid, const message& msg);
bool dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
const std::vector<strong_actor_ptr>& forwarding_stack,
const strong_actor_ptr& receiver,
message_id mid, const message& msg);
/// Returns the actor namespace associated to this BASP protocol instance.
proxy_registry& proxies() {
......@@ -162,7 +163,7 @@ public:
/// Stores the address of a published actor along with its publicly
/// 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.
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 {
~basp_broker_state();
// 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
execution_unit* registry_context() override;
......@@ -68,7 +68,7 @@ struct basp_broker_state : proxy_registry::backend, basp::instance::callee {
// inherited from basp::instance::listener
void deliver(const node_id& source_node, actor_id source_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;
// performs bookkeeping such as managing `spawn_servers`
......@@ -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`
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
// are spawned whenever the broker learns a new node ID and try to
// get a 'SpawnServ' instance on the remote side
......
......@@ -69,8 +69,6 @@ protected:
virtual behavior make_behavior();
};
using broker_ptr = intrusive_ptr<broker>;
/// Convenience template alias for declaring state-based brokers.
template <class State>
using stateful_broker = stateful_actor<State, broker>;
......
......@@ -68,8 +68,7 @@ protected:
void reset_mailbox_element() {
SysMsgType tmp;
set_hdl(tmp, hdl_);
mailbox_elem_ptr_ = mailbox_element::make_joint(invalid_actor_addr,
invalid_message_id,
mailbox_elem_ptr_ = mailbox_element::make_joint(nullptr, invalid_message_id,
{}, tmp);
}
......
......@@ -48,8 +48,8 @@ public:
/// Called whenever a message has arrived via the network.
virtual void message_received_cb(const node_id& source,
const actor_addr& from,
const actor_addr& dest,
const strong_actor_ptr& from,
const strong_actor_ptr& dest,
message_id mid,
const message& msg);
......@@ -61,13 +61,13 @@ public:
/// have a direct connection to `dest_node`.
/// @param mid The ID of the message.
/// @param payload The message we've sent.
virtual void message_sent_cb(const actor_addr& from, const node_id& hop,
const actor_addr& dest, message_id mid,
virtual void message_sent_cb(const strong_actor_ptr& from, const node_id& hop,
const strong_actor_ptr& dest, message_id mid,
const message& payload);
/// Called whenever no route for sending a message exists.
virtual void message_sending_failed_cb(const actor_addr& from,
const actor_addr& dest,
virtual void message_sending_failed_cb(const strong_actor_ptr& from,
const strong_actor_ptr& dest,
message_id mid,
const message& payload);
......@@ -80,12 +80,12 @@ public:
const std::vector<char>* payload);
/// 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,
uint16_t port);
/// 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.
virtual void new_connection_established_cb(const node_id& node);
......@@ -108,7 +108,7 @@ public:
/// tried to send a message to an actor ID that could not be found
/// in the registry.
virtual void invalid_message_received_cb(const node_id& source,
const actor_addr& sender,
const strong_actor_ptr& sender,
actor_id invalid_dest,
message_id mid, const message& msg);
......
......@@ -52,10 +52,10 @@ public:
/// @returns The actual port the OS uses after `bind()`. If `port == 0` the OS
/// chooses a random high-level port.
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) {
return publish(whom.address(), system().message_types(whom),
port, in, reuse_addr);
return publish(actor_cast<strong_actor_ptr>(std::forward<Handle>(whom)),
system().message_types(whom), port, in, reuse_addr);
}
/// Makes *all* local groups accessible via network
......@@ -127,9 +127,6 @@ public:
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.
/// @note This member function is thread-safe.
template <class F>
......@@ -301,13 +298,13 @@ private:
return system().spawn_class<Impl, Os>(cfg);
}
uint16_t publish(const actor_addr& whom, std::set<std::string> sigs,
uint16_t port, const char* in, bool ru);
uint16_t publish(const strong_actor_ptr& whom, std::set<std::string> sigs,
uint16_t port, const char* in, bool ru);
void unpublish(const actor_addr& whom, uint16_t port);
actor_addr remote_actor(std::set<std::string> ifs,
std::string host, uint16_t port);
strong_actor_ptr remote_actor(std::set<std::string> ifs,
std::string host, uint16_t port);
// environment
actor_system& system_;
......@@ -317,8 +314,6 @@ private:
std::thread thread_;
// keeps track of "singleton-like" brokers
std::map<atom_value, actor> named_brokers_;
// keeps track of anonymous brokers
std::set<broker_ptr> brokers_;
// user-defined hooks
hook_uptr hooks_;
// actor offering asyncronous IO by managing this singleton instance
......
......@@ -40,7 +40,7 @@ namespace io {
/// // ifs: Interface of given actor.
/// // addr: IP address to listen to or empty for any.
/// // reuse:_addr: Enables or disables SO_REUSEPORT option.
/// (publish_atom, uint16_t port, actor_addr whom,
/// (publish_atom, uint16_t port, strong_actor_ptr whom,
/// set<string> ifs, string addr, bool reuse_addr)
/// -> either (ok_atom, uint16_t port)
/// or (error_atom, string error_string)
......@@ -57,19 +57,19 @@ namespace io {
/// or (error_atom, string error_string)
///
/// // Queries a remote node and returns an ID to this node as well as
/// // an `actor_addr` to a remote actor if an actor was published at this
/// // an `strong_actor_ptr` to a remote actor if an actor was published at this
/// // port. The actor address must be cast to either `actor` or
/// // `typed_actor` using `actor_cast` after validating `ifs`.
/// // hostname: IP address or DNS hostname.
/// // port: TCP port.
/// (connect_atom, string hostname, uint16_t port)
/// -> either (ok_atom, node_id nid, actor_addr remote_actor, set<string> ifs)
/// -> either (ok_atom, node_id nid, strong_actor_ptr remote_actor, set<string> ifs)
/// or (error_atom, string error_string)
///
/// // Closes `port` if it is mapped to `whom`.
/// // whom: A published actor.
/// // port: Used TCP port.
/// (unpublish_atom, actor_addr whom, uint16_t port)
/// (unpublish_atom, strong_actor_ptr whom, uint16_t port)
/// -> either (ok_atom)
/// or (error_atom, string error_string)
///
......@@ -87,14 +87,14 @@ namespace io {
/// // name: Announced type name of the actor.
/// // args: Initialization arguments for the actor.
/// (spawn_atom, node_id nid, string name, message args)
/// -> either (ok_atom, actor_addr, set<string>
/// -> either (ok_atom, strong_actor_ptr, set<string>
/// or (error_atom, string error_string)
///
/// }
/// ~~~
using middleman_actor =
typed_actor<
replies_to<publish_atom, uint16_t, actor_addr,
replies_to<publish_atom, uint16_t, strong_actor_ptr,
std::set<std::string>, std::string, bool>
::with<ok_atom, uint16_t>,
......@@ -102,14 +102,14 @@ using middleman_actor =
::with<ok_atom, uint16_t>,
replies_to<connect_atom, std::string, uint16_t>
::with<ok_atom, node_id, actor_addr, std::set<std::string>>,
::with<ok_atom, node_id, strong_actor_ptr, std::set<std::string>>,
reacts_to<unpublish_atom, actor_addr, uint16_t>,
reacts_to<close_atom, uint16_t>,
replies_to<spawn_atom, node_id, std::string, message>
::with<ok_atom, actor_addr, std::set<std::string>>,
::with<ok_atom, strong_actor_ptr, std::set<std::string>>,
replies_to<get_atom, node_id>::with<node_id, std::string, uint16_t>>;
......
......@@ -104,7 +104,8 @@ public:
class runnable : public resumable, public ref_counted {
public:
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
......
......@@ -35,6 +35,11 @@
namespace caf {
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*) {
CAF_PUSH_AID(id());
CAF_LOG_TRACE("enqueue " << CAF_ARG(ptr->msg));
......@@ -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) {
CAF_ASSERT(eu != nullptr);
CAF_ASSERT(eu == &backend());
// add implicit reference count held by middleman/multiplexer
ref();
intrusive_ptr_add_ref(ctrl());
is_registered(! is_hidden);
CAF_PUSH_AID(id());
CAF_LOG_TRACE("init and launch broker:" << CAF_ARG(id()));
......
......@@ -58,7 +58,7 @@ basp_broker_state::~basp_broker_state() {
anon_send_exit(kvp.second, exit_reason::kill);
}
actor_proxy_ptr basp_broker_state::make_proxy(node_id nid, actor_id aid) {
strong_actor_ptr basp_broker_state::make_proxy(node_id nid, actor_id aid) {
CAF_LOG_TRACE(CAF_ARG(nid) << CAF_ARG(aid));
CAF_ASSERT(nid != this_node());
if (nid == invalid_node_id || aid == invalid_actor_id)
......@@ -82,17 +82,18 @@ actor_proxy_ptr basp_broker_state::make_proxy(node_id nid, actor_id aid) {
}
// create proxy and add functor that will be called if we
// receive a kill_proxy_instance message
intrusive_ptr<basp_broker> ptr = static_cast<basp_broker*>(self);
auto mm = &system().middleman();
auto res = make_counted<forwarding_actor_proxy>(self->home_system_,
aid, nid, ptr);
res->attach_functor([=](exit_reason rsn) {
auto res = make_actor<forwarding_actor_proxy, strong_actor_ptr>(
aid, nid, &(self->home_system()), self);
auto selfptr = actor_cast<strong_actor_ptr>(self);
res->get()->attach_functor([=](exit_reason rsn) {
mm->backend().post([=] {
// using res->id() instead of aid keeps this actor instance alive
// until the original instance terminates, thus preventing subtle
// bugs with attachables
if (! ptr->exited())
ptr->state.proxies().erase(nid, res->id(), rsn);
auto bptr = static_cast<basp_broker*>(selfptr->get());
if (! bptr->exited())
bptr->state.proxies().erase(nid, res->id(), rsn);
});
});
CAF_LOG_INFO("successfully created proxy instance, "
......@@ -105,7 +106,7 @@ actor_proxy_ptr basp_broker_state::make_proxy(node_id nid, actor_id aid) {
this_node(), nid,
invalid_actor_id, aid);
instance.tbl().flush(*path);
mm->notify<hook::new_remote_actor>(res->address());
mm->notify<hook::new_remote_actor>(res);
return res;
}
......@@ -132,20 +133,16 @@ void basp_broker_state::finalize_handshake(const node_id& nid, actor_id aid,
std::move(sigs)));
return;
}
actor_addr addr;
strong_actor_ptr ptr;
if (nid == this_node()) {
// connected to self
addr = system().registry().get(aid).first;
CAF_LOG_INFO_IF(! addr, "actor not found:" << CAF_ARG(aid));
ptr = actor_cast<strong_actor_ptr>(system().registry().get(aid).first);
CAF_LOG_INFO_IF(! ptr, "actor not found:" << CAF_ARG(aid));
} else {
auto ptr = namespace_.get_or_put(nid, aid);
if (ptr)
addr = ptr->address();
ptr = namespace_.get_or_put(nid, aid);
CAF_LOG_ERROR_IF(! ptr, "creating actor in finalize_handshake failed");
}
if (addr.node() != system().node())
known_remotes.emplace(nid, std::make_pair(this_context->remote_port, addr));
cb->deliver(make_message(ok_atom::value, nid, addr, std::move(sigs)));
cb->deliver(make_message(ok_atom::value, nid, ptr, std::move(sigs)));
this_context->callback = none;
}
......@@ -164,7 +161,6 @@ void basp_broker_state::purge_state(const node_id& nid) {
ctx.erase(i);
}
proxies().erase(nid);
known_remotes.erase(nid);
}
void basp_broker_state::proxy_announced(const node_id& nid, actor_id aid) {
......@@ -172,6 +168,8 @@ void basp_broker_state::proxy_announced(const node_id& nid, actor_id aid) {
// source node has created a proxy for one of our actors
auto entry = system().registry().get(aid);
auto send_kill_proxy_instance = [=](exit_reason rsn) {
if (rsn == exit_reason::not_exited)
rsn = exit_reason::unknown;
auto path = instance.tbl().lookup(nid);
if (! path) {
CAF_LOG_INFO("cannot send exit message for proxy, no route to host:"
......@@ -182,16 +180,18 @@ void basp_broker_state::proxy_announced(const node_id& nid, actor_id aid) {
nid, aid, rsn);
instance.tbl().flush(*path);
};
if (entry.second != exit_reason::not_exited) {
auto ptr = actor_cast<strong_actor_ptr>(entry.first);
if (! ptr || entry.second != exit_reason::not_exited) {
CAF_LOG_DEBUG("kill proxy immediately");
// kill immediately if actor has already terminated
send_kill_proxy_instance(entry.second);
} else {
intrusive_ptr<broker> bptr = self; // keep broker alive ...
auto tmp = actor_cast<strong_actor_ptr>(self); // keep broker alive ...
auto mm = &system().middleman();
entry.first->attach_functor([=](exit_reason reason) {
ptr->get()->attach_functor([=](exit_reason reason) {
mm->backend().dispatch([=] {
CAF_LOG_TRACE(CAF_ARG(reason));
auto bptr = static_cast<basp_broker*>(tmp->get());
// ... to make sure this is safe
if (bptr == mm->named_broker<basp_broker>(atom("BASP"))
&& ! bptr->exited())
......@@ -207,58 +207,50 @@ void basp_broker_state::kill_proxy(const node_id& nid, actor_id aid,
proxies().erase(nid, aid, rsn);
}
void basp_broker_state::deliver(const node_id& source_node,
actor_id source_actor,
const node_id& dest_node,
actor_id dest_actor,
void basp_broker_state::deliver(const node_id& src_nid,
actor_id src_aid,
const node_id& dest_nid,
actor_id dest_aid,
message_id mid,
std::vector<actor_addr>& stages,
std::vector<strong_actor_ptr>& stages,
message& msg) {
CAF_LOG_TRACE(CAF_ARG(source_node)
<< CAF_ARG(source_actor) << CAF_ARG(dest_node)
<< CAF_ARG(dest_actor) << CAF_ARG(msg) << CAF_ARG(mid));
actor_addr src;
if (source_node == this_node()) {
auto src_ptr = system().registry().get(source_actor).first;
if (src_ptr)
src = src_ptr->address();
} else {
auto ptr = proxies().get_or_put(source_node, source_actor);
if (ptr)
src = ptr->address();
}
actor_addr dest;
CAF_LOG_TRACE(CAF_ARG(src_nid)
<< CAF_ARG(src_aid) << CAF_ARG(dest_nid)
<< CAF_ARG(dest_aid) << CAF_ARG(msg) << CAF_ARG(mid));
strong_actor_ptr src;
if (src_nid == this_node())
src = actor_cast<strong_actor_ptr>(system().registry().get(src_aid).first);
else
src = proxies().get_or_put(src_nid, src_aid);
strong_actor_ptr dest;
auto rsn = exit_reason::remote_link_unreachable;
if (dest_node != this_node()) {
auto ptr = proxies().get_or_put(dest_node, dest_actor);
if (ptr)
dest = ptr->address();
if (dest_nid != this_node()) {
dest = proxies().get_or_put(dest_nid, dest_aid);
} else {
if (dest_actor == std::numeric_limits<actor_id>::max()) {
if (dest_aid == std::numeric_limits<actor_id>::max()) {
// this hack allows CAF to talk to older CAF versions; CAF <= 0.14 will
// discard this message silently as the receiver is not found, while
// CAF >= 0.14.1 will use the operation data to identify named actors
auto dest_name = static_cast<atom_value>(mid.integer_value());
CAF_LOG_DEBUG(CAF_ARG(dest_name));
mid = message_id::make(); // override this since the message is async
dest = system().registry().get(dest_name).address();
dest = actor_cast<strong_actor_ptr>(system().registry().get(dest_name));
} else {
std::tie(dest, rsn) = system().registry().get(dest_actor);
std::tie(dest, rsn) = system().registry().get(dest_aid);
}
}
if (! dest) {
CAF_LOG_INFO("cannot deliver message, destination not found");
self->parent().notify<hook::invalid_message_received>(source_node, src,
dest_actor, mid, msg);
if (mid.valid() && src != invalid_actor_addr) {
self->parent().notify<hook::invalid_message_received>(src_nid, src,
dest_aid, mid, msg);
if (mid.valid() && src) {
detail::sync_request_bouncer srb{rsn};
srb(src, mid);
}
return;
}
self->parent().notify<hook::message_received>(source_node, src,
dest->address(), mid, msg);
dest->enqueue(mailbox_element::make(src, mid, std::move(stages),
self->parent().notify<hook::message_received>(src_nid, src, dest, mid, msg);
dest->enqueue(mailbox_element::make(std::move(src), mid, std::move(stages),
std::move(msg)),
nullptr);
}
......@@ -276,7 +268,7 @@ void basp_broker_state::learned_new_node(const node_id& nid) {
this_actor->monitor(config_serv);
this_actor->become(
[=](spawn_atom, std::string& type, message& args)
-> delegated<ok_atom, actor_addr, std::set<std::string>> {
-> delegated<ok_atom, strong_actor_ptr, std::set<std::string>> {
CAF_LOG_TRACE(CAF_ARG(type) << CAF_ARG(args));
this_actor->delegate(config_serv, get_atom::value,
std::move(type), std::move(args));
......@@ -299,7 +291,7 @@ void basp_broker_state::learned_new_node(const node_id& nid) {
};
});
using namespace detail;
system().registry().put(tmp.id(), tmp.address());
system().registry().put(tmp.id(), actor_cast<strong_actor_ptr>(tmp));
auto writer = make_callback([](serializer& sink) {
std::vector<actor_id> stages;
auto msg = make_message(sys_atom::value, get_atom::value, "info");
......@@ -396,7 +388,7 @@ void basp_broker_state::learned_new_node_indirectly(const node_id& nid) {
}
using namespace detail;
auto tmp = system().spawn<detached + hidden>(connection_helper, self);
system().registry().put(tmp.id(), tmp.address());
system().registry().put(tmp.id(), actor_cast<strong_actor_ptr>(tmp));
auto writer = make_callback([](serializer& sink) {
std::vector<actor_id> stages;
auto msg = make_message(get_atom::value, "basp.default-connectivity");
......@@ -452,7 +444,8 @@ printf("enable automatic connections\n");
auto port = add_tcp_doorman(uint16_t{0});
auto addrs = network::interfaces::list_addresses(false);
auto config_server = system().registry().get(atom("ConfigServ"));
send(config_server, put_atom::value, "basp.default-connectivity",
send(actor_cast<actor>(config_server), put_atom::value,
"basp.default-connectivity",
make_message(port.second, std::move(addrs)));
state.enable_automatic_connections = true;
}
......@@ -489,17 +482,17 @@ printf("enable automatic connections\n");
}
},
// received from proxy instances
[=](forward_atom, const actor_addr& sender,
const std::vector<actor_addr>& fwd_stack, const actor_addr& receiver,
message_id mid, const message& msg) {
[=](forward_atom, strong_actor_ptr& sender,
const std::vector<strong_actor_ptr>& fwd_stack,
strong_actor_ptr& receiver, message_id mid, const message& msg) {
CAF_LOG_TRACE(CAF_ARG(sender) << CAF_ARG(receiver)
<< CAF_ARG(mid) << CAF_ARG(msg));
if (! receiver || system().node() == receiver.node()) {
if (! receiver || system().node() == receiver->node()) {
CAF_LOG_WARNING("cannot forward to invalid or local actor:"
<< CAF_ARG(receiver));
return;
}
if (sender && system().node() == sender.node())
if (sender && system().node() == sender->node())
system().registry().put(sender->id(), sender);
if (! state.instance.dispatch(context(), sender, fwd_stack,
receiver, mid, msg)
......@@ -509,16 +502,16 @@ printf("enable automatic connections\n");
}
},
// received from some system calls like whereis
[=](forward_atom, const actor_addr& sender,
[=](forward_atom, strong_actor_ptr& sender,
const node_id& receiving_node, atom_value receiver_name,
const message& msg) -> result<void> {
CAF_LOG_TRACE(CAF_ARG(sender)
<< ", " << CAF_ARG(receiving_node)
<< ", " << CAF_ARG(receiver_name)
<< ", " << CAF_ARG(msg));
if (sender == invalid_actor_addr)
if (! sender)
return sec::cannot_forward_to_invalid_actor;
if (system().node() == sender.node())
if (system().node() == sender->node())
system().registry().put(sender->id(), sender);
auto writer = make_callback([&](serializer& sink) {
std::vector<actor_addr> stages;
......@@ -536,7 +529,7 @@ printf("enable automatic connections\n");
basp::message_type::dispatch_message,
nullptr, static_cast<uint64_t>(receiver_name),
state.this_node(), receiving_node,
sender.id(),
sender->id(),
std::numeric_limits<actor_id>::max(),
&writer);
state.instance.flush(*path);
......@@ -571,8 +564,8 @@ printf("enable automatic connections\n");
state.instance.remove_published_actor(port);
},
// received from middleman actor
[=](publish_atom, accept_handle hdl, uint16_t port, const actor_addr& whom,
std::set<std::string>& sigs) {
[=](publish_atom, accept_handle hdl, uint16_t port,
const strong_actor_ptr& whom, std::set<std::string>& sigs) {
CAF_LOG_TRACE(CAF_ARG(hdl.id()) << CAF_ARG(whom) << CAF_ARG(port));
if (hdl.invalid()) {
CAF_LOG_WARNING("invalid handle");
......@@ -585,9 +578,8 @@ printf("enable automatic connections\n");
CAF_LOG_DEBUG("failed to assign doorman from handle");
return;
}
if (whom != invalid_actor_addr) {
if (whom)
system().registry().put(whom->id(), whom);
}
state.instance.add_published_actor(port, whom, std::move(sigs));
},
// received from middleman actor (delegated)
......@@ -618,7 +610,7 @@ printf("enable automatic connections\n");
CAF_LOG_TRACE(CAF_ARG(whom) << CAF_ARG(port));
if (whom == invalid_actor_addr)
return sec::no_actor_to_unpublish;
auto cb = make_callback([&](const actor_addr&, uint16_t x) {
auto cb = make_callback([&](const strong_actor_ptr&, uint16_t x) {
try { close(hdl_by_port(x)); }
catch (std::exception&) { }
});
......@@ -641,7 +633,7 @@ printf("enable automatic connections\n");
return unit;
},
[=](spawn_atom, const node_id& nid, std::string& type, message& xs)
-> delegated<ok_atom, actor_addr, std::set<std::string>> {
-> delegated<ok_atom, strong_actor_ptr, std::set<std::string>> {
CAF_LOG_TRACE(CAF_ARG(nid) << CAF_ARG(type) << CAF_ARG(xs));
auto i = state.spawn_servers.find(nid);
if (i == state.spawn_servers.end()) {
......
......@@ -709,7 +709,6 @@ default_multiplexer::~default_multiplexer() {
void default_multiplexer::exec_later(resumable* ptr) {
CAF_ASSERT(ptr);
CAF_ASSERT(ptr->as_ref_counted_ptr()->get_reference_count() > 0);
switch (ptr->subtype()) {
case resumable::io_actor:
case resumable::function_object:
......
......@@ -28,14 +28,15 @@ hook::~hook() {
// nop
}
void hook::message_received_cb(const node_id& source, const actor_addr& from,
const actor_addr& dest, message_id mid,
void hook::message_received_cb(const node_id& source,
const strong_actor_ptr& from,
const strong_actor_ptr& dest, message_id mid,
const message& msg) {
call_next<message_received>(source, from, dest, mid, msg);
}
void hook::message_sent_cb(const actor_addr& from, const node_id& dest_node,
const actor_addr& dest, message_id mid,
void hook::message_sent_cb(const strong_actor_ptr& from, const node_id& dest_node,
const strong_actor_ptr& dest, message_id mid,
const message& payload) {
call_next<message_sent>(from, dest_node, dest, mid, payload);
}
......@@ -50,20 +51,20 @@ void hook::message_forwarding_failed_cb(const basp::header& hdr,
call_next<message_forwarding_failed>(hdr, payload);
}
void hook::message_sending_failed_cb(const actor_addr& from,
const actor_addr& dest,
void hook::message_sending_failed_cb(const strong_actor_ptr& from,
const strong_actor_ptr& dest,
message_id mid,
const message& payload) {
call_next<message_sending_failed>(from, dest, mid, payload);
}
void hook::actor_published_cb(const actor_addr& addr,
void hook::actor_published_cb(const strong_actor_ptr& addr,
const std::set<std::string>& ifs,
uint16_t port) {
call_next<actor_published>(addr, ifs, port);
}
void hook::new_remote_actor_cb(const actor_addr& addr) {
void hook::new_remote_actor_cb(const strong_actor_ptr& addr) {
call_next<new_remote_actor>(addr);
}
......@@ -84,7 +85,7 @@ void hook::route_lost_cb(const node_id& hop, const node_id& dest) {
}
void hook::invalid_message_received_cb(const node_id& source,
const actor_addr& sender,
const strong_actor_ptr& sender,
actor_id invalid_dest,
message_id mid,
const message& msg) {
......
......@@ -177,7 +177,7 @@ connection_state instance::handle(execution_unit* ctx,
&& tbl_.add_indirect(last_hop, hdr.source_node))
callee_.learned_new_node_indirectly(hdr.source_node);
binary_deserializer bd{ctx, payload->data(), payload->size()};
std::vector<actor_addr> forwarding_stack;
std::vector<strong_actor_ptr> forwarding_stack;
message msg;
bd >> forwarding_stack >> msg;
callee_.deliver(hdr.source_node, hdr.source_actor,
......@@ -240,7 +240,7 @@ void instance::write(execution_unit* ctx, const routing_table::route& r,
}
void instance::add_published_actor(uint16_t port,
actor_addr published_actor,
strong_actor_ptr published_actor,
std::set<std::string> published_interface) {
using std::swap;
auto& entry = published_actors_[port];
......@@ -260,14 +260,15 @@ size_t instance::remove_published_actor(uint16_t port,
return 1;
}
size_t instance::remove_published_actor(const actor_addr& whom, uint16_t port,
size_t instance::remove_published_actor(const actor_addr& whom,
uint16_t port,
removed_published_actor* cb) {
size_t result = 0;
if (port != 0) {
auto i = published_actors_.find(port);
if (i != published_actors_.end() && i->second.first == whom) {
if (cb)
(*cb)(whom, port);
(*cb)(i->second.first, port);
published_actors_.erase(i);
result = 1;
}
......@@ -276,7 +277,7 @@ size_t instance::remove_published_actor(const actor_addr& whom, uint16_t port,
while (i != published_actors_.end()) {
if (i->second.first == whom) {
if (cb)
(*cb)(whom, i->first);
(*cb)(i->second.first, i->first);
i = published_actors_.erase(i);
++result;
} else {
......@@ -287,12 +288,12 @@ size_t instance::remove_published_actor(const actor_addr& whom, uint16_t port,
return result;
}
bool instance::dispatch(execution_unit* ctx, const actor_addr& sender,
const std::vector<actor_addr>& forwarding_stack,
const actor_addr& receiver, message_id mid,
bool instance::dispatch(execution_unit* ctx, const strong_actor_ptr& sender,
const std::vector<strong_actor_ptr>& forwarding_stack,
const strong_actor_ptr& receiver, message_id mid,
const message& msg) {
CAF_LOG_TRACE("");
CAF_ASSERT(system().node() != receiver.node());
CAF_ASSERT(receiver && system().node() != receiver->node());
auto path = lookup(receiver->node());
if (! path) {
notify<hook::message_sending_failed>(sender, receiver, mid, msg);
......@@ -373,13 +374,14 @@ void instance::write_server_handshake(execution_unit* ctx,
}
auto writer = make_callback([&](serializer& sink) {
if (pa) {
auto i = pa->first.id();
auto i = pa->first ? pa->first->id() : invalid_actor_id;
sink << i << pa->second;
}
});
header hdr{message_type::server_handshake, 0, version,
this_node_, invalid_node_id,
pa ? pa->first.id() : invalid_actor_id, invalid_actor_id};
pa && pa->first ? pa->first->id() : invalid_actor_id,
invalid_actor_id};
write(ctx, out_buf, hdr, &writer);
}
......
......@@ -48,7 +48,7 @@ void manager::detach(execution_unit* ctx, bool invoke_disconnect_message) {
set_parent(nullptr);
detach_from(ptr);
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());
ptr->exec_single_event(ctx, mptr);
}
......
......@@ -107,7 +107,8 @@ middleman::middleman(actor_system& sys)
// nop
}
uint16_t middleman::publish(const actor_addr& whom, std::set<std::string> sigs,
uint16_t middleman::publish(const strong_actor_ptr& whom,
std::set<std::string> sigs,
uint16_t port, const char* in, bool ru) {
CAF_LOG_TRACE(CAF_ARG(whom) << CAF_ARG(sigs) << CAF_ARG(port)
<< CAF_ARG(in) << CAF_ARG(ru));
......@@ -177,15 +178,15 @@ void middleman::unpublish(const actor_addr& whom, uint16_t port) {
);
}
actor_addr middleman::remote_actor(std::set<std::string> ifs,
std::string host, uint16_t port) {
strong_actor_ptr middleman::remote_actor(std::set<std::string> ifs,
std::string host, uint16_t port) {
CAF_LOG_TRACE(CAF_ARG(ifs) << CAF_ARG(host) << CAF_ARG(port));
auto mm = actor_handle();
actor_addr result;
strong_actor_ptr result;
scoped_actor self{system(), true};
self->request(mm, infinite, connect_atom::value,
std::move(host), port).receive(
[&](ok_atom, const node_id&, actor_addr res, std::set<std::string>& xs) {
[&](ok_atom, const node_id&, strong_actor_ptr res, std::set<std::string>& xs) {
CAF_LOG_TRACE(CAF_ARG(res) << CAF_ARG(xs));
if (!res)
throw network_error("no actor published at port "
......@@ -199,7 +200,7 @@ actor_addr middleman::remote_actor(std::set<std::string> ifs,
throw network_error(std::move(what));
}
result = std::move(res);
result.swap(res);
},
[&](const error& msg) {
CAF_LOG_TRACE(CAF_ARG(msg));
......@@ -241,13 +242,6 @@ group middleman::remote_group(const std::string& group_identifier,
return result;
}
void middleman::add_broker(broker_ptr bptr) {
CAF_ASSERT(bptr != nullptr);
CAF_LOG_TRACE(CAF_ARG(bptr->id()));
brokers_.insert(bptr);
bptr->attach_functor([=] { brokers_.erase(bptr); });
}
actor middleman::remote_lookup(atom_value name, const node_id& nid) {
CAF_LOG_TRACE(CAF_ARG(name) << CAF_ARG(nid));
auto basp = named_broker<basp_broker>(atom("BASP"));
......
......@@ -62,25 +62,25 @@ public:
using mpi_set = std::set<std::string>;
using get_res = delegated<ok_atom, node_id, actor_addr, mpi_set>;
using get_res = delegated<ok_atom, node_id, strong_actor_ptr, mpi_set>;
using del_res = delegated<void>;
using endpoint_data = std::tuple<node_id, actor_addr, mpi_set>;
using endpoint_data = std::tuple<node_id, strong_actor_ptr, mpi_set>;
using endpoint = std::pair<std::string, uint16_t>;
behavior_type make_behavior() override {
CAF_LOG_TRACE("");
return {
[=](publish_atom, uint16_t port, actor_addr& whom,
[=](publish_atom, uint16_t port, strong_actor_ptr& whom,
mpi_set& sigs, std::string& addr, bool reuse) -> put_res {
CAF_LOG_TRACE("");
return put(port, whom, sigs, addr.c_str(), reuse);
},
[=](open_atom, uint16_t port, std::string& addr, bool reuse) -> put_res {
CAF_LOG_TRACE("");
actor_addr whom = invalid_actor_addr;
strong_actor_ptr whom;
mpi_set sigs;
return put(port, whom, sigs, addr.c_str(), reuse);
},
......@@ -113,7 +113,7 @@ public:
std::vector<response_promise> tmp{std::move(rp)};
pending_.emplace(key, std::move(tmp));
request(broker_, infinite, connect_atom::value, hdl, port).then(
[=](ok_atom, node_id& nid, actor_addr& addr, mpi_set& sigs) {
[=](ok_atom, node_id& nid, strong_actor_ptr& addr, mpi_set& sigs) {
auto i = pending_.find(key);
if (i == pending_.end())
return;
......@@ -148,7 +148,7 @@ public:
return {};
},
[=](spawn_atom, const node_id&, const std::string&, const message&)
-> delegated<ok_atom, actor_addr, mpi_set> {
-> delegated<ok_atom, strong_actor_ptr, mpi_set> {
CAF_LOG_TRACE("");
forward_current_message(broker_);
return {};
......@@ -173,7 +173,7 @@ public:
}
private:
put_res put(uint16_t port, actor_addr& whom,
put_res put(uint16_t port, strong_actor_ptr& whom,
mpi_set& sigs, const char* in = nullptr,
bool reuse_addr = false) {
CAF_LOG_TRACE(CAF_ARG(port) << CAF_ARG(whom) << CAF_ARG(sigs)
......
......@@ -49,8 +49,12 @@ resumable::subtype_t multiplexer::runnable::subtype() const {
return resumable::function_object;
}
ref_counted* multiplexer::runnable::as_ref_counted_ptr() {
return this;
void multiplexer::runnable::intrusive_ptr_add_ref_impl() {
intrusive_ptr_add_ref(this);
}
void multiplexer::runnable::intrusive_ptr_release_impl() {
intrusive_ptr_release(this);
}
} // namespace network
......
......@@ -68,9 +68,7 @@ void scribe::data_transferred(execution_unit* ctx, size_t written,
if (detached())
return;
data_transferred_msg tmp{hdl(), written, remaining};
auto ptr = mailbox_element::make_joint(invalid_actor_addr,
invalid_message_id,
{}, tmp);
auto ptr = mailbox_element::make_joint(nullptr, invalid_message_id, {}, tmp);
parent()->exec_single_event(ctx, ptr);
}
......
......@@ -369,7 +369,6 @@ void test_multiplexer::flush_runnables() {
void test_multiplexer::exec_later(resumable* ptr) {
CAF_ASSERT(ptr != nullptr);
CAF_ASSERT(ptr->as_ref_counted_ptr()->get_reference_count() > 0);
CAF_LOG_TRACE("");
switch (ptr->subtype()) {
case resumable::io_actor:
......@@ -388,7 +387,6 @@ void test_multiplexer::exec_later(resumable* ptr) {
void test_multiplexer::exec(resumable_ptr& ptr) {
CAF_ASSERT(ptr != nullptr);
CAF_ASSERT(ptr->as_ref_counted_ptr()->get_reference_count() > 0);
CAF_LOG_TRACE("");
switch (ptr->resume(this, 1)) {
case resumable::resume_later:
......
......@@ -111,9 +111,9 @@ public:
CAF_MESSAGE("this node: " << to_string(this_node_));
self_.reset(new scoped_actor{system});
ahdl_ = accept_handle::from_int(1);
mpx_->assign_tcp_doorman(aut_.get(), ahdl_);
mpx_->assign_tcp_doorman(aut_, ahdl_);
registry_ = &system.registry();
registry_->put((*self_)->id(), (*self_)->address());
registry_->put((*self_)->id(), actor_cast<strong_actor_ptr>(*self_));
// first remote node is everything of this_node + 1, then +2, etc.
for (uint32_t i = 0; i < num_remote_nodes; ++i) {
node_id::host_id_type tmp = this_node_.host_id();
......@@ -124,7 +124,7 @@ public:
auto& ptr = pseudo_remote_[i];
ptr.reset(new scoped_actor{system});
// register all pseudo remote actors in the registry
registry_->put((*ptr)->id(), (*ptr)->address());
registry_->put((*ptr)->id(), actor_cast<strong_actor_ptr>(*ptr));
}
// make sure all init messages are handled properly
mpx_->flush_runnables();
......@@ -153,7 +153,7 @@ public:
// actor-under-test
basp_broker* aut() {
return aut_.get();
return aut_;
}
// our node ID
......@@ -320,16 +320,14 @@ public:
CAF_MESSAGE("dispatch output buffer for connection " << hdl.id());
CAF_REQUIRE(hdr.operation == basp::message_type::dispatch_message);
binary_deserializer source{mpx_, buf.data(), buf.size()};
std::vector<actor_addr> stages;
std::vector<strong_actor_ptr> stages;
message msg;
source >> stages >> msg;
auto src = registry_->get(hdr.source_actor).first;
auto dest = registry_->get(hdr.dest_actor).first;
CAF_REQUIRE(dest != nullptr);
dest->enqueue(mailbox_element::make(src ? src->address()
: invalid_actor_addr,
message_id::make(), std::move(stages),
std::move(msg)),
auto src = actor_cast<strong_actor_ptr>(registry_->get(hdr.source_actor).first);
auto dest = actor_cast<actor>(registry_->get(hdr.dest_actor).first);
CAF_REQUIRE(dest);
dest->enqueue(mailbox_element::make(src, message_id::make(),
std::move(stages), std::move(msg)),
nullptr);
}
......@@ -418,7 +416,7 @@ public:
actor_system system;
private:
intrusive_ptr<basp_broker> aut_;
basp_broker* aut_;
accept_handle ahdl_;
network::test_multiplexer* mpx_;
node_id this_node_;
......@@ -462,7 +460,7 @@ CAF_TEST(non_empty_server_handshake) {
// test whether basp instance correctly sends a
// server handshake with published actors
buffer buf;
instance().add_published_actor(4242, self().address(),
instance().add_published_actor(4242, actor_cast<strong_actor_ptr>(self()),
{"caf::replies_to<@u16>::with<@u16>"});
instance().write_server_handshake(mpx(), buf, 4242);
buffer expected_buf;
......@@ -594,18 +592,18 @@ CAF_TEST(remote_actor_and_send) {
invalid_actor_id, pseudo_remote(0)->id());
CAF_MESSAGE("BASP broker should've send the proxy");
f.receive(
[&](ok_atom, node_id nid, actor_addr res, std::set<std::string> ifs) {
auto aptr = actor_cast<abstract_actor_ptr>(res);
CAF_REQUIRE(aptr.downcast<forwarding_actor_proxy>() != nullptr);
CAF_CHECK(proxies().get_all().size() == 1);
[&](ok_atom, node_id nid, strong_actor_ptr res, std::set<std::string> ifs) {
CAF_REQUIRE(res);
auto aptr = actor_cast<abstract_actor*>(res);
CAF_REQUIRE(dynamic_cast<forwarding_actor_proxy*>(aptr) != nullptr);
CAF_CHECK(proxies().count_proxies(remote_node(0)) == 1);
CAF_CHECK(nid == remote_node(0));
CAF_CHECK(res.node() == remote_node(0));
CAF_CHECK(res.id() == pseudo_remote(0)->id());
CAF_CHECK(res->node() == remote_node(0));
CAF_CHECK(res->id() == pseudo_remote(0)->id());
CAF_CHECK(ifs.empty());
auto proxy = proxies().get(remote_node(0), pseudo_remote(0)->id());
CAF_REQUIRE(proxy != nullptr);
CAF_REQUIRE(proxy->address() == res);
CAF_REQUIRE(proxy == res);
result = actor_cast<actor>(res);
}
);
......@@ -656,9 +654,9 @@ CAF_TEST(actor_serialize_and_deserialize) {
CAF_CHECK(prx->node() == remote_node(0));
CAF_CHECK(prx->id() == pseudo_remote(0)->id());
auto testee = system.spawn(testee_impl);
registry()->put(testee->id(), testee->address());
registry()->put(testee->id(), actor_cast<strong_actor_ptr>(testee));
CAF_MESSAGE("send message via BASP (from proxy)");
auto msg = make_message(prx->address());
auto msg = make_message(actor_cast<actor_addr>(prx));
mock(remote_hdl(0),
{basp::message_type::dispatch_message, 0, 0,
prx->node(), this_node(),
......
......@@ -70,11 +70,12 @@ behavior server(stateful_actor<server_state>* self) {
auto mm = self->system().middleman().actor_handle();
self->request(mm, infinite, spawn_atom::value,
s.node(), "mirror", make_message()).then(
[=](ok_atom, const actor_addr& addr, const std::set<std::string>& ifs) {
CAF_LOG_TRACE(CAF_ARG(addr) << CAF_ARG(ifs));
CAF_REQUIRE(addr != invalid_actor_addr);
[=](ok_atom, const strong_actor_ptr& ptr,
const std::set<std::string>& ifs) {
CAF_LOG_TRACE(CAF_ARG(ptr) << CAF_ARG(ifs));
CAF_REQUIRE(ptr);
CAF_CHECK(ifs.empty());
self->state.aut = actor_cast<actor>(addr);
self->state.aut = actor_cast<actor>(ptr);
self->send(self->state.aut, "hello mirror");
self->become(
[=](const std::string& str) {
......
......@@ -75,7 +75,7 @@ struct fixture {
scoped_actor self{system, true};
self->request(system.middleman().actor_handle(), infinite,
connect_atom::value, hostname, port).receive(
[&](ok_atom, node_id&, actor_addr& res, std::set<std::string>& xs) {
[&](ok_atom, node_id&, strong_actor_ptr& res, std::set<std::string>& xs) {
CAF_REQUIRE(xs.empty());
result = actor_cast<actor>(std::move(res));
},
......
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