Commit 6773bedb authored by Dominik Charousset's avatar Dominik Charousset

preparations for 0.9 changes

this commit is the first part of a revision of libcppa that removes
the thread-local `self` pointer, `actor_ptr`, and `channel_ptr`
to pave the way for fully type-safe actor programming;
this first step splits the addressing of actors into an `actor`
handle and an `actor_addr`: only the former can be used to send
messages, whereas the latter can only be used to monitor or identify
actors;
next steps will add `typed_actor<>` handles that allow the compiler
to type-check the message passing interface;
the revision is work in progress and this commit does not compile
parent d098bcb5
...@@ -120,8 +120,11 @@ file(GLOB LIBCPPA_HDRS "cppa/*.hpp" ...@@ -120,8 +120,11 @@ file(GLOB LIBCPPA_HDRS "cppa/*.hpp"
# list cpp files including platform-dependent files # list cpp files including platform-dependent files
set(LIBCPPA_SRC set(LIBCPPA_SRC
${LIBCPPA_PLATFORM_SRC} ${LIBCPPA_PLATFORM_SRC}
src/abstract_actor.cpp
src/abstract_channel.cpp
src/abstract_tuple.cpp src/abstract_tuple.cpp
src/actor.cpp src/actor.cpp
src/actor_addr.cpp
src/actor_namespace.cpp src/actor_namespace.cpp
src/actor_proxy.cpp src/actor_proxy.cpp
src/actor_registry.cpp src/actor_registry.cpp
...@@ -149,7 +152,6 @@ set(LIBCPPA_SRC ...@@ -149,7 +152,6 @@ set(LIBCPPA_SRC
src/event_based_actor.cpp src/event_based_actor.cpp
src/exception.cpp src/exception.cpp
src/exit_reason.cpp src/exit_reason.cpp
src/factory.cpp
src/fd_util.cpp src/fd_util.cpp
src/fiber.cpp src/fiber.cpp
src/get_root_uuid.cpp src/get_root_uuid.cpp
...@@ -181,8 +183,7 @@ set(LIBCPPA_SRC ...@@ -181,8 +183,7 @@ set(LIBCPPA_SRC
src/scheduled_actor.cpp src/scheduled_actor.cpp
src/scheduled_actor_dummy.cpp src/scheduled_actor_dummy.cpp
src/scheduler.cpp src/scheduler.cpp
src/send.cpp src/scoped_actor.cpp
src/self.cpp
src/serializer.cpp src/serializer.cpp
src/shared_spinlock.cpp src/shared_spinlock.cpp
src/singleton_manager.cpp src/singleton_manager.cpp
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_ABSTRACT_ACTOR_HPP
#define CPPA_ABSTRACT_ACTOR_HPP
#include <mutex>
#include <atomic>
#include <memory>
#include <vector>
#include <cstdint>
#include <type_traits>
#include "cppa/node_id.hpp"
#include "cppa/cppa_fwd.hpp"
#include "cppa/attachable.hpp"
#include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_channel.hpp"
#include "cppa/util/type_traits.hpp"
namespace cppa {
class actor_addr;
class serializer;
class deserializer;
/**
* @brief A unique actor ID.
* @relates actor
*/
typedef std::uint32_t actor_id;
class abstract_actor;
typedef intrusive_ptr<abstract_actor> abstract_actor_ptr;
/**
* @brief Base class for all actor implementations.
*/
class abstract_actor : public abstract_channel {
public:
/**
* @brief Attaches @p ptr to this actor.
*
* The actor will call <tt>ptr->detach(...)</tt> on exit, or immediately
* if it already finished execution.
* @param ptr A callback object that's executed if the actor finishes
* execution.
* @returns @c true if @p ptr was successfully attached to the actor;
* otherwise (actor already exited) @p false.
* @warning The actor takes ownership of @p ptr.
*/
bool attach(attachable_ptr ptr);
/**
* @brief Convenience function that attaches the functor
* or function @p f to this actor.
*
* The actor executes <tt>f()</tt> on exit, or immediatley
* if it already finished execution.
* @param f A functor, function or lambda expression that's executed
* if the actor finishes execution.
* @returns @c true if @p f was successfully attached to the actor;
* otherwise (actor already exited) @p false.
*/
template<typename F>
bool attach_functor(F&& f);
/**
* @brief Returns the address of this actor.
*/
actor_addr address() const;
/**
* @brief Detaches the first attached object that matches @p what.
*/
void detach(const attachable::token& what);
/**
* @brief Links this actor to @p other.
* @param other Actor instance that whose execution is coupled to the
* execution of this Actor.
*/
virtual void link_to(const actor_addr& other);
/**
* @brief Unlinks this actor from @p other.
* @param other Linked Actor.
* @note Links are automatically removed if the actor finishes execution.
*/
virtual void unlink_from(const actor_addr& other);
/**
* @brief Establishes a link relation between this actor and @p other.
* @param other Actor instance that wants to link against this Actor.
* @returns @c true if this actor is running and added @p other to its
* list of linked actors; otherwise @c false.
*/
virtual bool establish_backlink(const actor_addr& other);
/**
* @brief Removes a link relation between this actor and @p other.
* @param other Actor instance that wants to unlink from this Actor.
* @returns @c true if this actor is running and removed @p other
* from its list of linked actors; otherwise @c false.
*/
virtual bool remove_backlink(const actor_addr& other);
/**
* @brief Gets an integer value that uniquely identifies this Actor in
* the process it's executed in.
* @returns The unique identifier of this actor.
*/
inline actor_id id() const;
/**
* @brief Checks if this actor is running on a remote node.
* @returns @c true if this actor represents a remote actor;
* otherwise @c false.
*/
inline bool is_proxy() const;
/**
* @brief Returns the ID of the node this actor is running on.
*/
inline const node_id& node() const;
protected:
abstract_actor();
abstract_actor(actor_id aid);
/**
* @brief Should be overridden by subtypes and called upon termination.
* @note Default implementation sets 'exit_reason' accordingly.
* @note Overridden functions should always call super::cleanup().
*/
virtual void cleanup(std::uint32_t reason);
/**
* @brief The default implementation for {@link link_to()}.
*/
bool link_to_impl(const actor_addr& other);
/**
* @brief The default implementation for {@link unlink_from()}.
*/
bool unlink_from_impl(const actor_addr& other);
/**
* @brief Returns the actor's exit reason of
* <tt>exit_reason::not_exited</tt> if it's still alive.
*/
inline std::uint32_t exit_reason() const;
/**
* @brief Returns <tt>exit_reason() != exit_reason::not_exited</tt>.
*/
inline bool exited() const;
// cannot be changed after construction
const actor_id m_id;
// you're either a proxy or you're not
const bool m_is_proxy;
private:
// initially exit_reason::not_exited
std::atomic<std::uint32_t> m_exit_reason;
// guards access to m_exit_reason, m_attachables, and m_links
std::mutex m_mtx;
// links to other actors
std::vector<abstract_actor_ptr> m_links;
// attached functors that are executed on cleanup
std::vector<attachable_ptr> m_attachables;
// identifies the node this actor is running on
node_id_ptr m_node;
};
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
inline std::uint32_t abstract_actor::id() const {
return m_id;
}
inline bool abstract_actor::is_proxy() const {
return m_is_proxy;
}
inline std::uint32_t abstract_actor::exit_reason() const {
return m_exit_reason;
}
inline bool abstract_actor::exited() const {
return exit_reason() != exit_reason::not_exited;
}
template<class F>
struct functor_attachable : attachable {
F m_functor;
template<typename T>
inline functor_attachable(T&& arg) : m_functor(std::forward<T>(arg)) { }
void actor_exited(std::uint32_t reason) { m_functor(reason); }
bool matches(const attachable::token&) { return false; }
};
template<typename F>
bool abstract_actor::attach_functor(F&& f) {
typedef typename util::rm_const_and_ref<F>::type f_type;
typedef functor_attachable<f_type> impl;
return attach(attachable_ptr{new impl(std::forward<F>(f))});
}
inline const node_id& abstract_actor::node() const {
return *m_node;
}
} // namespace cppa
#endif // CPPA_ABSTRACT_ACTOR_HPP
...@@ -28,52 +28,38 @@ ...@@ -28,52 +28,38 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_FACTORY_HPP #ifndef CPPA_ABSTRACT_CHANNEL_HPP
#define CPPA_FACTORY_HPP #define CPPA_ABSTRACT_CHANNEL_HPP
#include "cppa/detail/event_based_actor_factory.hpp" #include "cppa/ref_counted.hpp"
namespace cppa { namespace factory { namespace cppa {
void default_cleanup(); // forward declarations
class any_tuple;
class message_header;
/** /**
* @brief Returns a factory for event-based actors using @p fun as * @brief Interface for all message receivers.
* implementation for {@link cppa::event_based_actor::init() init()}.
* *
* @p fun must take pointer arguments only. The factory creates an event-based * This interface describes an entity that can receive messages
* actor implementation with member variables according to the functor's * and is implemented by {@link actor} and {@link group}.
* signature, as shown in the example below.
*
* @code
* auto f = factory::event_based([](int* a, int* b) { ... });
* auto actor1 = f.spawn();
* auto actor2 = f.spawn(1);
* auto actor3 = f.spawn(1, 2);
* @endcode
*
* The arguments @p a and @p b will point to @p int member variables of the
* actor. All member variables are initialized using the default constructor
* unless an initial value is passed to @p spawn.
*/ */
template<typename InitFun> class abstract_channel : public ref_counted {
inline typename detail::ebaf_from_functor<InitFun, void (*)()>::type
event_based(InitFun init) {
return {std::move(init), default_cleanup};
}
/** public:
* @brief Returns a factory for event-based actors using @p fun0 as
* implementation for {@link cppa::event_based_actor::init() init()} /**
* and @p fun1 as implementation for * @brief Enqueues @p msg to the list of received messages.
* {@link cppa::event_based_actor::on_exit() on_exit()}. */
*/ virtual void enqueue(const message_header& hdr, any_tuple msg) = 0;
template<typename InitFun, typename OnExitFun>
inline typename detail::ebaf_from_functor<InitFun, OnExitFun>::type protected:
event_based(InitFun init, OnExitFun on_exit) {
return {std::move(init), on_exit}; virtual ~abstract_channel();
}
};
} } // namespace cppa::factory } // namespace cppa
#endif // CPPA_FACTORY_HPP #endif // CPPA_ABSTRACT_CHANNEL_HPP
...@@ -31,227 +31,60 @@ ...@@ -31,227 +31,60 @@
#ifndef CPPA_ACTOR_HPP #ifndef CPPA_ACTOR_HPP
#define CPPA_ACTOR_HPP #define CPPA_ACTOR_HPP
#include <mutex>
#include <atomic>
#include <memory>
#include <vector>
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "cppa/group.hpp"
#include "cppa/channel.hpp"
#include "cppa/cppa_fwd.hpp"
#include "cppa/attachable.hpp"
#include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/comparable.hpp"
namespace cppa { namespace cppa {
class actor; class channel;
class self_type; class any_tuple;
class serializer; class actor_addr;
class deserializer; class local_actor;
class message_header;
/** /**
* @brief A unique actor ID. * @brief Identifies an untyped actor.
* @relates actor
*/ */
typedef std::uint32_t actor_id; class actor : util::comparable<actor> {
/** friend class channel;
* @brief A smart pointer type that manages instances of {@link actor}. friend class actor_addr;
* @relates actor friend class local_actor;
*/
typedef intrusive_ptr<actor> actor_ptr;
/**
* @brief Base class for all actor implementations.
*/
class actor : public channel {
public: public:
/** actor() = default;
* @brief Attaches @p ptr to this actor.
*
* The actor will call <tt>ptr->detach(...)</tt> on exit, or immediately
* if it already finished execution.
* @param ptr A callback object that's executed if the actor finishes
* execution.
* @returns @c true if @p ptr was successfully attached to the actor;
* otherwise (actor already exited) @p false.
* @warning The actor takes ownership of @p ptr.
*/
bool attach(attachable_ptr ptr);
/**
* @brief Convenience function that attaches the functor
* or function @p f to this actor.
*
* The actor executes <tt>f()</tt> on exit, or immediatley
* if it already finished execution.
* @param f A functor, function or lambda expression that's executed
* if the actor finishes execution.
* @returns @c true if @p f was successfully attached to the actor;
* otherwise (actor already exited) @p false.
*/
template<typename F>
bool attach_functor(F&& f);
/**
* @brief Detaches the first attached object that matches @p what.
*/
void detach(const attachable::token& what);
/**
* @brief Links this actor to @p other.
* @param other Actor instance that whose execution is coupled to the
* execution of this Actor.
*/
virtual void link_to(const actor_ptr& other);
/**
* @brief Unlinks this actor from @p other.
* @param other Linked Actor.
* @note Links are automatically removed if the actor finishes execution.
*/
virtual void unlink_from(const actor_ptr& other);
/** template<typename T>
* @brief Establishes a link relation between this actor and @p other. actor(intrusive_ptr<T> ptr, typename std::enable_if<std::is_base_of<abstract_actor, T>::value>::type* = 0) : m_ptr(ptr) { }
* @param other Actor instance that wants to link against this Actor.
* @returns @c true if this actor is running and added @p other to its
* list of linked actors; otherwise @c false.
*/
virtual bool establish_backlink(const actor_ptr& other);
/**
* @brief Removes a link relation between this actor and @p other.
* @param other Actor instance that wants to unlink from this Actor.
* @returns @c true if this actor is running and removed @p other
* from its list of linked actors; otherwise @c false.
*/
virtual bool remove_backlink(const actor_ptr& other);
/**
* @brief Gets an integer value that uniquely identifies this Actor in
* the process it's executed in.
* @returns The unique identifier of this actor.
*/
inline actor_id id() const;
/**
* @brief Checks if this actor is running on a remote node.
* @returns @c true if this actor represents a remote actor;
* otherwise @c false.
*/
inline bool is_proxy() const;
protected:
actor();
actor(actor_id aid); actor(abstract_actor*);
/** actor_id id() const;
* @brief Should be overridden by subtypes and called upon termination.
* @note Default implementation sets 'exit_reason' accordingly.
* @note Overridden functions should always call super::cleanup().
*/
virtual void cleanup(std::uint32_t reason);
/** actor_addr address() const;
* @brief The default implementation for {@link link_to()}.
*/
bool link_to_impl(const actor_ptr& other);
/** explicit operator bool() const;
* @brief The default implementation for {@link unlink_from()}.
*/
bool unlink_from_impl(const actor_ptr& other);
/** bool operator!() const;
* @brief Returns the actor's exit reason of
* <tt>exit_reason::not_exited</tt> if it's still alive.
*/
inline std::uint32_t exit_reason() const;
/** void enqueue(const message_header& hdr, any_tuple msg) const;
* @brief Returns <tt>exit_reason() != exit_reason::not_exited</tt>.
*/
inline bool exited() const;
// cannot be changed after construction bool is_remote() const;
const actor_id m_id;
// you're either a proxy or you're not intptr_t compare(const actor& other) const;
const bool m_is_proxy;
private: private:
// initially exit_reason::not_exited intrusive_ptr<abstract_actor> m_ptr;
std::atomic<std::uint32_t> m_exit_reason;
// guards access to m_exit_reason, m_attachables, and m_links
std::mutex m_mtx;
// links to other actors
std::vector<actor_ptr> m_links;
// attached functors that are executed on cleanup
std::vector<attachable_ptr> m_attachables;
}; };
// undocumented, because self_type is hidden in documentation
bool operator==(const actor_ptr&, const self_type&);
bool operator!=(const self_type&, const actor_ptr&);
/******************************************************************************
* inline and template member function implementations *
******************************************************************************/
inline std::uint32_t actor::id() const {
return m_id;
}
inline bool actor::is_proxy() const {
return m_is_proxy;
}
inline std::uint32_t actor::exit_reason() const {
return m_exit_reason;
}
inline bool actor::exited() const {
return exit_reason() != exit_reason::not_exited;
}
template<class F>
struct functor_attachable : attachable {
F m_functor;
template<typename T>
inline functor_attachable(T&& arg) : m_functor(std::forward<T>(arg)) { }
void actor_exited(std::uint32_t reason) { m_functor(reason); }
bool matches(const attachable::token&) { return false; }
};
template<typename F>
bool actor::attach_functor(F&& f) {
typedef typename util::rm_const_and_ref<F>::type f_type;
typedef functor_attachable<f_type> impl;
return attach(attachable_ptr{new impl(std::forward<F>(f))});
}
} // namespace cppa } // namespace cppa
#endif // CPPA_ACTOR_HPP #endif // CPPA_ACTOR_HPP
...@@ -25,135 +25,86 @@ ...@@ -25,135 +25,86 @@
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_SELF_HPP #ifndef CPPA_ACTOR_ADDR_HPP
#define CPPA_SELF_HPP #define CPPA_ACTOR_ADDR_HPP
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include "cppa/actor.hpp"
#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/util/comparable.hpp"
namespace cppa { namespace cppa {
#ifdef CPPA_DOCUMENTATION class actor;
class node_id;
/** class actor_addr;
* @brief Always points to the current actor. Similar to @c this in
* an object-oriented context.
*/
extern local_actor* self;
#else // CPPA_DOCUMENTATION
class local_actor; class local_actor;
// convertible<...> enables "actor_ptr this_actor = self;" namespace detail { template<typename T> T* actor_addr_cast(const actor_addr&); }
class self_type : public convertible<self_type, actor*>,
public convertible<self_type, channel*> {
self_type(const self_type&) = delete; constexpr struct invalid_actor_addr_t { constexpr invalid_actor_addr_t() { } } invalid_actor_addr;
self_type& operator=(const self_type&) = delete;
public: class actor_addr : util::comparable<actor_addr>
, util::comparable<actor_addr, actor>
, util::comparable<actor_addr, local_actor*> {
typedef local_actor* pointer; friend class abstract_actor;
constexpr self_type() { } template<typename T>
friend T* detail::actor_addr_cast(const actor_addr&);
// "inherited" from convertible<...> public:
inline actor* do_convert() const {
return convert_impl();
}
inline pointer get() const { actor_addr() = default;
return get_impl(); actor_addr(actor_addr&&) = default;
} actor_addr(const actor_addr&) = default;
actor_addr& operator=(actor_addr&&) = default;
actor_addr& operator=(const actor_addr&) = default;
// allow "self" wherever an local_actor or actor pointer is expected actor_addr(const actor&);
inline operator pointer() const {
return get_impl();
}
inline pointer operator->() const { actor_addr(const invalid_actor_addr_t&);
return get_impl();
}
// @pre get_unchecked() == nullptr explicit operator bool() const;
inline void set(pointer ptr) const { bool operator!() const;
set_impl(ptr);
}
// @returns The current value without converting the calling context intptr_t compare(const actor& other) const;
// to an actor on-the-fly. intptr_t compare(const actor_addr& other) const;
inline pointer unchecked() const { intptr_t compare(const local_actor* other) const;
return get_unchecked_impl();
}
inline pointer release() const { actor_id id() const;
return release_impl();
}
inline void adopt(pointer ptr) const { const node_id& node() const;
adopt_impl(ptr);
}
static void cleanup_fun(pointer); /**
* @brief Returns whether this is an address of a
* remote actor.
*/
bool is_remote() const;
private: private:
static void set_impl(pointer); explicit actor_addr(abstract_actor*);
static pointer get_unchecked_impl(); abstract_actor_ptr m_ptr;
static pointer get_impl();
static actor* convert_impl();
static pointer release_impl();
static void adopt_impl(pointer);
}; };
/* namespace detail {
* "self" emulates a new keyword. The object itself is useless, all it does
* is to provide syntactic sugar like "self->trap_exit(true)".
*/
constexpr self_type self;
class scoped_self_setter {
scoped_self_setter(const scoped_self_setter&) = delete;
scoped_self_setter& operator=(const scoped_self_setter&) = delete;
public:
inline scoped_self_setter(local_actor* new_value) {
m_original_value = self.release();
self.adopt(new_value);
}
inline ~scoped_self_setter() {
// restore self
static_cast<void>(self.release());
self.adopt(m_original_value);
}
private:
local_actor* m_original_value;
};
// disambiguation (compiler gets confused with cast operator otherwise) template<typename T>
bool operator==(const actor_ptr& lhs, const self_type& rhs); T* actor_addr_cast(const actor_addr& addr) {
bool operator==(const self_type& lhs, const actor_ptr& rhs); return static_cast<T*>(addr.m_ptr.get());
bool operator!=(const actor_ptr& lhs, const self_type& rhs); }
bool operator!=(const self_type& lhs, const actor_ptr& rhs);
#endif // CPPA_DOCUMENTATION } // namespace detail
} // namespace cppa } // namespace cppa
#endif // CPPA_SELF_HPP #endif // CPPA_ACTOR_ADDR_HPP
...@@ -63,9 +63,9 @@ class actor_namespace { ...@@ -63,9 +63,9 @@ class actor_namespace {
inline void set_new_element_callback(new_element_callback fun); inline void set_new_element_callback(new_element_callback fun);
void write(serializer* sink, const actor_ptr& ptr); void write(serializer* sink, const actor_addr& ptr);
actor_ptr read(deserializer* source); actor_addr read(deserializer* source);
/** /**
* @brief A map that stores weak actor proxy pointers by actor ids. * @brief A map that stores weak actor proxy pointers by actor ids.
...@@ -81,13 +81,13 @@ class actor_namespace { ...@@ -81,13 +81,13 @@ class actor_namespace {
* @brief Returns the proxy instance identified by @p node and @p aid * @brief Returns the proxy instance identified by @p node and @p aid
* or @p nullptr if the actor is unknown. * or @p nullptr if the actor is unknown.
*/ */
actor_ptr get(const node_id& node, actor_id aid); actor_proxy_ptr get(const node_id& node, actor_id aid);
/** /**
* @brief Returns the proxy instance identified by @p node and @p aid * @brief Returns the proxy instance identified by @p node and @p aid
* or creates a new (default) proxy instance. * or creates a new (default) proxy instance.
*/ */
actor_ptr get_or_put(node_id_ptr node, actor_id aid); actor_proxy_ptr get_or_put(node_id_ptr node, actor_id aid);
/** /**
* @brief Stores @p proxy in the list of known actor proxies. * @brief Stores @p proxy in the list of known actor proxies.
......
...@@ -31,8 +31,9 @@ ...@@ -31,8 +31,9 @@
#ifndef CPPA_ACTOR_PROXY_HPP #ifndef CPPA_ACTOR_PROXY_HPP
#define CPPA_ACTOR_PROXY_HPP #define CPPA_ACTOR_PROXY_HPP
#include "cppa/actor.hpp"
#include "cppa/extend.hpp" #include "cppa/extend.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/message_header.hpp" #include "cppa/message_header.hpp"
#include "cppa/enable_weak_ptr.hpp" #include "cppa/enable_weak_ptr.hpp"
#include "cppa/weak_intrusive_ptr.hpp" #include "cppa/weak_intrusive_ptr.hpp"
...@@ -45,7 +46,7 @@ class actor_proxy_cache; ...@@ -45,7 +46,7 @@ class actor_proxy_cache;
* @brief Represents a remote actor. * @brief Represents a remote actor.
* @extends actor * @extends actor
*/ */
class actor_proxy : public extend<actor>::with<enable_weak_ptr> { class actor_proxy : public extend<abstract_actor>::with<enable_weak_ptr> {
typedef combined_type super; typedef combined_type super;
...@@ -55,12 +56,12 @@ class actor_proxy : public extend<actor>::with<enable_weak_ptr> { ...@@ -55,12 +56,12 @@ class actor_proxy : public extend<actor>::with<enable_weak_ptr> {
* @brief Establishes a local link state that's not synchronized back * @brief Establishes a local link state that's not synchronized back
* to the remote instance. * to the remote instance.
*/ */
virtual void local_link_to(const intrusive_ptr<actor>& other) = 0; virtual void local_link_to(const actor_addr& other) = 0;
/** /**
* @brief Removes a local link state. * @brief Removes a local link state.
*/ */
virtual void local_unlink_from(const actor_ptr& other) = 0; virtual void local_unlink_from(const actor_addr& other) = 0;
/** /**
* @brief Delivers given message via this proxy instance. * @brief Delivers given message via this proxy instance.
......
...@@ -91,7 +91,7 @@ class any_tuple { ...@@ -91,7 +91,7 @@ class any_tuple {
* @brief Creates a tuple from a set of values. * @brief Creates a tuple from a set of values.
*/ */
template<typename T, typename... Ts> template<typename T, typename... Ts>
any_tuple(T v0, Ts&&... vs) explicit any_tuple(T v0, Ts&&... vs)
: m_vals(make_cow_tuple(std::move(v0), std::forward<Ts>(vs)...).vals()) { } : m_vals(make_cow_tuple(std::move(v0), std::forward<Ts>(vs)...).vals()) { }
/** /**
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_BLOCKING_UNTYPED_ACTOR_HPP
#define CPPA_BLOCKING_UNTYPED_ACTOR_HPP
#include "cppa/extend.hpp"
#include "cppa/stacked.hpp"
#include "cppa/local_actor.hpp"
namespace cppa {
class untyped_actor : extend<local_actor>::with<stacked> {
};
} // namespace cppa
#endif // CPPA_BLOCKING_UNTYPED_ACTOR_HPP
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_CHANNEL_HPP #ifndef CPPA_CHANNEL_HPP
...@@ -33,68 +33,53 @@ ...@@ -33,68 +33,53 @@
#include <type_traits> #include <type_traits>
#include "cppa/ref_counted.hpp"
#include "cppa/intrusive_ptr.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/abstract_channel.hpp"
#include "cppa/util/comparable.hpp"
namespace cppa { namespace cppa {
// forward declarations
class actor; class actor;
class group;
class any_tuple; class any_tuple;
class message_header; class message_header;
typedef intrusive_ptr<actor> actor_ptr;
/** /**
* @brief Interface for all message receivers. * @brief Interface for all message receivers.
* *
* This interface describes an entity that can receive messages * This interface describes an entity that can receive messages
* and is implemented by {@link actor} and {@link group}. * and is implemented by {@link actor} and {@link group}.
*/ */
class channel : public ref_counted { class channel : util::comparable<channel>
, util::comparable<channel, actor> {
friend class actor;
friend class group;
public: public:
/** channel() = default;
* @brief Enqueues @p msg to the list of received messages.
*/ template<typename T>
virtual void enqueue(const message_header& hdr, any_tuple msg) = 0; channel(intrusive_ptr<T> ptr, typename std::enable_if<std::is_base_of<abstract_channel, T>::value>::type* = 0) : m_ptr(ptr) { }
channel(abstract_channel*);
/**
* @brief Enqueues @p msg to the list of received messages and returns explicit operator bool() const;
* true if this is an scheduled actor that successfully changed
* its state to @p pending in response to the enqueue operation. bool operator!() const;
*/
virtual bool chained_enqueue(const message_header& hdr, any_tuple msg); void enqueue(const message_header& hdr, any_tuple msg) const;
/** intptr_t compare(const channel& other) const;
* @brief Sets the state from @p pending to @p ready.
*/ intptr_t compare(const actor& other) const;
virtual void unchain();
static intptr_t compare(const abstract_channel* lhs, const abstract_channel* rhs);
protected:
private:
virtual ~channel();
intrusive_ptr<abstract_channel> m_ptr;
}; };
/**
* @brief A smart pointer type that manages instances of {@link channel}.
* @relates channel
*/
typedef intrusive_ptr<channel> channel_ptr;
/**
* @brief Convenience alias.
*/
template<typename T, typename R = void>
using enable_if_channel = std::enable_if<std::is_base_of<channel, T>::value, R>;
} // namespace cppa } // namespace cppa
#endif // CPPA_CHANNEL_HPP #endif // CPPA_CHANNEL_HPP
...@@ -62,7 +62,7 @@ class context_switching_actor : public extend<scheduled_actor, context_switching ...@@ -62,7 +62,7 @@ class context_switching_actor : public extend<scheduled_actor, context_switching
*/ */
context_switching_actor(std::function<void()> fun); context_switching_actor(std::function<void()> fun);
resume_result resume(util::fiber* from, actor_ptr& next_job); resume_result resume(util::fiber* from);
scheduled_actor_type impl_type(); scheduled_actor_type impl_type();
......
...@@ -37,7 +37,6 @@ ...@@ -37,7 +37,6 @@
#include <type_traits> #include <type_traits>
#include "cppa/get.hpp" #include "cppa/get.hpp"
#include "cppa/actor.hpp"
#include "cppa/cow_ptr.hpp" #include "cppa/cow_ptr.hpp"
#include "cppa/ref_counted.hpp" #include "cppa/ref_counted.hpp"
......
...@@ -40,14 +40,9 @@ ...@@ -40,14 +40,9 @@
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
#include "cppa/send.hpp"
#include "cppa/self.hpp"
#include "cppa/actor.hpp"
#include "cppa/match.hpp" #include "cppa/match.hpp"
#include "cppa/spawn.hpp" #include "cppa/spawn.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/receive.hpp"
#include "cppa/factory.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/announce.hpp" #include "cppa/announce.hpp"
#include "cppa/sb_actor.hpp" #include "cppa/sb_actor.hpp"
...@@ -63,9 +58,9 @@ ...@@ -63,9 +58,9 @@
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/prioritizing.hpp" #include "cppa/prioritizing.hpp"
#include "cppa/spawn_options.hpp" #include "cppa/spawn_options.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/message_future.hpp" #include "cppa/message_future.hpp"
#include "cppa/response_handle.hpp" #include "cppa/response_handle.hpp"
#include "cppa/typed_actor_ptr.hpp"
#include "cppa/scheduled_actor.hpp" #include "cppa/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
...@@ -84,7 +79,6 @@ ...@@ -84,7 +79,6 @@
#include "cppa/detail/memory.hpp" #include "cppa/detail/memory.hpp"
#include "cppa/detail/get_behavior.hpp" #include "cppa/detail/get_behavior.hpp"
#include "cppa/detail/actor_registry.hpp" #include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/receive_loop_helper.hpp"
/** /**
* @author Dominik Charousset <dominik.charousset (at) haw-hamburg.de> * @author Dominik Charousset <dominik.charousset (at) haw-hamburg.de>
...@@ -440,47 +434,32 @@ ...@@ -440,47 +434,32 @@
namespace cppa { namespace cppa {
/** template<typename T, typename... Ts>
* @ingroup MessageHandling typename std::enable_if<std::is_base_of<channel, T>::value>::type
* @{ send_tuple_as(const actor& from, const intrusive_ptr<T>& to, any_tuple msg) {
*/ to->enqueue({from.address(), to}, std::move(msg));
/**
* @brief Sends a message to @p whom.
*
* <b>Usage example:</b>
* @code
* self << make_any_tuple(1, 2, 3);
* @endcode
* @param whom Receiver of the message.
* @param what Message as instance of {@link any_tuple}.
* @returns @p whom.
*/
template<class C>
inline typename enable_if_channel<C, const intrusive_ptr<C>&>::type
operator<<(const intrusive_ptr<C>& whom, any_tuple what) {
send_tuple(whom, std::move(what));
return whom;
} }
inline const self_type& operator<<(const self_type& s, any_tuple what) { template<typename T, typename... Ts>
send_tuple(s.get(), std::move(what)); typename std::enable_if<std::is_base_of<channel, T>::value>::type
return s; send_as(const actor& from, const intrusive_ptr<T>& to, Ts&&... args) {
send_tuple_as(from, to, make_any_tuple(std::forward<Ts>(args)...));
} }
/** void send_tuple_as(const actor& from, const actor& to, any_tuple msg);
* @}
*/
template<typename... Ts>
void send_as(const actor& from, const actor& to, Ts&&... args) {
send_tuple_as(from, to, make_any_tuple(std::forward<Ts>(args)...));
}
/** /**
* @brief Blocks execution of this actor until all * @brief Blocks execution of this actor until all
* other actors finished execution. * other actors finished execution.
* @warning This function will cause a deadlock if called from multiple actors. * @warning This function will cause a deadlock if called from multiple actors.
* @warning Do not call this function in cooperatively scheduled actors. * @warning Do not call this function in cooperatively scheduled actors.
*/ */
inline void await_all_others_done() { inline void await_all_actors_done() {
auto value = (self.unchecked() == nullptr) ? 0 : 1; get_actor_registry()->await_running_count_equal(0);
get_actor_registry()->await_running_count_equal(value);
} }
/** /**
...@@ -493,7 +472,7 @@ inline void await_all_others_done() { ...@@ -493,7 +472,7 @@ inline void await_all_others_done() {
* @p nullptr. * @p nullptr.
* @throws bind_failure * @throws bind_failure
*/ */
void publish(actor_ptr whom, std::uint16_t port, const char* addr = nullptr); void publish(actor whom, std::uint16_t port, const char* addr = nullptr);
/** /**
* @brief Publishes @p whom using @p acceptor to handle incoming connections. * @brief Publishes @p whom using @p acceptor to handle incoming connections.
...@@ -502,7 +481,7 @@ void publish(actor_ptr whom, std::uint16_t port, const char* addr = nullptr); ...@@ -502,7 +481,7 @@ void publish(actor_ptr whom, std::uint16_t port, const char* addr = nullptr);
* @param whom Actor that should be published at @p port. * @param whom Actor that should be published at @p port.
* @param acceptor Network technology-specific acceptor implementation. * @param acceptor Network technology-specific acceptor implementation.
*/ */
void publish(actor_ptr whom, std::unique_ptr<io::acceptor> acceptor); void publish(actor whom, std::unique_ptr<io::acceptor> acceptor);
/** /**
* @brief Establish a new connection to the actor at @p host on given @p port. * @brief Establish a new connection to the actor at @p host on given @p port.
...@@ -511,12 +490,12 @@ void publish(actor_ptr whom, std::unique_ptr<io::acceptor> acceptor); ...@@ -511,12 +490,12 @@ void publish(actor_ptr whom, std::unique_ptr<io::acceptor> acceptor);
* @returns An {@link actor_ptr} to the proxy instance * @returns An {@link actor_ptr} to the proxy instance
* representing a remote actor. * representing a remote actor.
*/ */
actor_ptr remote_actor(const char* host, std::uint16_t port); actor remote_actor(const char* host, std::uint16_t port);
/** /**
* @copydoc remote_actor(const char*, std::uint16_t) * @copydoc remote_actor(const char*, std::uint16_t)
*/ */
inline actor_ptr remote_actor(const std::string& host, std::uint16_t port) { inline actor remote_actor(const std::string& host, std::uint16_t port) {
return remote_actor(host.c_str(), port); return remote_actor(host.c_str(), port);
} }
...@@ -527,7 +506,7 @@ inline actor_ptr remote_actor(const std::string& host, std::uint16_t port) { ...@@ -527,7 +506,7 @@ inline actor_ptr remote_actor(const std::string& host, std::uint16_t port) {
* @returns An {@link actor_ptr} to the proxy instance * @returns An {@link actor_ptr} to the proxy instance
* representing a remote actor. * representing a remote actor.
*/ */
actor_ptr remote_actor(io::stream_ptr_pair connection); actor remote_actor(io::stream_ptr_pair connection);
/** /**
* @brief Spawns an IO actor of type @p Impl. * @brief Spawns an IO actor of type @p Impl.
...@@ -537,9 +516,9 @@ actor_ptr remote_actor(io::stream_ptr_pair connection); ...@@ -537,9 +516,9 @@ actor_ptr remote_actor(io::stream_ptr_pair connection);
* @returns An {@link actor_ptr} to the spawned {@link actor}. * @returns An {@link actor_ptr} to the spawned {@link actor}.
*/ */
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts> template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn_io(io::input_stream_ptr in, actor spawn_io(io::input_stream_ptr in,
io::output_stream_ptr out, io::output_stream_ptr out,
Ts&&... args) { Ts&&... args) {
using namespace io; using namespace io;
using namespace std; using namespace std;
auto ptr = make_counted<Impl>(move(in), move(out), forward<Ts>(args)...); auto ptr = make_counted<Impl>(move(in), move(out), forward<Ts>(args)...);
...@@ -555,10 +534,10 @@ actor_ptr spawn_io(io::input_stream_ptr in, ...@@ -555,10 +534,10 @@ actor_ptr spawn_io(io::input_stream_ptr in,
template<spawn_options Options = no_spawn_options, template<spawn_options Options = no_spawn_options,
typename F = std::function<void (io::broker*)>, typename F = std::function<void (io::broker*)>,
typename... Ts> typename... Ts>
actor_ptr spawn_io(F fun, actor spawn_io(F fun,
io::input_stream_ptr in, io::input_stream_ptr in,
io::output_stream_ptr out, io::output_stream_ptr out,
Ts&&... args) { Ts&&... args) {
using namespace std; using namespace std;
auto ptr = io::broker::from(move(fun), move(in), move(out), auto ptr = io::broker::from(move(fun), move(in), move(out),
forward<Ts>(args)...); forward<Ts>(args)...);
...@@ -576,7 +555,7 @@ actor_ptr spawn_io(const char* host, uint16_t port, Ts&&... args) { ...@@ -576,7 +555,7 @@ actor_ptr spawn_io(const char* host, uint16_t port, Ts&&... args) {
template<spawn_options Options = no_spawn_options, template<spawn_options Options = no_spawn_options,
typename F = std::function<void (io::broker*)>, typename F = std::function<void (io::broker*)>,
typename... Ts> typename... Ts>
actor_ptr spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) { actor spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) {
auto ptr = io::ipv4_io_stream::connect_to(host.c_str(), port); auto ptr = io::ipv4_io_stream::connect_to(host.c_str(), port);
return spawn_io(std::move(fun), ptr, ptr, std::forward<Ts>(args)...); return spawn_io(std::move(fun), ptr, ptr, std::forward<Ts>(args)...);
} }
...@@ -584,7 +563,7 @@ actor_ptr spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args) ...@@ -584,7 +563,7 @@ actor_ptr spawn_io(F fun, const std::string& host, uint16_t port, Ts&&... args)
template<spawn_options Options = no_spawn_options, template<spawn_options Options = no_spawn_options,
typename F = std::function<void (io::broker*)>, typename F = std::function<void (io::broker*)>,
typename... Ts> typename... Ts>
actor_ptr spawn_io_server(F fun, uint16_t port, Ts&&... args) { actor spawn_io_server(F fun, uint16_t port, Ts&&... args) {
using namespace std; using namespace std;
auto ptr = io::broker::from(move(fun), io::ipv4_acceptor::create(port), auto ptr = io::broker::from(move(fun), io::ipv4_acceptor::create(port),
forward<Ts>(args)...); forward<Ts>(args)...);
...@@ -599,33 +578,6 @@ actor_ptr spawn_io_server(F fun, uint16_t port, Ts&&... args) { ...@@ -599,33 +578,6 @@ actor_ptr spawn_io_server(F fun, uint16_t port, Ts&&... args) {
*/ */
void shutdown(); // note: implemented in singleton_manager.cpp void shutdown(); // note: implemented in singleton_manager.cpp
/**
* @brief Sets the actor's behavior and discards the previous behavior
* unless {@link keep_behavior} is given as first argument.
*/
template<typename T, typename... Ts>
inline typename std::enable_if<
!is_behavior_policy<typename util::rm_const_and_ref<T>::type>::value,
void
>::type
become(T&& arg, Ts&&... args) {
self->do_become(match_expr_convert(std::forward<T>(arg),
std::forward<Ts>(args)...),
true);
}
template<bool Discard, typename... Ts>
inline void become(behavior_policy<Discard>, Ts&&... args) {
self->do_become(match_expr_convert(std::forward<Ts>(args)...), Discard);
}
/**
* @brief Returns to a previous behavior if available.
*/
inline void unbecome() {
self->do_unbecome();
}
struct actor_ostream { struct actor_ostream {
typedef const actor_ostream& (*fun_type)(const actor_ostream&); typedef const actor_ostream& (*fun_type)(const actor_ostream&);
...@@ -633,12 +585,12 @@ struct actor_ostream { ...@@ -633,12 +585,12 @@ struct actor_ostream {
constexpr actor_ostream() { } constexpr actor_ostream() { }
inline const actor_ostream& write(std::string arg) const { inline const actor_ostream& write(std::string arg) const {
send(get_scheduler()->printer(), atom("add"), move(arg)); send_as(nullptr, get_scheduler()->printer(), atom("add"), move(arg));
return *this; return *this;
} }
inline const actor_ostream& flush() const { inline const actor_ostream& flush() const {
send(get_scheduler()->printer(), atom("flush")); send_as(nullptr, get_scheduler()->printer(), atom("flush"));
return *this; return *this;
} }
...@@ -678,9 +630,9 @@ inline const actor_ostream& operator<<(const actor_ostream& o, actor_ostream::fu ...@@ -678,9 +630,9 @@ inline const actor_ostream& operator<<(const actor_ostream& o, actor_ostream::fu
namespace std { namespace std {
// allow actor_ptr to be used in hash maps // allow actor_ptr to be used in hash maps
template<> template<>
struct hash<cppa::actor_ptr> { struct hash<cppa::actor> {
inline size_t operator()(const cppa::actor_ptr& ptr) const { inline size_t operator()(const cppa::actor& ref) const {
return (ptr) ? static_cast<size_t>(ptr->id()) : 0; return static_cast<size_t>(ref.id());
} }
}; };
// provide convenience overlaods for aout; implemented in logging.cpp // provide convenience overlaods for aout; implemented in logging.cpp
......
...@@ -39,15 +39,16 @@ namespace cppa { ...@@ -39,15 +39,16 @@ namespace cppa {
class actor; class actor;
class group; class group;
class channel; class channel;
class node_id;
class behavior; class behavior;
class any_tuple; class any_tuple;
class self_type; class self_type;
class actor_proxy; class actor_proxy;
class abstract_actor;
class message_header; class message_header;
class partial_function; class partial_function;
class uniform_type_info; class uniform_type_info;
class primitive_variant; class primitive_variant;
class node_id;
// structs // structs
struct anything; struct anything;
...@@ -62,11 +63,9 @@ template<typename> class intrusive_ptr; ...@@ -62,11 +63,9 @@ template<typename> class intrusive_ptr;
template<typename> class weak_intrusive_ptr; template<typename> class weak_intrusive_ptr;
// intrusive pointer typedefs // intrusive pointer typedefs
typedef intrusive_ptr<actor> actor_ptr;
typedef intrusive_ptr<group> group_ptr; typedef intrusive_ptr<group> group_ptr;
typedef intrusive_ptr<channel> channel_ptr;
typedef intrusive_ptr<actor_proxy> actor_proxy_ptr; typedef intrusive_ptr<actor_proxy> actor_proxy_ptr;
typedef intrusive_ptr<node_id> node_id_ptr; typedef intrusive_ptr<node_id> node_id_ptr;
// weak intrusive pointer typedefs // weak intrusive pointer typedefs
typedef weak_intrusive_ptr<actor_proxy> weak_actor_proxy_ptr; typedef weak_intrusive_ptr<actor_proxy> weak_actor_proxy_ptr;
......
...@@ -38,8 +38,8 @@ ...@@ -38,8 +38,8 @@
#include <cstdint> #include <cstdint>
#include <condition_variable> #include <condition_variable>
#include "cppa/actor.hpp"
#include "cppa/attachable.hpp" #include "cppa/attachable.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/util/shared_spinlock.hpp" #include "cppa/util/shared_spinlock.hpp"
#include "cppa/detail/singleton_mixin.hpp" #include "cppa/detail/singleton_mixin.hpp"
...@@ -59,7 +59,7 @@ class actor_registry : public singleton_mixin<actor_registry> { ...@@ -59,7 +59,7 @@ class actor_registry : public singleton_mixin<actor_registry> {
* exit reason. An entry with a nullptr means the actor has finished * exit reason. An entry with a nullptr means the actor has finished
* execution for given reason. * execution for given reason.
*/ */
typedef std::pair<actor_ptr, std::uint32_t> value_type; typedef std::pair<abstract_actor_ptr, std::uint32_t> value_type;
/** /**
* @brief Returns the {nullptr, invalid_exit_reason}. * @brief Returns the {nullptr, invalid_exit_reason}.
...@@ -67,11 +67,11 @@ class actor_registry : public singleton_mixin<actor_registry> { ...@@ -67,11 +67,11 @@ class actor_registry : public singleton_mixin<actor_registry> {
value_type get_entry(actor_id key) const; value_type get_entry(actor_id key) const;
// return nullptr if the actor wasn't put *or* finished execution // return nullptr if the actor wasn't put *or* finished execution
inline actor_ptr get(actor_id key) const { inline abstract_actor_ptr get(actor_id key) const {
return get_entry(key).first; return get_entry(key).first;
} }
void put(actor_id key, const actor_ptr& value); void put(actor_id key, const abstract_actor_ptr& value);
void erase(actor_id key, std::uint32_t reason); void erase(actor_id key, std::uint32_t reason);
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_EVENT_BASED_ACTOR_FACTORY_HPP
#define CPPA_EVENT_BASED_ACTOR_FACTORY_HPP
#include <type_traits>
#include "cppa/scheduler.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/detail/tdata.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/util/type_list.hpp"
namespace cppa { namespace detail {
template<typename InitFun, typename CleanupFun, typename... Members>
class event_based_actor_impl : public event_based_actor {
public:
template<typename... Ts>
event_based_actor_impl(InitFun fun, CleanupFun cfun, Ts&&... args)
: m_init(std::move(fun)), m_on_exit(std::move(cfun))
, m_members(std::forward<Ts>(args)...) { }
void init() { apply(m_init); }
void on_exit() override {
typedef typename util::get_callable_trait<CleanupFun>::arg_types arg_types;
std::integral_constant<size_t, util::tl_size<arg_types>::value> token;
on_exit_impl(m_on_exit, token);
}
private:
InitFun m_init;
CleanupFun m_on_exit;
tdata<Members...> m_members;
template<typename F>
void apply(F& f, typename std::add_pointer<Members>::type... args) {
f(args...);
}
template<typename F, typename... Ts>
void apply(F& f, Ts... args) {
apply(f, args..., &get_ref<sizeof...(Ts)>(m_members));
}
typedef std::integral_constant<size_t, 0> zero_t;
template<typename OnExit, typename Token>
typename std::enable_if<std::is_same<Token, zero_t>::value>::type
on_exit_impl(OnExit& fun, Token) {
fun();
}
template<typename OnExit, typename Token>
typename std::enable_if<std::is_same<Token, zero_t>::value == false>::type
on_exit_impl(OnExit& fun, Token) {
apply(fun);
}
};
template<typename InitFun, typename CleanupFun, typename... Members>
class event_based_actor_factory {
public:
typedef event_based_actor_impl<InitFun, CleanupFun, Members...> impl;
event_based_actor_factory(InitFun fun, CleanupFun cfun)
: m_init(std::move(fun)), m_on_exit(std::move(cfun)) { }
template<typename... Ts>
actor_ptr spawn(Ts&&... args) {
auto ptr = make_counted<impl>(m_init, m_on_exit, std::forward<Ts>(args)...);
return get_scheduler()->exec(no_spawn_options, ptr);
}
private:
InitFun m_init;
CleanupFun m_on_exit;
};
// event-based actor factory from type list
template<typename InitFun, typename CleanupFun, class TypeList>
struct ebaf_from_type_list;
template<typename InitFun, typename CleanupFun, typename... Ts>
struct ebaf_from_type_list<InitFun, CleanupFun, util::type_list<Ts...> > {
typedef event_based_actor_factory<InitFun, CleanupFun, Ts...> type;
};
template<typename Init, typename Cleanup>
struct ebaf_from_functor {
typedef typename util::get_callable_trait<Init>::arg_types arg_types;
typedef typename util::get_callable_trait<Cleanup>::arg_types arg_types2;
static_assert(util::tl_forall<arg_types, std::is_pointer>::value,
"First functor takes non-pointer arguments");
static_assert( std::is_same<arg_types, arg_types2>::value
|| util::tl_empty<arg_types2>::value,
"Second functor must provide either the same signature "
"as the first one or must take zero arguments");
typedef typename util::tl_map<arg_types, std::remove_pointer>::type mems;
typedef typename ebaf_from_type_list<Init, Cleanup, mems>::type type;
};
} } // namespace cppa::detail
#endif // CPPA_EVENT_BASED_ACTOR_FACTORY_HPP
...@@ -34,9 +34,6 @@ ...@@ -34,9 +34,6 @@
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include "cppa/self.hpp"
#include "cppa/actor.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
namespace cppa { class local_actor; } namespace cppa { class local_actor; }
...@@ -76,7 +73,7 @@ struct implicit_conversions { ...@@ -76,7 +73,7 @@ struct implicit_conversions {
typedef typename util::replace_type< typedef typename util::replace_type<
subtype3, subtype3,
actor_ptr, actor,
std::is_convertible<T, actor*>, std::is_convertible<T, actor*>,
std::is_convertible<T, local_actor*>, std::is_convertible<T, local_actor*>,
std::is_same<self_type, T> std::is_same<self_type, T>
......
...@@ -379,7 +379,7 @@ class receive_policy { ...@@ -379,7 +379,7 @@ class receive_policy {
<< " did not reply to a " << " did not reply to a "
"synchronous request message"); "synchronous request message");
auto fhdl = fetch_response_handle(client, hdl); auto fhdl = fetch_response_handle(client, hdl);
if (fhdl.valid()) fhdl.apply(atom("VOID")); if (fhdl.valid()) fhdl.apply(make_any_tuple(atom("VOID")));
} }
} else { } else {
if ( matches<atom_value, std::uint64_t>(*res) if ( matches<atom_value, std::uint64_t>(*res)
......
...@@ -38,7 +38,7 @@ namespace cppa { namespace detail { ...@@ -38,7 +38,7 @@ namespace cppa { namespace detail {
struct scheduled_actor_dummy : scheduled_actor { struct scheduled_actor_dummy : scheduled_actor {
scheduled_actor_dummy(); scheduled_actor_dummy();
void enqueue(const message_header&, any_tuple) override; void enqueue(const message_header&, any_tuple) override;
resume_result resume(util::fiber*, actor_ptr&) override; resume_result resume(util::fiber*) override;
void quit(std::uint32_t) override; void quit(std::uint32_t) override;
void dequeue(behavior&) override; void dequeue(behavior&) override;
void dequeue_response(behavior&, message_id) override; void dequeue_response(behavior&, message_id) override;
......
...@@ -33,29 +33,22 @@ ...@@ -33,29 +33,22 @@
#include <cstdint> #include <cstdint>
#include "cppa/atom.hpp" namespace cppa {
#include "cppa/actor.hpp"
#include "cppa/any_tuple.hpp" class actor_addr;
#include "cppa/message_id.hpp" class message_id;
#include "cppa/exit_reason.hpp" class local_actor;
#include "cppa/mailbox_element.hpp" class mailbox_element;
} // namespace cppa
namespace cppa { namespace detail { namespace cppa { namespace detail {
struct sync_request_bouncer { struct sync_request_bouncer {
std::uint32_t rsn; std::uint32_t rsn;
constexpr sync_request_bouncer(std::uint32_t r) explicit sync_request_bouncer(std::uint32_t r);
: rsn(r == exit_reason::not_exited ? exit_reason::normal : r) { } void operator()(const actor_addr& sender, const message_id& mid) const;
inline void operator()(const actor_ptr& sender, const message_id& mid) const { void operator()(const mailbox_element& e) const;
CPPA_REQUIRE(rsn != exit_reason::not_exited);
if (mid.is_request() && sender != nullptr) {
sender->enqueue({nullptr, sender, mid.response_id()},
make_any_tuple(atom("EXITED"), rsn));
}
}
inline void operator()(const mailbox_element& e) const {
(*this)(e.sender, e.mid);
}
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
...@@ -47,7 +47,7 @@ class thread_pool_scheduler : public scheduler { ...@@ -47,7 +47,7 @@ class thread_pool_scheduler : public scheduler {
public: public:
using scheduler::init_callback; using scheduler::init_callback;
using scheduler::void_function; using scheduler::actor_fun;
struct worker; struct worker;
...@@ -63,7 +63,7 @@ class thread_pool_scheduler : public scheduler { ...@@ -63,7 +63,7 @@ class thread_pool_scheduler : public scheduler {
local_actor_ptr exec(spawn_options opts, scheduled_actor_ptr ptr) override; local_actor_ptr exec(spawn_options opts, scheduled_actor_ptr ptr) override;
local_actor_ptr exec(spawn_options opts, init_callback init_cb, void_function f) override; local_actor_ptr exec(spawn_options opts, init_callback init_cb, actor_fun f) override;
private: private:
......
...@@ -62,8 +62,8 @@ using mapped_type_list = util::type_list< ...@@ -62,8 +62,8 @@ using mapped_type_list = util::type_list<
bool, bool,
any_tuple, any_tuple,
atom_value, atom_value,
actor_ptr, actor,
channel_ptr, channel,
group_ptr, group_ptr,
node_id_ptr, node_id_ptr,
io::accept_handle, io::accept_handle,
......
...@@ -57,17 +57,23 @@ class event_based_actor : public extend<scheduled_actor>::with<stackless> { ...@@ -57,17 +57,23 @@ class event_based_actor : public extend<scheduled_actor>::with<stackless> {
public: public:
resume_result resume(util::fiber*, actor_ptr&); resume_result resume(util::fiber*);
/** /**
* @brief Initializes the actor. * @brief Initializes the actor.
*/ */
virtual void init() = 0; virtual behavior make_behavior() = 0;
scheduled_actor_type impl_type(); scheduled_actor_type impl_type();
static intrusive_ptr<event_based_actor> from(std::function<void()> fun); static intrusive_ptr<event_based_actor> from(std::function<void()> fun);
static intrusive_ptr<event_based_actor> from(std::function<behavior()> fun);
static intrusive_ptr<event_based_actor> from(std::function<void(event_based_actor*)> fun);
static intrusive_ptr<event_based_actor> from(std::function<behavior(event_based_actor*)> fun);
protected: protected:
event_based_actor(actor_state st = actor_state::blocked); event_based_actor(actor_state st = actor_state::blocked);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/attachable.hpp" #include "cppa/attachable.hpp"
#include "cppa/ref_counted.hpp" #include "cppa/ref_counted.hpp"
#include "cppa/abstract_channel.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
...@@ -53,7 +54,7 @@ class deserializer; ...@@ -53,7 +54,7 @@ class deserializer;
/** /**
* @brief A multicast group. * @brief A multicast group.
*/ */
class group : public channel { class group : public abstract_channel {
friend class detail::group_manager; friend class detail::group_manager;
friend class detail::peer_connection; // needs access to remote_enqueue friend class detail::peer_connection; // needs access to remote_enqueue
...@@ -77,7 +78,7 @@ class group : public channel { ...@@ -77,7 +78,7 @@ class group : public channel {
subscription() = default; subscription() = default;
subscription(subscription&&) = default; subscription(subscription&&) = default;
subscription(const channel_ptr& s, const intrusive_ptr<group>& g); subscription(const channel& s, const intrusive_ptr<group>& g);
~subscription(); ~subscription();
...@@ -85,7 +86,7 @@ class group : public channel { ...@@ -85,7 +86,7 @@ class group : public channel {
private: private:
channel_ptr m_subscriber; channel m_subscriber;
intrusive_ptr<group> m_group; intrusive_ptr<group> m_group;
}; };
...@@ -146,7 +147,7 @@ class group : public channel { ...@@ -146,7 +147,7 @@ class group : public channel {
* @returns A {@link subscription} object that unsubscribes @p who * @returns A {@link subscription} object that unsubscribes @p who
* if the lifetime of @p who ends. * if the lifetime of @p who ends.
*/ */
virtual subscription subscribe(const channel_ptr& who) = 0; virtual subscription subscribe(const channel& who) = 0;
/** /**
* @brief Get a pointer to the group associated with * @brief Get a pointer to the group associated with
...@@ -181,7 +182,7 @@ class group : public channel { ...@@ -181,7 +182,7 @@ class group : public channel {
group(module_ptr module, std::string group_id); group(module_ptr module, std::string group_id);
virtual void unsubscribe(const channel_ptr& who) = 0; virtual void unsubscribe(const channel& who) = 0;
module_ptr m_module; module_ptr m_module;
std::string m_identifier; std::string m_identifier;
......
...@@ -45,8 +45,6 @@ ...@@ -45,8 +45,6 @@
#include "cppa/io/accept_handle.hpp" #include "cppa/io/accept_handle.hpp"
#include "cppa/io/connection_handle.hpp" #include "cppa/io/connection_handle.hpp"
#include "cppa/detail/fwd.hpp"
namespace cppa { namespace io { namespace cppa { namespace io {
class broker; class broker;
...@@ -108,7 +106,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> { ...@@ -108,7 +106,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
return from_impl(std::bind(std::move(fun), return from_impl(std::bind(std::move(fun),
std::placeholders::_1, std::placeholders::_1,
hdl, hdl,
detail::fwd<Ts>(args)...), std::forward<Ts>(args)...),
std::move(in), std::move(in),
std::move(out)); std::move(out));
} }
...@@ -119,19 +117,17 @@ class broker : public extend<local_actor>::with<threadless, stackless> { ...@@ -119,19 +117,17 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
static broker_ptr from(F fun, acceptor_uptr in, T0&& arg0, Ts&&... args) { static broker_ptr from(F fun, acceptor_uptr in, T0&& arg0, Ts&&... args) {
return from(std::bind(std::move(fun), return from(std::bind(std::move(fun),
std::placeholders::_1, std::placeholders::_1,
detail::fwd<T0>(arg0), std::forward<T0>(arg0),
detail::fwd<Ts>(args)...), std::forward<Ts>(args)...),
std::move(in)); std::move(in));
} }
template<typename F, typename... Ts> template<typename F, typename... Ts>
actor_ptr fork(F fun, actor fork(F fun, connection_handle hdl, Ts&&... args) {
connection_handle hdl,
Ts&&... args) {
return this->fork_impl(std::bind(std::move(fun), return this->fork_impl(std::bind(std::move(fun),
std::placeholders::_1, std::placeholders::_1,
hdl, hdl,
detail::fwd<Ts>(args)...), std::forward<Ts>(args)...),
hdl); hdl);
} }
...@@ -160,7 +156,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> { ...@@ -160,7 +156,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
private: private:
actor_ptr fork_impl(std::function<void (broker*)> fun, actor_addr fork_impl(std::function<void (broker*)> fun,
connection_handle hdl); connection_handle hdl);
static broker_ptr from_impl(std::function<void (broker*)> fun, static broker_ptr from_impl(std::function<void (broker*)> fun,
......
...@@ -137,7 +137,7 @@ class middleman { ...@@ -137,7 +137,7 @@ class middleman {
virtual void deliver(const node_id& node, virtual void deliver(const node_id& node,
const message_header& hdr, const message_header& hdr,
any_tuple msg ) = 0; any_tuple msg ) = 0;
/** /**
* @brief This callback is invoked by {@link peer} implementations * @brief This callback is invoked by {@link peer} implementations
* and causes the middleman to disconnect from the node. * and causes the middleman to disconnect from the node.
...@@ -156,7 +156,7 @@ class middleman { ...@@ -156,7 +156,7 @@ class middleman {
* to the event loop of the middleman. * to the event loop of the middleman.
* @note This member function is thread-safe. * @note This member function is thread-safe.
*/ */
virtual void register_acceptor(const actor_ptr& pa, peer_acceptor* ptr) = 0; virtual void register_acceptor(const actor_addr& pa, peer_acceptor* ptr) = 0;
/** /**
* @brief Returns the namespace that contains all remote actors * @brief Returns the namespace that contains all remote actors
......
...@@ -123,18 +123,18 @@ class peer : public extend<continuable>::with<buffered_writing> { ...@@ -123,18 +123,18 @@ class peer : public extend<continuable>::with<buffered_writing> {
type_lookup_table m_incoming_types; type_lookup_table m_incoming_types;
type_lookup_table m_outgoing_types; type_lookup_table m_outgoing_types;
void monitor(const actor_ptr& sender, const node_id_ptr& node, actor_id aid); void monitor(const actor_addr& sender, const node_id_ptr& node, actor_id aid);
void kill_proxy(const actor_ptr& sender, const node_id_ptr& node, actor_id aid, std::uint32_t reason); void kill_proxy(const actor_addr& sender, const node_id_ptr& node, actor_id aid, std::uint32_t reason);
void link(const actor_ptr& sender, const actor_ptr& ptr); void link(const actor_addr& sender, const actor_addr& ptr);
void unlink(const actor_ptr& sender, const actor_ptr& ptr); void unlink(const actor_addr& sender, const actor_addr& ptr);
void deliver(const message_header& hdr, any_tuple msg); void deliver(const message_header& hdr, any_tuple msg);
inline void enqueue(const any_tuple& msg) { inline void enqueue(const any_tuple& msg) {
enqueue({nullptr, nullptr}, msg); enqueue({invalid_actor_addr, nullptr}, msg);
} }
void enqueue_impl(const message_header& hdr, const any_tuple& msg); void enqueue_impl(const message_header& hdr, const any_tuple& msg);
......
...@@ -49,10 +49,10 @@ class peer_acceptor : public continuable { ...@@ -49,10 +49,10 @@ class peer_acceptor : public continuable {
continue_reading_result continue_reading() override; continue_reading_result continue_reading() override;
peer_acceptor(middleman* parent, peer_acceptor(middleman* parent,
acceptor_uptr ptr, acceptor_uptr ptr,
const actor_ptr& published_actor); const actor_addr& published_actor);
inline const actor_ptr& published_actor() const { return m_pa; } inline const actor_addr& published_actor() const { return m_pa; }
void dispose() override; void dispose() override;
...@@ -62,7 +62,7 @@ class peer_acceptor : public continuable { ...@@ -62,7 +62,7 @@ class peer_acceptor : public continuable {
middleman* m_parent; middleman* m_parent;
acceptor_uptr m_ptr; acceptor_uptr m_ptr;
actor_ptr m_pa; actor_addr m_pa;
}; };
......
...@@ -57,13 +57,13 @@ class sync_request_info : public extend<memory_managed>::with<memory_cached> { ...@@ -57,13 +57,13 @@ class sync_request_info : public extend<memory_managed>::with<memory_cached> {
typedef sync_request_info* pointer; typedef sync_request_info* pointer;
pointer next; // intrusive next pointer pointer next; // intrusive next pointer
actor_ptr sender; // points to the sender of the message actor_addr sender; // points to the sender of the message
message_id mid; // sync message ID message_id mid; // sync message ID
private: private:
sync_request_info(actor_ptr sptr, message_id id); sync_request_info(actor_addr sptr, message_id id);
}; };
...@@ -79,17 +79,17 @@ class remote_actor_proxy : public actor_proxy { ...@@ -79,17 +79,17 @@ class remote_actor_proxy : public actor_proxy {
void enqueue(const message_header& hdr, any_tuple msg) override; void enqueue(const message_header& hdr, any_tuple msg) override;
void link_to(const actor_ptr& other) override; void link_to(const actor_addr& other) override;
void unlink_from(const actor_ptr& other) override; void unlink_from(const actor_addr& other) override;
bool remove_backlink(const actor_ptr& to) override; bool remove_backlink(const actor_addr& to) override;
bool establish_backlink(const actor_ptr& to) override; bool establish_backlink(const actor_addr& to) override;
void local_link_to(const actor_ptr& other) override; void local_link_to(const actor_addr& other) override;
void local_unlink_from(const actor_ptr& other) override; void local_unlink_from(const actor_addr& other) override;
void deliver(const message_header& hdr, any_tuple msg) override; void deliver(const message_header& hdr, any_tuple msg) override;
......
...@@ -34,16 +34,20 @@ ...@@ -34,16 +34,20 @@
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
#include "cppa/group.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/group.hpp"
#include "cppa/extend.hpp" #include "cppa/extend.hpp"
#include "cppa/channel.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/message_id.hpp" #include "cppa/message_id.hpp"
#include "cppa/match_expr.hpp" #include "cppa/match_expr.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/typed_actor.hpp"
#include "cppa/memory_cached.hpp" #include "cppa/memory_cached.hpp"
#include "cppa/message_future.hpp"
#include "cppa/message_header.hpp" #include "cppa/message_header.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/mailbox_element.hpp" #include "cppa/mailbox_element.hpp"
#include "cppa/response_handle.hpp" #include "cppa/response_handle.hpp"
#include "cppa/message_priority.hpp" #include "cppa/message_priority.hpp"
...@@ -56,61 +60,90 @@ ...@@ -56,61 +60,90 @@
namespace cppa { namespace cppa {
// forward declarations // forward declarations
class self_type;
class scheduler; class scheduler;
class message_future; class message_future;
class local_scheduler; class local_scheduler;
class sync_handle_helper; class sync_handle_helper;
#ifdef CPPA_DOCUMENTATION namespace detail { class receive_policy; }
/**
* @brief Policy tag that causes {@link event_based_actor::become} to
* discard the current behavior.
* @relates local_actor
*/
constexpr auto discard_behavior;
/** /**
* @brief Policy tag that causes {@link event_based_actor::become} to * @brief Base class for local running Actors.
* keep the current behavior available. * @extends actor
* @relates local_actor
*/ */
constexpr auto keep_behavior; class local_actor : public extend<abstract_actor>::with<memory_cached> {
#else
template<bool DiscardBehavior> friend class detail::receive_policy;
struct behavior_policy { static constexpr bool discard_old = DiscardBehavior; };
template<typename T> typedef combined_type super;
struct is_behavior_policy : std::false_type { };
template<bool DiscardBehavior>
struct is_behavior_policy<behavior_policy<DiscardBehavior>> : std::true_type { };
typedef behavior_policy<false> keep_behavior_t; public:
typedef behavior_policy<true > discard_behavior_t;
constexpr discard_behavior_t discard_behavior = discard_behavior_t{}; ~local_actor();
constexpr keep_behavior_t keep_behavior = keep_behavior_t{}; /**
* @brief Sends @p what to the receiver specified in @p dest.
*/
void send_tuple(const channel& dest, any_tuple what);
#endif /**
* @brief Sends <tt>{what...}</tt> to the receiver specified in @p hdr.
* @pre <tt>sizeof...(Ts) > 0</tt>
*/
template<typename... Ts>
void send(const channel& whom, Ts&&... what) {
send_tuple(whom, make_any_tuple(std::forward<Ts>(what)...));
}
/** /**
* @brief Base class for local running Actors. * @brief Sends @p what as a synchronous message to @p whom.
* @extends actor * @param whom Receiver of the message.
*/ * @param what Message content as tuple.
class local_actor : public extend<actor>::with<memory_cached> { * @returns A handle identifying a future to the response of @p whom.
* @warning The returned handle is actor specific and the response to the sent
* message cannot be received by another actor.
* @throws std::invalid_argument if <tt>whom == nullptr</tt>
*/
message_future sync_send_tuple(const actor& dest, any_tuple what);
friend class self_type; message_future timed_sync_send_tuple(const util::duration& rtime,
const actor& dest,
any_tuple what);
typedef combined_type super; /**
* @brief Sends <tt>{what...}</tt> as a synchronous message to @p whom.
* @param whom Receiver of the message.
* @param what Message elements.
* @returns A handle identifying a future to the response of @p whom.
* @warning The returned handle is actor specific and the response to the sent
* message cannot be received by another actor.
* @pre <tt>sizeof...(Ts) > 0</tt>
* @throws std::invalid_argument if <tt>whom == nullptr</tt>
*/
template<typename... Ts>
inline message_future sync_send(const actor& dest, Ts&&... what) {
static_assert(sizeof...(Ts) > 0, "no message to send");
return sync_send_tuple(dest, make_any_tuple(std::forward<Ts>(what)...));
}
public: template<typename... Ts>
message_future timed_sync_send(const util::duration& rtime,
const actor& dest,
Ts&&... what) {
static_assert(sizeof...(Ts) > 0, "no message to send");
return timed_sync_send_tuple(rtime, dest, make_any_tuple(std::forward<Ts>(what)...));
}
~local_actor(); /**
* @brief Sends a message to @p whom that is delayed by @p rel_time.
* @param whom Receiver of the message.
* @param rtime Relative time duration to delay the message in
* microseconds, milliseconds, seconds or minutes.
* @param data Message content as a tuple.
*/
void delayed_send_tuple(const channel& dest,
const util::duration& rtime,
any_tuple data);
/** /**
* @brief Causes this actor to subscribe to the group @p what. * @brief Causes this actor to subscribe to the group @p what.
...@@ -164,16 +197,6 @@ class local_actor : public extend<actor>::with<memory_cached> { ...@@ -164,16 +197,6 @@ class local_actor : public extend<actor>::with<memory_cached> {
*/ */
inline void trap_exit(bool new_value); inline void trap_exit(bool new_value);
/**
* @brief Checks whether this actor uses the "chained send" optimization.
*/
inline bool chaining() const;
/**
* @brief Enables or disables chained send.
*/
inline void chaining(bool new_value);
/** /**
* @brief Returns the last message that was dequeued * @brief Returns the last message that was dequeued
* from the actor's mailbox. * from the actor's mailbox.
...@@ -182,10 +205,10 @@ class local_actor : public extend<actor>::with<memory_cached> { ...@@ -182,10 +205,10 @@ class local_actor : public extend<actor>::with<memory_cached> {
inline any_tuple& last_dequeued(); inline any_tuple& last_dequeued();
/** /**
* @brief Returns the sender of the last dequeued message. * @brief Returns the address of the last sender of the
* @warning Only set during callback invocation. * last dequeued message.
*/ */
inline actor_ptr& last_sender(); inline actor_addr& last_sender();
/** /**
* @brief Adds a unidirectional @p monitor to @p whom. * @brief Adds a unidirectional @p monitor to @p whom.
...@@ -194,13 +217,21 @@ class local_actor : public extend<actor>::with<memory_cached> { ...@@ -194,13 +217,21 @@ class local_actor : public extend<actor>::with<memory_cached> {
* @param whom The actor that should be monitored by this actor. * @param whom The actor that should be monitored by this actor.
* @note Each call to @p monitor creates a new, independent monitor. * @note Each call to @p monitor creates a new, independent monitor.
*/ */
void monitor(const actor_ptr& whom); void monitor(const actor_addr& whom);
inline void monitor(const actor& whom) {
monitor(whom.address());
}
/** /**
* @brief Removes a monitor from @p whom. * @brief Removes a monitor from @p whom.
* @param whom A monitored actor. * @param whom A monitored actor.
*/ */
void demonitor(const actor_ptr& whom); void demonitor(const actor_addr& whom);
inline void demonitor(const actor& whom) {
demonitor(whom.address());
}
/** /**
* @brief Can be overridden to initialize an actor before any * @brief Can be overridden to initialize an actor before any
...@@ -224,16 +255,6 @@ class local_actor : public extend<actor>::with<memory_cached> { ...@@ -224,16 +255,6 @@ class local_actor : public extend<actor>::with<memory_cached> {
*/ */
std::vector<group_ptr> joined_groups() const; std::vector<group_ptr> joined_groups() const;
/**
* @ingroup BlockingAPI
* @brief Executes an actor's behavior stack until it is empty.
*
* This member function allows thread-based and context-switching actors
* to make use of the nonblocking behavior API of libcppa.
* Calling this member function in an event-based actor does nothing.
*/
virtual void exec_behavior_stack();
/** /**
* @brief Creates a {@link response_handle} to allow actors to response * @brief Creates a {@link response_handle} to allow actors to response
* to a request later on. * to a request later on.
...@@ -304,7 +325,7 @@ class local_actor : public extend<actor>::with<memory_cached> { ...@@ -304,7 +325,7 @@ class local_actor : public extend<actor>::with<memory_cached> {
inline bool chaining_enabled(); inline bool chaining_enabled();
message_id send_timed_sync_message(message_priority mp, message_id send_timed_sync_message(message_priority mp,
const actor_ptr& whom, const actor& whom,
const util::duration& rel_time, const util::duration& rel_time,
any_tuple&& what); any_tuple&& what);
...@@ -314,11 +335,7 @@ class local_actor : public extend<actor>::with<memory_cached> { ...@@ -314,11 +335,7 @@ class local_actor : public extend<actor>::with<memory_cached> {
void reply_message(any_tuple&& what); void reply_message(any_tuple&& what);
void forward_message(const actor_ptr& new_receiver, message_priority prio); void forward_message(const actor& new_receiver, message_priority prio);
inline const actor_ptr& chained_actor();
inline void chained_actor(const actor_ptr& value);
inline bool awaits(message_id response_id); inline bool awaits(message_id response_id);
...@@ -349,18 +366,12 @@ class local_actor : public extend<actor>::with<memory_cached> { ...@@ -349,18 +366,12 @@ class local_actor : public extend<actor>::with<memory_cached> {
// used *only* when compiled in debug mode // used *only* when compiled in debug mode
union { std::string m_debug_name; }; union { std::string m_debug_name; };
// true if this actor uses the chained_send optimization
bool m_chaining;
// true if this actor receives EXIT messages as ordinary messages // true if this actor receives EXIT messages as ordinary messages
bool m_trap_exit; bool m_trap_exit;
// true if this actor takes part in cooperative scheduling // true if this actor takes part in cooperative scheduling
bool m_is_scheduled; bool m_is_scheduled;
// pointer to the actor that is marked as successor due to a chained send
actor_ptr m_chained_actor;
// identifies the ID of the last sent synchronous request // identifies the ID of the last sent synchronous request
message_id m_last_request_id; message_id m_last_request_id;
...@@ -423,19 +434,11 @@ inline void local_actor::trap_exit(bool new_value) { ...@@ -423,19 +434,11 @@ inline void local_actor::trap_exit(bool new_value) {
m_trap_exit = new_value; m_trap_exit = new_value;
} }
inline bool local_actor::chaining() const {
return m_chaining;
}
inline void local_actor::chaining(bool new_value) {
m_chaining = m_is_scheduled && new_value;
}
inline any_tuple& local_actor::last_dequeued() { inline any_tuple& local_actor::last_dequeued() {
return m_current_node->msg; return m_current_node->msg;
} }
inline actor_ptr& local_actor::last_sender() { inline actor_addr& local_actor::last_sender() {
return m_current_node->sender; return m_current_node->sender;
} }
...@@ -443,23 +446,11 @@ inline void local_actor::do_unbecome() { ...@@ -443,23 +446,11 @@ inline void local_actor::do_unbecome() {
m_bhvr_stack.pop_async_back(); m_bhvr_stack.pop_async_back();
} }
inline bool local_actor::chaining_enabled() {
return m_chaining && !m_chained_actor;
}
inline message_id local_actor::get_response_id() { inline message_id local_actor::get_response_id() {
auto id = m_current_node->mid; auto id = m_current_node->mid;
return (id.is_request()) ? id.response_id() : message_id(); return (id.is_request()) ? id.response_id() : message_id();
} }
inline const actor_ptr& local_actor::chained_actor() {
return m_chained_actor;
}
inline void local_actor::chained_actor(const actor_ptr& value) {
m_chained_actor = value;
}
inline bool local_actor::awaits(message_id response_id) { inline bool local_actor::awaits(message_id response_id) {
CPPA_REQUIRE(response_id.is_response()); CPPA_REQUIRE(response_id.is_response());
return std::any_of(m_pending_responses.begin(), return std::any_of(m_pending_responses.begin(),
......
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#include <execinfo.h> #include <execinfo.h>
#include <type_traits> #include <type_traits>
#include "cppa/self.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/singletons.hpp" #include "cppa/singletons.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
...@@ -70,7 +69,7 @@ class logging { ...@@ -70,7 +69,7 @@ class logging {
const char* function_name, const char* function_name,
const char* file_name, const char* file_name,
int line_num, int line_num,
const actor_ptr& from, actor_addr from,
const std::string& msg ) = 0; const std::string& msg ) = 0;
class trace_helper { class trace_helper {
...@@ -81,7 +80,7 @@ class logging { ...@@ -81,7 +80,7 @@ class logging {
const char* fun_name, const char* fun_name,
const char* file_name, const char* file_name,
int line_num, int line_num,
actor_ptr aptr, actor_addr aptr,
const std::string& msg); const std::string& msg);
~trace_helper(); ~trace_helper();
...@@ -92,7 +91,7 @@ class logging { ...@@ -92,7 +91,7 @@ class logging {
const char* m_fun_name; const char* m_fun_name;
const char* m_file_name; const char* m_file_name;
int m_line_num; int m_line_num;
actor_ptr m_self; actor_addr m_self;
}; };
...@@ -110,14 +109,6 @@ class logging { ...@@ -110,14 +109,6 @@ class logging {
}; };
inline actor_ptr fwd_aptr(const self_type& s) {
return s.unchecked();
}
inline actor_ptr fwd_aptr(actor_ptr ptr) {
return ptr;
}
struct oss_wr { struct oss_wr {
inline oss_wr() { } inline oss_wr() { }
......
...@@ -33,9 +33,9 @@ ...@@ -33,9 +33,9 @@
#include <cstdint> #include <cstdint>
#include "cppa/actor.hpp"
#include "cppa/extend.hpp" #include "cppa/extend.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/actor_addr.hpp"
#include "cppa/message_id.hpp" #include "cppa/message_id.hpp"
#include "cppa/ref_counted.hpp" #include "cppa/ref_counted.hpp"
#include "cppa/memory_cached.hpp" #include "cppa/memory_cached.hpp"
...@@ -57,7 +57,7 @@ class mailbox_element : public extend<memory_managed>::with<memory_cached> { ...@@ -57,7 +57,7 @@ class mailbox_element : public extend<memory_managed>::with<memory_cached> {
pointer next; // intrusive next pointer pointer next; // intrusive next pointer
bool marked; // denotes if this node is currently processed bool marked; // denotes if this node is currently processed
actor_ptr sender; // points to the sender of msg actor_addr sender;
any_tuple msg; // 'content field' any_tuple msg; // 'content field'
message_id mid; message_id mid;
......
...@@ -34,19 +34,13 @@ ...@@ -34,19 +34,13 @@
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "cppa/on.hpp"
#include "cppa/atom.hpp"
#include "cppa/logging.hpp"
#include "cppa/behavior.hpp"
#include "cppa/match_expr.hpp" #include "cppa/match_expr.hpp"
#include "cppa/message_id.hpp" #include "cppa/partial_function.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/detail/typed_actor_util.hpp"
namespace cppa { namespace cppa {
class local_actor;
namespace detail { struct optional_any_tuple_visitor; } namespace detail { struct optional_any_tuple_visitor; }
/** /**
...@@ -62,24 +56,8 @@ class continue_helper { ...@@ -62,24 +56,8 @@ class continue_helper {
inline continue_helper(message_id mid) : m_mid(mid) { } inline continue_helper(message_id mid) : m_mid(mid) { }
template<typename F> template<typename F>
continue_helper& continue_with(F fun) { continue_helper& continue_with(F fun);
return continue_with(behavior::continuation_fun{partial_function{
on(any_vals, arg_match) >> fun
}});
}
inline continue_helper& continue_with(behavior::continuation_fun fun) {
auto ref_opt = self->bhvr_stack().sync_handler(m_mid);
if (ref_opt) {
auto& ref = *ref_opt;
// copy original behavior
behavior cpy = ref;
ref = cpy.add_continuation(std::move(fun));
}
else CPPA_LOG_ERROR(".continue_with: failed to add continuation");
return *this;
}
inline message_id get_message_id() const { inline message_id get_message_id() const {
return m_mid; return m_mid;
} }
...@@ -87,6 +65,7 @@ class continue_helper { ...@@ -87,6 +65,7 @@ class continue_helper {
private: private:
message_id m_mid; message_id m_mid;
local_actor* self;
}; };
...@@ -99,14 +78,16 @@ class message_future { ...@@ -99,14 +78,16 @@ class message_future {
message_future() = delete; message_future() = delete;
continue_helper then(const partial_function& pfun);
continue_helper await(const partial_function& pfun);
/** /**
* @brief Sets @p mexpr as event-handler for the response message. * @brief Sets @p mexpr as event-handler for the response message.
*/ */
template<typename... Cs, typename... Ts> template<typename... Cs, typename... Ts>
continue_helper then(const match_expr<Cs...>& arg, const Ts&... args) { continue_helper then(const match_expr<Cs...>& arg, const Ts&... args) {
check_consistency(); return then(match_expr_convert(arg, args...));
self->become_waiting_for(match_expr_convert(arg, args...), m_mid);
return {m_mid};
} }
/** /**
...@@ -114,8 +95,7 @@ class message_future { ...@@ -114,8 +95,7 @@ class message_future {
*/ */
template<typename... Cs, typename... Ts> template<typename... Cs, typename... Ts>
void await(const match_expr<Cs...>& arg, const Ts&... args) { void await(const match_expr<Cs...>& arg, const Ts&... args) {
check_consistency(); await(match_expr_convert(arg, args...));
self->dequeue_response(match_expr_convert(arg, args...), m_mid);
} }
/** /**
...@@ -129,9 +109,7 @@ class message_future { ...@@ -129,9 +109,7 @@ class message_future {
continue_helper continue_helper
>::type >::type
then(Fs... fs) { then(Fs... fs) {
check_consistency(); return then(fs2bhvr(std::move(fs)...));
self->become_waiting_for(fs2bhvr(std::move(fs)...), m_mid);
return {m_mid};
} }
/** /**
...@@ -142,8 +120,7 @@ class message_future { ...@@ -142,8 +120,7 @@ class message_future {
template<typename... Fs> template<typename... Fs>
typename std::enable_if<util::all_callable<Fs...>::value>::type typename std::enable_if<util::all_callable<Fs...>::value>::type
await(Fs... fs) { await(Fs... fs) {
check_consistency(); await(fs2bhvr({std::move(fs)...}));
self->dequeue_response(fs2bhvr(std::move(fs)...), m_mid);
} }
/** /**
...@@ -159,117 +136,11 @@ class message_future { ...@@ -159,117 +136,11 @@ class message_future {
private: private:
message_id m_mid; message_id m_mid;
local_actor* self;
template<typename... Fs> partial_function fs2bhvr(partial_function pf);
behavior fs2bhvr(Fs... fs) {
auto handle_sync_timeout = []() -> match_hint { void check_consistency();
self->handle_sync_timeout();
return match_hint::skip;
};
return {
on(atom("EXITED"), val<std::uint32_t>) >> skip_message,
on(atom("VOID")) >> skip_message,
on(atom("TIMEOUT")) >> handle_sync_timeout,
(on(any_vals, arg_match) >> fs)...
};
}
void check_consistency() {
if (!m_mid.valid() || !m_mid.is_response()) {
throw std::logic_error("handle does not point to a response");
}
else if (!self->awaits(m_mid)) {
throw std::logic_error("response already received");
}
}
};
template<typename R>
class typed_continue_helper {
public:
typedef int message_id_wrapper_tag;
typedef typename detail::lifted_result_type<R>::type result_types;
typed_continue_helper(continue_helper ch) : m_ch(std::move(ch)) { }
template<typename F>
typed_continue_helper<typename util::get_callable_trait<F>::result_type>
continue_with(F fun) {
detail::assert_types<result_types, F>();
m_ch.continue_with(std::move(fun));
return {m_ch};
}
inline message_id get_message_id() const {
return m_ch.get_message_id();
}
private:
continue_helper m_ch;
};
/*
template<>
class typed_continue_helper<void> {
public:
typedef int message_id_wrapper_tag;
typedef util::type_list<void> result_types;
typed_continue_helper(continue_helper ch) : m_ch(std::move(ch)) { }
template<typename F>
void continue_with(F fun) {
using arg_types = typename util::get_callable_trait<F>::arg_types;
static_assert(std::is_same<util::empty_type_list, arg_types>::value,
"functor takes too much arguments");
m_ch.continue_with(std::move(fun));
}
inline message_id get_message_id() const {
return m_ch.get_message_id();
}
private:
continue_helper m_ch;
};
*/
template<typename OutputList>
class typed_message_future {
public:
typed_message_future(message_future&& mf) : m_mf(std::move(mf)) { }
template<typename F>
void await(F fun) {
detail::assert_types<OutputList, F>();
m_mf.await(fun);
}
template<typename F>
typed_continue_helper<
typename util::get_callable_trait<F>::result_type
>
then(F fun) {
detail::assert_types<OutputList, F>();
return m_mf.then(fun);
}
private:
message_future m_mf;
}; };
......
...@@ -31,8 +31,8 @@ ...@@ -31,8 +31,8 @@
#ifndef CPPA_MESSAGE_HEADER_HPP #ifndef CPPA_MESSAGE_HEADER_HPP
#define CPPA_MESSAGE_HEADER_HPP #define CPPA_MESSAGE_HEADER_HPP
#include "cppa/self.hpp" #include "cppa/channel.hpp"
#include "cppa/actor.hpp" #include "cppa/actor_addr.hpp"
#include "cppa/message_id.hpp" #include "cppa/message_id.hpp"
#include "cppa/message_priority.hpp" #include "cppa/message_priority.hpp"
...@@ -48,9 +48,9 @@ class message_header { ...@@ -48,9 +48,9 @@ class message_header {
public: public:
actor_ptr sender; actor_addr sender;
channel_ptr receiver; channel receiver;
message_id id; message_id id;
message_priority priority; message_priority priority;
/** /**
...@@ -58,52 +58,12 @@ class message_header { ...@@ -58,52 +58,12 @@ class message_header {
**/ **/
message_header() = default; message_header() = default;
/**
* @brief Creates a message header with <tt>receiver = dest</tt>
* and <tt>sender = self</tt>.
**/
template<typename T>
message_header(intrusive_ptr<T> dest)
: sender(self), receiver(dest), priority(message_priority::normal) {
static_assert(std::is_convertible<T*, channel*>::value,
"illegal receiver");
}
template<typename T>
message_header(T* dest)
: sender(self), receiver(dest), priority(message_priority::normal) {
static_assert(std::is_convertible<T*, channel*>::value,
"illegal receiver");
}
message_header(const std::nullptr_t&);
/**
* @brief Creates a message header with <tt>receiver = self</tt>
* and <tt>sender = self</tt>.
**/
message_header(const self_type&);
/**
* @brief Creates a message header with <tt>receiver = dest</tt>
* and <tt>sender = self</tt>.
*/
message_header(channel_ptr dest,
message_id mid,
message_priority prio = message_priority::normal);
/**
* @brief Creates a message header with <tt>receiver = dest</tt> and
* <tt>sender = self</tt>.
*/
message_header(channel_ptr dest, message_priority prio);
/** /**
* @brief Creates a message header with <tt>receiver = dest</tt> and * @brief Creates a message header with <tt>receiver = dest</tt> and
* <tt>sender = source</tt>. * <tt>sender = source</tt>.
*/ */
message_header(actor_ptr source, message_header(actor_addr source,
channel_ptr dest, channel dest,
message_id mid = message_id::invalid, message_id mid = message_id::invalid,
message_priority prio = message_priority::normal); message_priority prio = message_priority::normal);
...@@ -111,7 +71,7 @@ class message_header { ...@@ -111,7 +71,7 @@ class message_header {
* @brief Creates a message header with <tt>receiver = dest</tt> and * @brief Creates a message header with <tt>receiver = dest</tt> and
* <tt>sender = self</tt>. * <tt>sender = self</tt>.
*/ */
message_header(actor_ptr source, channel_ptr dest, message_priority prio); message_header(actor_addr source, channel dest, message_priority prio);
void deliver(any_tuple msg) const; void deliver(any_tuple msg) const;
......
...@@ -37,9 +37,9 @@ ...@@ -37,9 +37,9 @@
#include <algorithm> #include <algorithm>
#include <functional> #include <functional>
#include "cppa/actor.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/opencl/global.hpp" #include "cppa/opencl/global.hpp"
#include "cppa/abstract_actor.hpp"
#include "cppa/response_handle.hpp" #include "cppa/response_handle.hpp"
#include "cppa/opencl/smart_ptr.hpp" #include "cppa/opencl/smart_ptr.hpp"
#include "cppa/util/scope_guard.hpp" #include "cppa/util/scope_guard.hpp"
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
#ifndef OPTIONAL_VARIANT_HPP #ifndef OPTIONAL_VARIANT_HPP
#define OPTIONAL_VARIANT_HPP #define OPTIONAL_VARIANT_HPP
#include <iosfwd> #include <ostream>
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
......
...@@ -50,8 +50,8 @@ class response_handle { ...@@ -50,8 +50,8 @@ class response_handle {
response_handle& operator=(response_handle&&) = default; response_handle& operator=(response_handle&&) = default;
response_handle& operator=(const response_handle&) = default; response_handle& operator=(const response_handle&) = default;
response_handle(const actor_ptr& from, response_handle(const actor_addr& from,
const actor_ptr& to, const actor_addr& to,
const message_id& response_id); const message_id& response_id);
/** /**
...@@ -78,17 +78,17 @@ class response_handle { ...@@ -78,17 +78,17 @@ class response_handle {
/** /**
* @brief Returns the actor that is going send the response message. * @brief Returns the actor that is going send the response message.
*/ */
inline const actor_ptr& sender() const { return m_from; } inline const actor_addr& sender() const { return m_from; }
/** /**
* @brief Returns the actor that is waiting for the response message. * @brief Returns the actor that is waiting for the response message.
*/ */
inline const actor_ptr& receiver() const { return m_to; } inline const actor_addr& receiver() const { return m_to; }
private: private:
actor_ptr m_from; actor_addr m_from;
actor_ptr m_to; actor_addr m_to;
message_id m_id; message_id m_id;
}; };
......
...@@ -88,7 +88,7 @@ class scheduled_actor : public extend<local_actor>::with<mailbox_based, threadle ...@@ -88,7 +88,7 @@ class scheduled_actor : public extend<local_actor>::with<mailbox_based, threadle
* set in case of chaining. * set in case of chaining.
* @note This member function is called from the scheduler's worker threads. * @note This member function is called from the scheduler's worker threads.
*/ */
virtual resume_result resume(util::fiber* from, actor_ptr& next_job) = 0; virtual resume_result resume(util::fiber* from) = 0;
/** /**
* @brief Called once by the scheduler after actor is initialized, * @brief Called once by the scheduler after actor is initialized,
...@@ -110,7 +110,7 @@ class scheduled_actor : public extend<local_actor>::with<mailbox_based, threadle ...@@ -110,7 +110,7 @@ class scheduled_actor : public extend<local_actor>::with<mailbox_based, threadle
/** /**
* @brief Returns @p true if this actor is ignored by * @brief Returns @p true if this actor is ignored by
* {@link await_all_others_done()}, false otherwise. * {@link await_all_actors_done()}, false otherwise.
*/ */
inline bool is_hidden() const; inline bool is_hidden() const;
...@@ -118,10 +118,6 @@ class scheduled_actor : public extend<local_actor>::with<mailbox_based, threadle ...@@ -118,10 +118,6 @@ class scheduled_actor : public extend<local_actor>::with<mailbox_based, threadle
void enqueue(const message_header&, any_tuple) override; void enqueue(const message_header&, any_tuple) override;
bool chained_enqueue(const message_header&, any_tuple) override;
void unchain() override;
protected: protected:
scheduled_actor(actor_state init_state, bool enable_chained_send); scheduled_actor(actor_state init_state, bool enable_chained_send);
......
...@@ -44,17 +44,15 @@ ...@@ -44,17 +44,15 @@
#include "cppa/attachable.hpp" #include "cppa/attachable.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/spawn_options.hpp" #include "cppa/spawn_options.hpp"
//#include "cppa/scheduled_actor.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
#include "cppa/detail/fwd.hpp"
namespace cppa { namespace cppa {
class self_type; class self_type;
class scheduled_actor; class scheduled_actor;
class scheduler_helper; class scheduler_helper;
class event_based_actor;
typedef intrusive_ptr<scheduled_actor> scheduled_actor_ptr; typedef intrusive_ptr<scheduled_actor> scheduled_actor_ptr;
namespace detail { class singleton_manager; } // namespace detail namespace detail { class singleton_manager; } // namespace detail
...@@ -86,9 +84,9 @@ class scheduler { ...@@ -86,9 +84,9 @@ class scheduler {
public: public:
typedef std::function<void(local_actor*)> init_callback; typedef std::function<void(local_actor*)> init_callback;
typedef std::function<void()> void_function; typedef std::function<behavior(local_actor*)> actor_fun;
const actor_ptr& printer() const; const actor& printer() const;
virtual void enqueue(scheduled_actor*) = 0; virtual void enqueue(scheduled_actor*) = 0;
...@@ -115,7 +113,7 @@ class scheduler { ...@@ -115,7 +113,7 @@ class scheduler {
util::duration{rel_time}, util::duration{rel_time},
std::move(hdr), std::move(hdr),
std::move(data)); std::move(data));
delayed_send_helper()->enqueue(nullptr, std::move(tup)); //TODO: delayed_send_helper()->enqueue(nullptr, std::move(tup));
} }
template<typename Duration, typename... Data> template<typename Duration, typename... Data>
...@@ -127,7 +125,7 @@ class scheduler { ...@@ -127,7 +125,7 @@ class scheduler {
util::duration{rel_time}, util::duration{rel_time},
std::move(hdr), std::move(hdr),
std::move(data)); std::move(data));
delayed_send_helper()->enqueue(nullptr, std::move(tup)); //TODO: delayed_send_helper()->enqueue(nullptr, std::move(tup));
} }
/** /**
...@@ -141,14 +139,13 @@ class scheduler { ...@@ -141,14 +139,13 @@ class scheduler {
* in this scheduler. * in this scheduler.
*/ */
virtual local_actor_ptr exec(spawn_options opts, virtual local_actor_ptr exec(spawn_options opts,
init_callback init_cb, init_callback init_cb,
void_function actor_behavior) = 0; actor_fun actor_behavior) = 0;
template<typename F, typename T, typename... Ts> template<typename F, typename T, typename... Ts>
local_actor_ptr exec(spawn_options opts, init_callback cb, local_actor_ptr exec(spawn_options opts, init_callback cb,
F f, T&& a0, Ts&&... as) { F f, T&& a0, Ts&&... as) {
return this->exec(opts, cb, std::bind(f, detail::fwd<T>(a0), return this->exec(opts, cb, std::bind(f, std::forward<T>(a0), std::forward<Ts>(as)...));
detail::fwd<Ts>(as)...));
} }
private: private:
...@@ -157,7 +154,7 @@ class scheduler { ...@@ -157,7 +154,7 @@ class scheduler {
inline void dispose() { delete this; } inline void dispose() { delete this; }
const actor_ptr& delayed_send_helper(); actor& delayed_send_helper();
scheduler_helper* m_helper; scheduler_helper* m_helper;
......
...@@ -25,144 +25,131 @@ ...@@ -25,144 +25,131 @@
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_RECEIVE_HPP #ifndef CPPA_SCOPED_ACTOR_HPP
#define CPPA_RECEIVE_HPP #define CPPA_SCOPED_ACTOR_HPP
#include "cppa/self.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/local_actor.hpp" #include "cppa/thread_mapped_actor.hpp"
#include "cppa/detail/receive_loop_helper.hpp"
namespace cppa { namespace cppa {
/** class scoped_actor {
* @ingroup BlockingAPI
* @{ public:
*/
/**
/** * @brief Dequeues the next message from the mailbox that
* @brief Dequeues the next message from the mailbox that * is matched by given behavior.
* is matched by given behavior. */
*/ template<typename... Ts>
template<typename... Ts> void receive(Ts&&... args);
void receive(Ts&&... args);
/**
/** * @brief Receives messages in an endless loop.
* @brief Receives messages in an endless loop. * Semantically equal to: <tt>for (;;) { receive(...); }</tt>
* Semantically equal to: <tt>for (;;) { receive(...); }</tt> */
*/ template<typename... Ts>
template<typename... Ts> void receive_loop(Ts&&... args);
void receive_loop(Ts&&... args);
/**
/** * @brief Receives messages as in a range-based loop.
* @brief Receives messages as in a range-based loop. *
* * Semantically equal to:
* Semantically equal to: * <tt>for ( ; begin != end; ++begin) { receive(...); }</tt>.
* <tt>for ( ; begin != end; ++begin) { receive(...); }</tt>. *
* * <b>Usage example:</b>
* <b>Usage example:</b> * @code
* @code * int i = 0;
* int i = 0; * receive_for(i, 10) (
* receive_for(i, 10) ( * on(atom("get")) >> [&]() -> any_tuple { return {"result", i}; }
* on(atom("get")) >> [&]() -> any_tuple { return {"result", i}; } * );
* ); * @endcode
* @endcode * @param begin First value in range.
* @param begin First value in range. * @param end Last value in range (excluded).
* @param end Last value in range (excluded). * @returns A functor implementing the loop.
* @returns A functor implementing the loop. */
*/ template<typename T>
template<typename T> detail::receive_for_helper<T> receive_for(T& begin, const T& end);
detail::receive_for_helper<T> receive_for(T& begin, const T& end);
/**
/** * @brief Receives messages as long as @p stmt returns true.
* @brief Receives messages as long as @p stmt returns true. *
* * Semantically equal to: <tt>while (stmt()) { receive(...); }</tt>.
* Semantically equal to: <tt>while (stmt()) { receive(...); }</tt>. *
* * <b>Usage example:</b>
* <b>Usage example:</b> * @code
* @code * int i = 0;
* int i = 0; * receive_while([&]() { return (++i <= 10); })
* receive_while([&]() { return (++i <= 10); }) * (
* ( * on<int>() >> int_fun,
* on<int>() >> int_fun, * on<float>() >> float_fun
* on<float>() >> float_fun * );
* ); * @endcode
* @endcode * @param stmt Lambda expression, functor or function returning a @c bool.
* @param stmt Lambda expression, functor or function returning a @c bool. * @returns A functor implementing the loop.
* @returns A functor implementing the loop. */
*/ template<typename Statement>
template<typename Statement> detail::receive_while_helper<Statement> receive_while(Statement&& stmt);
detail::receive_while_helper<Statement> receive_while(Statement&& stmt);
/**
/** * @brief Receives messages until @p stmt returns true.
* @brief Receives messages until @p stmt returns true. *
* * Semantically equal to: <tt>do { receive(...); } while (stmt() == false);</tt>
* Semantically equal to: <tt>do { receive(...); } while (stmt() == false);</tt> *
* * <b>Usage example:</b>
* <b>Usage example:</b> * @code
* @code * int i = 0;
* int i = 0; * do_receive
* do_receive * (
* ( * on<int>() >> int_fun,
* on<int>() >> int_fun, * on<float>() >> float_fun
* on<float>() >> float_fun * )
* ) * .until([&]() { return (++i >= 10); };
* .until([&]() { return (++i >= 10); }; * @endcode
* @endcode * @param bhvr Denotes the actor's response the next incoming message.
* @param bhvr Denotes the actor's response the next incoming message. * @returns A functor providing the @c until member function.
* @returns A functor providing the @c until member function. */
*/ template<typename... Ts>
template<typename... Ts> detail::do_receive_helper do_receive(Ts&&... args);
detail::do_receive_helper do_receive(Ts&&... args);
private:
/**
* @} intrusive_ptr<thread_mapped_actor> m_self;
*/
};
/****************************************************************************** /******************************************************************************
* inline and template function implementations * * inline and template function implementations *
******************************************************************************/ ******************************************************************************/
template<typename... Ts> template<typename... Ts>
void receive(Ts&&... args) { void scoped_actor::receive(Ts&&... args) {
static_assert(sizeof...(Ts), "receive() requires at least one argument"); m_self->receive(std::forward<Ts(args)...);
self->dequeue(match_expr_convert(std::forward<Ts>(args)...));
}
inline void receive_loop(behavior rules) {
local_actor* sptr = self;
for (;;) sptr->dequeue(rules);
} }
template<typename... Ts> template<typename... Ts>
void receive_loop(Ts&&... args) { void scoped_actor::receive_loop(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...); m_self->receive_loop(std::forward<Ts(args)...);
local_actor* sptr = self;
for (;;) sptr->dequeue(bhvr);
} }
template<typename T> template<typename T>
detail::receive_for_helper<T> receive_for(T& begin, const T& end) { detail::receive_for_helper<T> scoped_actor::receive_for(T& begin, const T& end) {
return {begin, end}; m_self->receive_for(begin, end);
} }
template<typename Statement> template<typename Statement>
detail::receive_while_helper<Statement> receive_while(Statement&& stmt) { detail::receive_while_helper<Statement> scoped_actor::receive_while(Statement&& stmt) {
static_assert(std::is_same<bool, decltype(stmt())>::value, m_self->receive_while(std::forward<Statement(stmt));
"functor or function does not return a boolean");
return std::move(stmt);
} }
template<typename... Ts> template<typename... Ts>
detail::do_receive_helper do_receive(Ts&&... args) { detail::do_receive_helper scoped_actor::do_receive(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...); m_self->do_receive(std::forward<Ts(args)...);
return detail::do_receive_helper(std::move(bhvr));
} }
} // namespace cppa } // namespace cppa
#endif // CPPA_RECEIVE_HPP #endif // CPPA_SCOPED_ACTOR_HPP
...@@ -31,13 +31,11 @@ ...@@ -31,13 +31,11 @@
#ifndef CPPA_SEND_HPP #ifndef CPPA_SEND_HPP
#define CPPA_SEND_HPP #define CPPA_SEND_HPP
#include "cppa/self.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/message_header.hpp" #include "cppa/message_header.hpp"
#include "cppa/message_future.hpp" #include "cppa/message_future.hpp"
#include "cppa/typed_actor_ptr.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
...@@ -48,25 +46,9 @@ namespace cppa { ...@@ -48,25 +46,9 @@ namespace cppa {
* @{ * @{
*/ */
/** using channel_destination = destination_header<channel>;
* @brief Stores sender, receiver, and message priority.
*/ using actor_destination = destination_header<abstract_actor_ptr>;
template<typename T = channel_ptr>
struct destination_header {
T receiver;
message_priority priority;
template<typename U>
destination_header(U&& dest, message_priority mp = message_priority::normal)
: receiver(std::forward<U>(dest)), priority(mp) { }
destination_header(destination_header&&) = default;
destination_header(const destination_header&) = default;
destination_header& operator=(destination_header&&) = default;
destination_header& operator=(const destination_header&) = default;
};
using channel_destination = destination_header<channel_ptr>;
using actor_destination = destination_header<actor_ptr>;
/** /**
* @brief Sends @p what to the receiver specified in @p hdr. * @brief Sends @p what to the receiver specified in @p hdr.
......
...@@ -38,18 +38,15 @@ ...@@ -38,18 +38,15 @@
#include "cppa/typed_actor.hpp" #include "cppa/typed_actor.hpp"
#include "cppa/prioritizing.hpp" #include "cppa/prioritizing.hpp"
#include "cppa/spawn_options.hpp" #include "cppa/spawn_options.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
namespace cppa { namespace cppa {
/** @cond PRIVATE */ /** @cond PRIVATE */
inline actor_ptr eval_sopts(spawn_options opts, local_actor_ptr ptr) { constexpr bool unbound_spawn_options(spawn_options opts) {
CPPA_LOGF_INFO("spawned new local actor with ID " << ptr->id() return !has_monitor_flag(opts) && !has_link_flag(opts);
<< " of type " << detail::demangle(typeid(*ptr)));
if (has_monitor_flag(opts)) self->monitor(ptr);
if (has_link_flag(opts)) self->link_to(ptr);
return ptr;
} }
/** @endcond */ /** @endcond */
...@@ -63,15 +60,16 @@ inline actor_ptr eval_sopts(spawn_options opts, local_actor_ptr ptr) { ...@@ -63,15 +60,16 @@ inline actor_ptr eval_sopts(spawn_options opts, local_actor_ptr ptr) {
* @brief Spawns a new {@link actor} that evaluates given arguments. * @brief Spawns a new {@link actor} that evaluates given arguments.
* @param args A functor followed by its arguments. * @param args A functor followed by its arguments.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior. * @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}. * @returns An {@link actor} to the spawned {@link actor}.
*/ */
template<spawn_options Options = no_spawn_options, typename... Ts> template<spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn(Ts&&... args) { actor spawn(Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "too few arguments provided"); static_assert(sizeof...(Ts) > 0, "too few arguments provided");
return eval_sopts(Options, static_assert(unbound_spawn_options(Options),
get_scheduler()->exec(Options, "top-level spawns cannot have monitor or link flag");
scheduler::init_callback{}, return get_scheduler()->exec(Options,
std::forward<Ts>(args)...)); scheduler::init_callback{},
std::forward<Ts>(args)...);
} }
/** /**
...@@ -79,12 +77,14 @@ actor_ptr spawn(Ts&&... args) { ...@@ -79,12 +77,14 @@ actor_ptr spawn(Ts&&... args) {
* @param args Constructor arguments. * @param args Constructor arguments.
* @tparam Impl Subtype of {@link event_based_actor} or {@link sb_actor}. * @tparam Impl Subtype of {@link event_based_actor} or {@link sb_actor}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior. * @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}. * @returns An {@link actor} to the spawned {@link actor}.
*/ */
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts> template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn(Ts&&... args) { actor spawn(Ts&&... args) {
static_assert(std::is_base_of<event_based_actor, Impl>::value, static_assert(std::is_base_of<event_based_actor, Impl>::value,
"Impl is not a derived type of event_based_actor"); "Impl is not a derived type of event_based_actor");
static_assert(unbound_spawn_options(Options),
"top-level spawns cannot have monitor or link flag");
scheduled_actor_ptr ptr; scheduled_actor_ptr ptr;
if (has_priority_aware_flag(Options)) { if (has_priority_aware_flag(Options)) {
using derived = typename extend<Impl>::template with<threaded, prioritizing>; using derived = typename extend<Impl>::template with<threaded, prioritizing>;
...@@ -95,7 +95,7 @@ actor_ptr spawn(Ts&&... args) { ...@@ -95,7 +95,7 @@ actor_ptr spawn(Ts&&... args) {
ptr = make_counted<derived>(std::forward<Ts>(args)...); ptr = make_counted<derived>(std::forward<Ts>(args)...);
} }
else ptr = make_counted<Impl>(std::forward<Ts>(args)...); else ptr = make_counted<Impl>(std::forward<Ts>(args)...);
return eval_sopts(Options, get_scheduler()->exec(Options, std::move(ptr))); return get_scheduler()->exec(Options, std::move(ptr));
} }
/** /**
...@@ -103,11 +103,11 @@ actor_ptr spawn(Ts&&... args) { ...@@ -103,11 +103,11 @@ actor_ptr spawn(Ts&&... args) {
* immediately joins @p grp. * immediately joins @p grp.
* @param args A functor followed by its arguments. * @param args A functor followed by its arguments.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior. * @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}. * @returns An {@link actor} to the spawned {@link actor}.
* @note The spawned has joined the group before this function returns. * @note The spawned has joined the group before this function returns.
*/ */
template<spawn_options Options = no_spawn_options, typename... Ts> template<spawn_options Options = no_spawn_options, typename... Ts>
actor_ptr spawn_in_group(const group_ptr& grp, Ts&&... args) { actor spawn_in_group(const group_ptr& grp, Ts&&... args) {
static_assert(sizeof...(Ts) > 0, "too few arguments provided"); static_assert(sizeof...(Ts) > 0, "too few arguments provided");
auto init_cb = [=](local_actor* ptr) { auto init_cb = [=](local_actor* ptr) {
ptr->join(grp); ptr->join(grp);
...@@ -123,11 +123,11 @@ actor_ptr spawn_in_group(const group_ptr& grp, Ts&&... args) { ...@@ -123,11 +123,11 @@ actor_ptr spawn_in_group(const group_ptr& grp, Ts&&... args) {
* @param args Constructor arguments. * @param args Constructor arguments.
* @tparam Impl Subtype of {@link event_based_actor} or {@link sb_actor}. * @tparam Impl Subtype of {@link event_based_actor} or {@link sb_actor}.
* @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior. * @tparam Options Optional flags to modify <tt>spawn</tt>'s behavior.
* @returns An {@link actor_ptr} to the spawned {@link actor}. * @returns An {@link actor} to the spawned {@link actor}.
* @note The spawned has joined the group before this function returns. * @note The spawned has joined the group before this function returns.
*/ */
template<class Impl, spawn_options Options, typename... Ts> template<class Impl, spawn_options Options, typename... Ts>
actor_ptr spawn_in_group(const group_ptr& grp, Ts&&... args) { actor spawn_in_group(const group_ptr& grp, Ts&&... args) {
auto ptr = make_counted<Impl>(std::forward<Ts>(args)...); auto ptr = make_counted<Impl>(std::forward<Ts>(args)...);
ptr->join(grp); ptr->join(grp);
return eval_sopts(Options, get_scheduler()->exec(Options, ptr)); return eval_sopts(Options, get_scheduler()->exec(Options, ptr));
...@@ -145,8 +145,9 @@ typename Impl::typed_pointer_type spawn_typed(Ts&&... args) { ...@@ -145,8 +145,9 @@ typename Impl::typed_pointer_type spawn_typed(Ts&&... args) {
); );
} }
/*TODO:
template<spawn_options Options, typename... Ts> template<spawn_options Options, typename... Ts>
typed_actor_ptr<typename detail::deduce_signature<Ts>::type...> typed_actor<typename detail::deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>& me) { spawn_typed(const match_expr<Ts...>& me) {
static_assert(util::conjunction< static_assert(util::conjunction<
detail::match_expr_has_no_guard<Ts>::value... detail::match_expr_has_no_guard<Ts>::value...
...@@ -166,7 +167,7 @@ spawn_typed(const match_expr<Ts...>& me) { ...@@ -166,7 +167,7 @@ spawn_typed(const match_expr<Ts...>& me) {
} }
template<typename... Ts> template<typename... Ts>
typed_actor_ptr<typename detail::deduce_signature<Ts>::type...> typed_actor<typename detail::deduce_signature<Ts>::type...>
spawn_typed(const match_expr<Ts...>& me) { spawn_typed(const match_expr<Ts...>& me) {
return spawn_typed<no_spawn_options>(me); return spawn_typed<no_spawn_options>(me);
} }
...@@ -180,6 +181,7 @@ auto spawn_typed(T0&& v0, T1&& v1, Ts&&... vs) ...@@ -180,6 +181,7 @@ auto spawn_typed(T0&& v0, T1&& v1, Ts&&... vs)
std::forward<T1>(v1), std::forward<T1>(v1),
std::forward<Ts>(vs)...)); std::forward<Ts>(vs)...));
} }
*/
/** @} */ /** @} */
......
...@@ -93,7 +93,7 @@ constexpr spawn_options detached = spawn_options::detach_flag; ...@@ -93,7 +93,7 @@ constexpr spawn_options detached = spawn_options::detach_flag;
/** /**
* @brief Causes the runtime to ignore the new actor in * @brief Causes the runtime to ignore the new actor in
* {@link await_all_others_done()}. * {@link await_all_actors_done()}.
*/ */
constexpr spawn_options hidden = spawn_options::hide_flag; constexpr spawn_options hidden = spawn_options::hide_flag;
......
...@@ -41,7 +41,6 @@ ...@@ -41,7 +41,6 @@
#include "cppa/util/dptr.hpp" #include "cppa/util/dptr.hpp"
#include "cppa/detail/behavior_stack.hpp"
#include "cppa/detail/receive_policy.hpp" #include "cppa/detail/receive_policy.hpp"
namespace cppa { namespace cppa {
...@@ -64,22 +63,140 @@ class stacked : public Base { ...@@ -64,22 +63,140 @@ class stacked : public Base {
static constexpr auto receive_flag = detail::rp_nestable; static constexpr auto receive_flag = detail::rp_nestable;
void dequeue(behavior& bhvr) override { struct receive_while_helper {
++m_nested_count;
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr);
--m_nested_count;
check_quit();
}
void dequeue_response(behavior& bhvr, message_id request_id) override { std::function<void(behavior&)> m_dq;
++m_nested_count; std::function<bool()> m_stmt;
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr, request_id);
--m_nested_count; template<typename... Ts>
check_quit(); void operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0,
"operator() requires at least one argument");
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...);
while (m_stmt()) m_dq(bhvr);
}
};
template<typename T>
struct receive_for_helper {
std::function<void(behavior&)> m_dq;
T& begin;
T end;
template<typename... Ts>
void operator()(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...);
for ( ; begin != end; ++begin) m_dq(bhvr);
}
};
struct do_receive_helper {
std::function<void(behavior&)> m_dq;
behavior m_bhvr;
template<typename Statement>
void until(Statement stmt) {
do { m_dq(m_bhvr); }
while (stmt() == false);
}
};
/**
* @brief Dequeues the next message from the mailbox that
* is matched by given behavior.
*/
template<typename... Ts>
void receive(Ts&&... args) {
static_assert(sizeof...(Ts), "receive() requires at least one argument");
dequeue(match_expr_convert(std::forward<Ts>(args)...));
}
/**
* @brief Receives messages in an endless loop.
* Semantically equal to: <tt>for (;;) { receive(...); }</tt>
*/
template<typename... Ts>
void receive_loop(Ts&&... args) {
behavior bhvr = match_expr_convert(std::forward<Ts>(args)...);
for (;;) dequeue(bhvr);
}
/**
* @brief Receives messages as in a range-based loop.
*
* Semantically equal to:
* <tt>for ( ; begin != end; ++begin) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_for(i, 10) (
* on(atom("get")) >> [&]() -> any_tuple { return {"result", i}; }
* );
* @endcode
* @param begin First value in range.
* @param end Last value in range (excluded).
* @returns A functor implementing the loop.
*/
template<typename T>
receive_for_helper<T> receive_for(T& begin, const T& end) {
return {make_dequeue_callback(), begin, end};
}
/**
* @brief Receives messages as long as @p stmt returns true.
*
* Semantically equal to: <tt>while (stmt()) { receive(...); }</tt>.
*
* <b>Usage example:</b>
* @code
* int i = 0;
* receive_while([&]() { return (++i <= 10); })
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* );
* @endcode
* @param stmt Lambda expression, functor or function returning a @c bool.
* @returns A functor implementing the loop.
*/
template<typename Statement>
receive_while_helper receive_while(Statement stmt) {
static_assert(std::is_same<bool, decltype(stmt())>::value,
"functor or function does not return a boolean");
return {make_dequeue_callback(), stmt};
}
/**
* @brief Receives messages until @p stmt returns true.
*
* Semantically equal to: <tt>do { receive(...); } while (stmt() == false);</tt>
*
* <b>Usage example:</b>
* @code
* int i = 0;
* do_receive
* (
* on<int>() >> int_fun,
* on<float>() >> float_fun
* )
* .until([&]() { return (++i >= 10); };
* @endcode
* @param bhvr Denotes the actor's response the next incoming message.
* @returns A functor providing the @c until member function.
*/
template<typename... Ts>
do_receive_helper do_receive(Ts&&... args) {
return { make_dequeue_callback()
, match_expr_convert(std::forward<Ts>(args)...)};
} }
virtual void run() { virtual void run() {
exec_behavior_stack();
if (m_behavior) m_behavior(); if (m_behavior) m_behavior();
auto dthis = util::dptr<Subtype>(this); auto dthis = util::dptr<Subtype>(this);
auto rsn = dthis->planned_exit_reason(); auto rsn = dthis->planned_exit_reason();
...@@ -90,38 +207,13 @@ class stacked : public Base { ...@@ -90,38 +207,13 @@ class stacked : public Base {
m_behavior = std::move(fun); m_behavior = std::move(fun);
} }
void exec_behavior_stack() override {
m_in_bhvr_loop = true;
auto dthis = util::dptr<Subtype>(this);
if (!stack_empty() && !m_nested_count) {
while (!stack_empty()) {
++m_nested_count;
dthis->m_bhvr_stack.exec(m_recv_policy, dthis);
--m_nested_count;
check_quit();
}
}
m_in_bhvr_loop = false;
}
protected: protected:
template<typename... Ts> template<typename... Ts>
stacked(Ts&&... args) : Base(std::forward<Ts>(args)...) stacked(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
, m_in_bhvr_loop(false)
, m_nested_count(0) { }
void do_become(behavior&& bhvr, bool discard_old) override {
become_impl(std::move(bhvr), discard_old, message_id());
}
void become_waiting_for(behavior bhvr, message_id mid) override {
become_impl(std::move(bhvr), false, mid);
}
virtual bool has_behavior() { virtual bool has_behavior() {
return static_cast<bool>(m_behavior) return static_cast<bool>(m_behavior);
|| !util::dptr<Subtype>(this)->m_bhvr_stack.empty();
} }
std::function<void()> m_behavior; std::function<void()> m_behavior;
...@@ -129,43 +221,18 @@ class stacked : public Base { ...@@ -129,43 +221,18 @@ class stacked : public Base {
private: private:
inline bool stack_empty() { std::function<void(behavior&)> make_dequeue_callback() {
return util::dptr<Subtype>(this)->m_bhvr_stack.empty(); return [=](behavior& bhvr) { dequeue(bhvr); };
} }
void become_impl(behavior&& bhvr, bool discard_old, message_id mid) { void dequeue(behavior& bhvr) {
auto dthis = util::dptr<Subtype>(this); m_recv_policy.receive(util::dptr<Subtype>(this), bhvr);
if (bhvr.timeout().valid()) {
dthis->reset_timeout();
dthis->request_timeout(bhvr.timeout());
}
if (!dthis->m_bhvr_stack.empty() && discard_old) {
dthis->m_bhvr_stack.pop_async_back();
}
dthis->m_bhvr_stack.push_back(std::move(bhvr), mid);
} }
void check_quit() { void dequeue_response(behavior& bhvr, message_id request_id) {
// do nothing if other message handlers are still running m_recv_policy.receive(util::dptr<Subtype>(this), bhvr, request_id);
if (m_nested_count > 0) return;
auto dthis = util::dptr<Subtype>(this);
auto rsn = dthis->planned_exit_reason();
if (rsn != exit_reason::not_exited) {
dthis->on_exit();
if (stack_empty()) {
dthis->cleanup(rsn);
throw actor_exited(rsn);
}
else {
dthis->planned_exit_reason(exit_reason::not_exited);
if (!m_in_bhvr_loop) exec_behavior_stack();
}
}
} }
bool m_in_bhvr_loop;
size_t m_nested_count;
}; };
} // namespace cppa } // namespace cppa
......
...@@ -31,20 +31,52 @@ ...@@ -31,20 +31,52 @@
#ifndef CPPA_STACKLESS_HPP #ifndef CPPA_STACKLESS_HPP
#define CPPA_STACKLESS_HPP #define CPPA_STACKLESS_HPP
#include "cppa/util/dptr.hpp"
#include "cppa/detail/receive_policy.hpp" #include "cppa/detail/receive_policy.hpp"
#include "cppa/detail/behavior_stack.hpp"
namespace cppa { namespace cppa {
#ifdef CPPA_DOCUMENTATION
/** /**
* @brief An actor that uses the non-blocking API of @p libcppa and * @brief Policy tag that causes {@link event_based_actor::become} to
* does not has its own stack. * discard the current behavior.
* @relates local_actor
*/ */
constexpr auto discard_behavior;
/**
* @brief Policy tag that causes {@link event_based_actor::become} to
* keep the current behavior available.
* @relates local_actor
*/
constexpr auto keep_behavior;
#else
template<bool DiscardBehavior>
struct behavior_policy { static constexpr bool discard_old = DiscardBehavior; };
template<typename T>
struct is_behavior_policy : std::false_type { };
template<bool DiscardBehavior>
struct is_behavior_policy<behavior_policy<DiscardBehavior>> : std::true_type { };
typedef behavior_policy<false> keep_behavior_t;
typedef behavior_policy<true > discard_behavior_t;
constexpr discard_behavior_t discard_behavior = discard_behavior_t{};
constexpr keep_behavior_t keep_behavior = keep_behavior_t{};
#endif
template<class Base, class Subtype> template<class Base, class Subtype>
class stackless : public Base { class stackless : public Base {
friend class detail::receive_policy;
friend class detail::behavior_stack;
protected: protected:
typedef stackless combined_type; typedef stackless combined_type;
...@@ -60,15 +92,30 @@ class stackless : public Base { ...@@ -60,15 +92,30 @@ class stackless : public Base {
return this->m_bhvr_stack.empty() == false; return this->m_bhvr_stack.empty() == false;
} }
protected: void unbecome() {
this->m_bhvr_stack.pop_async_back();
void do_become(behavior&& bhvr, bool discard_old) {
this->reset_timeout();
this->request_timeout(bhvr.timeout());
if (discard_old) this->m_bhvr_stack.pop_async_back();
this->m_bhvr_stack.push_back(std::move(bhvr));
} }
/**
* @brief Sets the actor's behavior and discards the previous behavior
* unless {@link keep_behavior} is given as first argument.
*/
template<typename T, typename... Ts>
inline typename std::enable_if<
!is_behavior_policy<typename util::rm_const_and_ref<T>::type>::value,
void
>::type
become(T&& arg, Ts&&... args) {
do_become(match_expr_convert(std::forward<T>(arg),
std::forward<Ts>(args)...),
true);
}
template<bool Discard, typename... Ts>
inline void become(behavior_policy<Discard>, Ts&&... args) {
do_become(match_expr_convert(std::forward<Ts>(args)...), Discard);
}
void become_waiting_for(behavior bhvr, message_id mf) { void become_waiting_for(behavior bhvr, message_id mf) {
if (bhvr.timeout().valid()) { if (bhvr.timeout().valid()) {
this->reset_timeout(); this->reset_timeout();
...@@ -76,16 +123,23 @@ class stackless : public Base { ...@@ -76,16 +123,23 @@ class stackless : public Base {
} }
this->m_bhvr_stack.push_back(std::move(bhvr), mf); this->m_bhvr_stack.push_back(std::move(bhvr), mf);
} }
void do_become(behavior&& bhvr, bool discard_old) {
this->reset_timeout();
this->request_timeout(bhvr.timeout());
if (discard_old) this->m_bhvr_stack.pop_async_back();
this->m_bhvr_stack.push_back(std::move(bhvr));
}
inline bool has_behavior() const { inline bool has_behavior() const {
return this->m_bhvr_stack.empty() == false; return this->m_bhvr_stack.empty() == false;
} }
inline behavior& get_behavior() { inline behavior& get_behavior() {
CPPA_REQUIRE(this->m_bhvr_stack.empty() == false); CPPA_REQUIRE(this->m_bhvr_stack.empty() == false);
return this->m_bhvr_stack.back(); return this->m_bhvr_stack.back();
} }
inline void handle_timeout(behavior& bhvr) { inline void handle_timeout(behavior& bhvr) {
CPPA_REQUIRE(bhvr.timeout().valid()); CPPA_REQUIRE(bhvr.timeout().valid());
this->reset_timeout(); this->reset_timeout();
...@@ -95,44 +149,18 @@ class stackless : public Base { ...@@ -95,44 +149,18 @@ class stackless : public Base {
} }
} }
// provoke compiler errors for usage of receive() and related functions void exec_bhvr_stack() {
while (!m_bhvr_stack.empty()) {
/** m_bhvr_stack.exec(m_recv_policy, util::dptr<Subtype>(this));
* @brief Provokes a compiler error to ensure that a stackless actor }
* does not accidently uses receive() instead of become().
*/
template<typename... Ts>
void receive(Ts&&...) {
// this asssertion always fails
static_assert((sizeof...(Ts) + 1) < 1,
"You shall not use receive in an event-based actor. "
"Use become() instead.");
}
/**
* @brief Provokes a compiler error.
*/
template<typename... Ts>
void receive_loop(Ts&&... args) {
receive(std::forward<Ts>(args)...);
} }
/** protected:
* @brief Provokes a compiler error.
*/
template<typename... Ts>
void receive_while(Ts&&... args) {
receive(std::forward<Ts>(args)...);
}
/** // allows actors to keep previous behaviors and enables unbecome()
* @brief Provokes a compiler error. detail::behavior_stack m_bhvr_stack;
*/
template<typename... Ts>
void do_receive(Ts&&... args) {
receive(std::forward<Ts>(args)...);
}
// used for message handling in subclasses
detail::receive_policy m_recv_policy; detail::receive_policy m_recv_policy;
}; };
......
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <chrono> #include <chrono>
#include <condition_variable> #include <condition_variable>
#include "cppa/exit_reason.hpp"
#include "cppa/mailbox_element.hpp" #include "cppa/mailbox_element.hpp"
#include "cppa/util/dptr.hpp" #include "cppa/util/dptr.hpp"
...@@ -93,10 +94,6 @@ class threaded : public Base { ...@@ -93,10 +94,6 @@ class threaded : public Base {
// init() did indeed call quit() for some reason // init() did indeed call quit() for some reason
dthis->on_exit(); dthis->on_exit();
} }
while (!dthis->m_bhvr_stack.empty()) {
dthis->m_bhvr_stack.exec(dthis->m_recv_policy, dthis);
dthis->on_exit();
}
auto rsn = dthis->planned_exit_reason(); auto rsn = dthis->planned_exit_reason();
dthis->cleanup(rsn == exit_reason::not_exited ? exit_reason::normal : rsn); dthis->cleanup(rsn == exit_reason::not_exited ? exit_reason::normal : rsn);
} }
...@@ -137,11 +134,6 @@ class threaded : public Base { ...@@ -137,11 +134,6 @@ class threaded : public Base {
enqueue_impl(this->m_mailbox, hdr, std::move(msg)); enqueue_impl(this->m_mailbox, hdr, std::move(msg));
} }
bool chained_enqueue(const message_header& hdr, any_tuple msg) override {
enqueue(hdr, std::move(msg));
return false;
}
timeout_type init_timeout(const util::duration& rel_time) { timeout_type init_timeout(const util::duration& rel_time) {
auto result = std::chrono::high_resolution_clock::now(); auto result = std::chrono::high_resolution_clock::now();
result += rel_time; result += rel_time;
......
...@@ -31,7 +31,9 @@ ...@@ -31,7 +31,9 @@
#ifndef CPPA_THREADLESS_HPP #ifndef CPPA_THREADLESS_HPP
#define CPPA_THREADLESS_HPP #define CPPA_THREADLESS_HPP
#include "cppa/send.hpp" #include "cppa/atom.hpp"
#include "cppa/behavior.hpp"
#include "cppa/util/duration.hpp"
namespace cppa { namespace cppa {
...@@ -67,11 +69,11 @@ class threadless : public Base { ...@@ -67,11 +69,11 @@ class threadless : public Base {
auto msg = make_any_tuple(atom("SYNC_TOUT"), ++m_pending_tout); auto msg = make_any_tuple(atom("SYNC_TOUT"), ++m_pending_tout);
if (d.is_zero()) { if (d.is_zero()) {
// immediately enqueue timeout message if duration == 0s // immediately enqueue timeout message if duration == 0s
this->enqueue(this, std::move(msg)); this->enqueue({this->address(), this}, std::move(msg));
//auto e = this->new_mailbox_element(this, std::move(msg)); //auto e = this->new_mailbox_element(this, std::move(msg));
//this->m_mailbox.enqueue(e); //this->m_mailbox.enqueue(e);
} }
else delayed_send_tuple(this, d, std::move(msg)); else this->delayed_send_tuple(this, d, std::move(msg));
m_has_pending_tout = true; m_has_pending_tout = true;
} }
} }
......
...@@ -68,7 +68,7 @@ inline std::string to_string(const message_header& what) { ...@@ -68,7 +68,7 @@ inline std::string to_string(const message_header& what) {
return detail::to_string_impl(what); return detail::to_string_impl(what);
} }
inline std::string to_string(const actor_ptr& what) { inline std::string to_string(const actor& what) {
return detail::to_string_impl(what); return detail::to_string_impl(what);
} }
...@@ -76,7 +76,7 @@ inline std::string to_string(const group_ptr& what) { ...@@ -76,7 +76,7 @@ inline std::string to_string(const group_ptr& what) {
return detail::to_string_impl(what); return detail::to_string_impl(what);
} }
inline std::string to_string(const channel_ptr& what) { inline std::string to_string(const channel& what) {
return detail::to_string_impl(what); return detail::to_string_impl(what);
} }
......
...@@ -25,75 +25,33 @@ ...@@ -25,75 +25,33 @@
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_TYPED_ACTOR_HPP #ifndef CPPA_TYPED_ACTOR_HPP
#define CPPA_TYPED_ACTOR_HPP #define CPPA_TYPED_ACTOR_HPP
#include "cppa/replies_to.hpp" #include "cppa/intrusive_ptr.hpp"
#include "cppa/typed_behavior.hpp" #include "cppa/abstract_actor.hpp"
#include "cppa/message_future.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/detail/typed_actor_util.hpp"
namespace cppa { namespace cppa {
template<typename... Signatures> class local_actor;
class typed_actor_ptr;
template<typename... Signatures>
class typed_actor : public event_based_actor {
public:
using signatures = util::type_list<Signatures...>;
using behavior_type = typed_behavior<Signatures...>;
using typed_pointer_type = typed_actor_ptr<Signatures...>; /**
* @brief Identifies an untyped actor.
*/
template<typename Interface>
class typed_actor {
protected: friend class local_actor;
virtual behavior_type make_behavior() = 0;
void init() final {
auto bhvr = make_behavior();
m_bhvr_stack.push_back(std::move(bhvr.unbox()));
}
void do_become(behavior&&, bool) final {
CPPA_LOG_ERROR("typed actors are not allowed to call become()");
quit(exit_reason::unallowed_function_call);
}
};
} // namespace cppa
namespace cppa { namespace detail {
template<typename... Signatures>
class default_typed_actor : public typed_actor<Signatures...> {
public:
template<typename... Cases>
default_typed_actor(match_expr<Cases...> expr) : m_bhvr(std::move(expr)) { }
protected:
typed_behavior<Signatures...> make_behavior() override {
return m_bhvr;
}
private: private:
typed_behavior<Signatures...> m_bhvr; intrusive_ptr<abstract_actor> m_ptr;
}; };
} } // namespace cppa::detail } // namespace cppa
#endif // CPPA_TYPED_ACTOR_HPP #endif // CPPA_TYPED_ACTOR_HPP
...@@ -28,81 +28,72 @@ ...@@ -28,81 +28,72 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_RECEIVE_LOOP_HELPER_HPP #ifndef CPPA_TYPED_ACTOR_HPP
#define CPPA_RECEIVE_LOOP_HELPER_HPP #define CPPA_TYPED_ACTOR_HPP
#include <new> #include "cppa/replies_to.hpp"
#include "cppa/typed_behavior.hpp"
#include "cppa/message_future.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/self.hpp" #include "cppa/detail/typed_actor_util.hpp"
#include "cppa/behavior.hpp"
#include "cppa/match_expr.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/partial_function.hpp"
#include "cppa/util/type_list.hpp" namespace cppa {
namespace cppa { namespace detail { template<typename... Signatures>
class typed_actor_ptr;
template<typename Statement> template<typename... Signatures>
struct receive_while_helper { class typed_actor : public event_based_actor {
Statement m_stmt;
template<typename S> public:
receive_while_helper(S&& stmt) : m_stmt(std::forward<S>(stmt)) { }
template<typename... Ts> using signatures = util::type_list<Signatures...>;
void operator()(Ts&&... args) {
static_assert(sizeof...(Ts) > 0,
"operator() requires at least one argument");
behavior tmp = match_expr_convert(std::forward<Ts>(args)...);
local_actor* sptr = self;
while (m_stmt()) sptr->dequeue(tmp);
}
}; using behavior_type = typed_behavior<Signatures...>;
template<typename T> using typed_pointer_type = typed_actor_ptr<Signatures...>;
class receive_for_helper {
T& begin; protected:
T end;
public: virtual behavior_type make_behavior() = 0;
receive_for_helper(T& first, const T& last) : begin(first), end(last) { } void init() final {
auto bhvr = make_behavior();
m_bhvr_stack.push_back(std::move(bhvr.unbox()));
}
template<typename... Ts> void do_become(behavior&&, bool) final {
void operator()(Ts&&... args) { CPPA_LOG_ERROR("typed actors are not allowed to call become()");
auto tmp = match_expr_convert(std::forward<Ts>(args)...); quit(exit_reason::unallowed_function_call);
local_actor* sptr = self;
for ( ; begin != end; ++begin) sptr->dequeue(tmp);
} }
}; };
class do_receive_helper { } // namespace cppa
namespace cppa { namespace detail {
behavior m_bhvr; template<typename... Signatures>
class default_typed_actor : public typed_actor<Signatures...> {
public: public:
inline do_receive_helper(behavior&& bhvr) : m_bhvr(std::move(bhvr)) { } template<typename... Cases>
default_typed_actor(match_expr<Cases...> expr) : m_bhvr(std::move(expr)) { }
do_receive_helper(do_receive_helper&&) = default; protected:
template<typename Statement> typed_behavior<Signatures...> make_behavior() override {
void until(Statement&& stmt) { return m_bhvr;
static_assert(std::is_same<bool, decltype(stmt())>::value,
"functor or function does not return a boolean");
local_actor* sptr = self;
do {
sptr->dequeue(m_bhvr);
}
while (stmt() == false);
} }
private:
typed_behavior<Signatures...> m_bhvr;
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
#endif // CPPA_RECEIVE_LOOP_HELPER_HPP #endif // CPPA_TYPED_ACTOR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_UNTYPED_ACTOR_HPP
#define CPPA_UNTYPED_ACTOR_HPP
#include "cppa/extend.hpp"
#include "cppa/stackless.hpp"
#include "cppa/local_actor.hpp"
namespace cppa {
class untyped_actor : extend<local_actor>::with<stackless> {
};
} // namespace cppa
#endif // CPPA_UNTYPED_ACTOR_HPP
...@@ -164,9 +164,9 @@ struct is_builtin { ...@@ -164,9 +164,9 @@ struct is_builtin {
atom_value, atom_value,
any_tuple, any_tuple,
message_header, message_header,
actor_ptr, actor,
group_ptr, group_ptr,
channel_ptr, channel,
node_id_ptr node_id_ptr
>::value; >::value;
}; };
......
...@@ -401,7 +401,7 @@ int main() { ...@@ -401,7 +401,7 @@ int main() {
aout << color::cyan aout << color::cyan
<< "await CURL; this may take a while (press CTRL+C again to abort)" << "await CURL; this may take a while (press CTRL+C again to abort)"
<< color::reset_endl; << color::reset_endl;
await_all_others_done(); await_all_actors_done();
// shutdown libcppa // shutdown libcppa
shutdown(); shutdown();
// shutdown CURL // shutdown CURL
......
...@@ -37,7 +37,7 @@ int main() { ...@@ -37,7 +37,7 @@ int main() {
// create another actor that calls 'hello_world(mirror_actor)' // create another actor that calls 'hello_world(mirror_actor)'
spawn(hello_world, mirror_actor); spawn(hello_world, mirror_actor);
// wait until all other actors we have spawned are done // wait until all other actors we have spawned are done
await_all_others_done(); await_all_actors_done();
// run cleanup code before exiting main // run cleanup code before exiting main
shutdown(); shutdown();
} }
...@@ -74,7 +74,7 @@ void tester(const actor_ptr& testee) { ...@@ -74,7 +74,7 @@ void tester(const actor_ptr& testee) {
int main() { int main() {
spawn(tester, spawn(calculator)); spawn(tester, spawn(calculator));
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
......
...@@ -73,7 +73,7 @@ void dancing_kirby() { ...@@ -73,7 +73,7 @@ void dancing_kirby() {
int main() { int main() {
spawn(dancing_kirby); spawn(dancing_kirby);
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -184,7 +184,7 @@ int main(int, char**) { ...@@ -184,7 +184,7 @@ int main(int, char**) {
spawn<philosopher>(names[i], chopsticks[i], chopsticks[(i+1)%5]); spawn<philosopher>(names[i], chopsticks[i], chopsticks[(i+1)%5]);
} }
// real philosophers are never done // real philosophers are never done
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -216,7 +216,7 @@ int main(int argc, char** argv) { ...@@ -216,7 +216,7 @@ int main(int argc, char** argv) {
if (host.empty()) host = "localhost"; if (host.empty()) host = "localhost";
client_repl(host, port); client_repl(host, port);
} }
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -143,7 +143,7 @@ int main(int argc, char** argv) { ...@@ -143,7 +143,7 @@ int main(int argc, char** argv) {
); );
// force actor to quit // force actor to quit
send_exit(client_actor, exit_reason::user_shutdown); send_exit(client_actor, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -118,7 +118,7 @@ int main(int, char**) { ...@@ -118,7 +118,7 @@ int main(int, char**) {
// send t a foo_pair2 // send t a foo_pair2
send(t, foo_pair2{3, 4}); send(t, foo_pair2{3, 4});
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
......
...@@ -58,7 +58,7 @@ int main(int, char**) { ...@@ -58,7 +58,7 @@ int main(int, char**) {
make_pair(&foo::b, &foo::set_b)); make_pair(&foo::b, &foo::set_b));
auto t = spawn(testee); auto t = spawn(testee);
send(t, foo{1, 2}); send(t, foo{1, 2});
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -79,7 +79,7 @@ int main(int, char**) { ...@@ -79,7 +79,7 @@ int main(int, char**) {
// spawn a new testee and send it a foo // spawn a new testee and send it a foo
send(spawn(testee), foo{1, 2}); send(spawn(testee), foo{1, 2});
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
......
...@@ -129,7 +129,7 @@ int main(int, char**) { ...@@ -129,7 +129,7 @@ int main(int, char**) {
auto t = spawn(testee, 2); auto t = spawn(testee, 2);
send(t, bar{foo{1, 2}, 3}); send(t, bar{foo{1, 2}, 3});
send(t, baz{foo{1, 2}, bar{foo{3, 4}, 5}}); send(t, baz{foo{1, 2}, bar{foo{3, 4}, 5}});
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
......
...@@ -201,7 +201,7 @@ int main() { ...@@ -201,7 +201,7 @@ int main() {
tvec.push_back(t0); tvec.push_back(t0);
send(t, tvec); send(t, tvec);
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -28,168 +28,185 @@ ...@@ -28,168 +28,185 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_ACTOR_COMPANION_MIXIN_HPP #include "cppa/config.hpp"
#define CPPA_ACTOR_COMPANION_MIXIN_HPP
#include <mutex> // std::lock_guard #include <map>
#include <memory> // std::unique_ptr #include <mutex>
#include <atomic>
#include <stdexcept>
#include "cppa/self.hpp" #include "cppa/config.hpp"
#include "cppa/actor.hpp" #include "cppa/logging.hpp"
#include "cppa/extend.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/match_expr.hpp" #include "cppa/singletons.hpp"
#include "cppa/local_actor.hpp" #include "cppa/actor_addr.hpp"
#include "cppa/partial_function.hpp" #include "cppa/abstract_actor.hpp"
#include "cppa/message_header.hpp"
#include "cppa/util/shared_spinlock.hpp" #include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp" #include "cppa/util/shared_lock_guard.hpp"
#include "cppa/detail/memory.hpp" #include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/singleton_manager.hpp"
namespace cppa { namespace cppa {
/** namespace { typedef std::unique_lock<std::mutex> guard_type; }
* @brief Adds co-existing objects (companions) to a class,
* which serve as gateways, thereby enabling libcppa's message passing.
*/
template<typename Base>
class actor_companion_mixin : public Base {
typedef Base super; // m_exit_reason is guaranteed to be set to 0, i.e., exit_reason::not_exited,
// by std::atomic<> constructor
public: abstract_actor::abstract_actor(actor_id aid)
: m_id(aid), m_is_proxy(true), m_exit_reason(exit_reason::not_exited) { }
typedef std::unique_ptr<mailbox_element, detail::disposer> message_pointer; abstract_actor::abstract_actor()
: m_id(get_actor_registry()->next_id()), m_is_proxy(false)
, m_exit_reason(exit_reason::not_exited) { }
template<typename... Ts> bool abstract_actor::link_to_impl(const actor_addr& other) {
actor_companion_mixin(Ts&&... args) : super(std::forward<Ts>(args)...) { if (other && other != this) {
m_self.reset(detail::memory::create<companion>(this)); guard_type guard{m_mtx};
} auto ptr = detail::actor_addr_cast<abstract_actor>(other);
// send exit message if already exited
~actor_companion_mixin() { if (exited()) {
m_self->disconnect(); ptr->enqueue({address(), ptr}, make_any_tuple(atom("EXIT"), exit_reason()));
}
/**
* @brief Returns a smart pointer to the companion object.
*/
inline actor_ptr as_actor() const { return m_self; }
protected:
/**
* @brief This callback is invoked by the companion object whenever a
* new messages arrives.
* @warning Implementation has to be thread-safe.
*/
virtual void new_message(message_pointer ptr) = 0;
/**
* @brief Defines the message handler.
* @note While the message handler is invoked, @p self will point
* to the companion object to enable function calls to send().
*/
template<typename... Ts>
void set_message_handler(Ts&&... args) {
m_message_handler = match_expr_convert(std::forward<Ts>(args)...);
}
/**
* @brief Invokes the message handler with @p msg.
* @note While the message handler is invoked, @p self will point
* to the companion object to enable function calls to send().
*/
void handle_message(const message_pointer& msg) {
if (!msg) return;
scoped_self_setter sss(m_self.get());
m_self->m_current_node = msg.get();
auto f = m_message_handler; // make sure ref count >= 2
f(msg->msg);
}
private:
class companion : public local_actor {
friend class actor_companion_mixin;
typedef util::shared_spinlock lock_type;
public:
companion(actor_companion_mixin* parent) : m_parent(parent) { }
void disconnect() {
{ // lifetime scope of guard
std::lock_guard<lock_type> guard(m_lock);
m_parent = nullptr;
}
cleanup(exit_reason::normal);
} }
// add link if not already linked to other
void enqueue(const message_header& hdr, any_tuple msg) override { // (checked by establish_backlink)
using std::move; else if (ptr->establish_backlink(address())) {
util::shared_lock_guard<lock_type> guard(m_lock); m_links.push_back(ptr);
if (!m_parent) return; return true;
message_pointer ptr;
ptr.reset(detail::memory::create<mailbox_element>(hdr, move(msg)));
m_parent->new_message(move(ptr));
}
bool initialized() const override { return true; }
void quit(std::uint32_t) override {
throw std::runtime_error("Using actor_companion_mixin::quit "
"is prohibited; use Qt's widget "
"management instead.");
} }
}
return false;
}
void dequeue(behavior&) override { bool abstract_actor::attach(attachable_ptr ptr) {
throw_no_recv(); if (ptr == nullptr) {
guard_type guard{m_mtx};
return m_exit_reason == exit_reason::not_exited;
}
std::uint32_t reason;
{ // lifetime scope of guard
guard_type guard{m_mtx};
reason = m_exit_reason;
if (reason == exit_reason::not_exited) {
m_attachables.push_back(std::move(ptr));
return true;
} }
}
void dequeue_response(behavior&, message_id) override { ptr->actor_exited(reason);
throw_no_recv(); return false;
}
void abstract_actor::detach(const attachable::token& what) {
attachable_ptr ptr;
{ // lifetime scope of guard
guard_type guard{m_mtx};
auto end = m_attachables.end();
auto i = std::find_if(
m_attachables.begin(), end,
[&](attachable_ptr& p) { return p->matches(what); });
if (i != end) {
ptr = std::move(*i);
m_attachables.erase(i);
} }
}
void become_waiting_for(behavior, message_id) override { // ptr will be destroyed here, without locked mutex
throw_no_become(); }
void abstract_actor::link_to(const actor_addr& other) {
static_cast<void>(link_to_impl(other));
}
void abstract_actor::unlink_from(const actor_addr& other) {
static_cast<void>(unlink_from_impl(other));
}
bool abstract_actor::remove_backlink(const actor_addr& other) {
if (other && other != this) {
guard_type guard{m_mtx};
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i != m_links.end()) {
m_links.erase(i);
return true;
} }
}
protected: return false;
}
void do_become(behavior&&, bool) override { throw_no_become(); }
bool abstract_actor::establish_backlink(const actor_addr& other) {
private: std::uint32_t reason = exit_reason::not_exited;
if (other && other != this) {
void throw_no_become() { guard_type guard{m_mtx};
throw std::runtime_error("actor_companion_companion " reason = m_exit_reason;
"does not support libcppa's " if (reason == exit_reason::not_exited) {
"become() API"); auto i = std::find(m_links.begin(), m_links.end(), other);
if (i == m_links.end()) {
m_links.push_back(detail::actor_addr_cast<abstract_actor>(other));
return true;
}
} }
}
void throw_no_recv() { // send exit message without lock
throw std::runtime_error("actor_companion_companion " if (reason != exit_reason::not_exited) {
"does not support libcppa's " //send_as(this, other, make_any_tuple(atom("EXIT"), reason));
"receive() API"); }
return false;
}
bool abstract_actor::unlink_from_impl(const actor_addr& other) {
if (!other) return false;
guard_type guard{m_mtx};
// remove_backlink returns true if this actor is linked to other
auto ptr = detail::actor_addr_cast<abstract_actor>(other);
if (!exited() && ptr->remove_backlink(address())) {
auto i = std::find(m_links.begin(), m_links.end(), ptr);
CPPA_REQUIRE(i != m_links.end());
m_links.erase(i);
return true;
}
return false;
}
actor_addr abstract_actor::address() const {
return actor_addr{const_cast<abstract_actor*>(this)};
}
void abstract_actor::cleanup(std::uint32_t reason) {
// log as 'actor'
CPPA_LOGM_TRACE("cppa::actor", CPPA_ARG(m_id) << ", " << CPPA_ARG(reason));
CPPA_REQUIRE(reason != exit_reason::not_exited);
// move everyhting out of the critical section before processing it
decltype(m_links) mlinks;
decltype(m_attachables) mattachables;
{ // lifetime scope of guard
guard_type guard{m_mtx};
if (m_exit_reason != exit_reason::not_exited) {
// already exited
return;
} }
m_exit_reason = reason;
// guards access to m_parent mlinks = std::move(m_links);
lock_type m_lock; mattachables = std::move(m_attachables);
// make sure lists are empty
// set to nullptr if this companion became detached m_links.clear();
actor_companion_mixin* m_parent; m_attachables.clear();
}
}; CPPA_LOGC_INFO_IF(not is_proxy(), "cppa::actor", __func__,
"actor with ID " << m_id << " had " << mlinks.size()
// used as 'self' before calling message handler << " links and " << mattachables.size()
intrusive_ptr<companion> m_self; << " attached functors; exit reason = " << reason
<< ", class = " << detail::demangle(typeid(*this)));
// user-defined message handler for incoming messages // send exit messages
partial_function m_message_handler; auto msg = make_any_tuple(atom("EXIT"), reason);
CPPA_LOGM_DEBUG("cppa::actor", "send EXIT to " << mlinks.size() << " links");
}; for (auto& aptr : mlinks) {
aptr->enqueue({address(), aptr, message_priority::high}, msg);
}
for (attachable_ptr& ptr : mattachables) {
ptr->actor_exited(reason);
}
}
} // namespace cppa } // namespace cppa
#endif // CPPA_ACTOR_COMPANION_MIXIN_HPP
...@@ -28,29 +28,10 @@ ...@@ -28,29 +28,10 @@
\******************************************************************************/ \******************************************************************************/
#ifndef FWD_HPP #include "cppa/abstract_channel.hpp"
#define FWD_HPP
#include "cppa/self.hpp" namespace cppa {
namespace cppa { namespace detail { abstract_channel::~abstract_channel() { }
template<typename T> } // namespace cppa
struct is_self {
typedef typename util::rm_const_and_ref<T>::type plain_type;
static constexpr bool value = std::is_same<plain_type, self_type>::value;
};
template<typename T, typename U>
auto fwd(U& arg, typename std::enable_if<!is_self<T>::value>::type* = 0)
-> decltype(std::forward<T>(arg)) {
return std::forward<T>(arg);
}
template<typename T, typename U>
local_actor* fwd(U& arg, typename std::enable_if<is_self<T>::value>::type* = 0){
return arg;
}
} } // namespace cppa::detail
#endif // FWD_HPP
...@@ -25,182 +25,38 @@ ...@@ -25,182 +25,38 @@
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#include "cppa/config.hpp" #include <utility>
#include <map>
#include <mutex>
#include <atomic>
#include <stdexcept>
#include "cppa/send.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/config.hpp" #include "cppa/channel.hpp"
#include "cppa/logging.hpp" #include "cppa/actor_addr.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/local_actor.hpp"
#include "cppa/singletons.hpp"
#include "cppa/message_header.hpp"
#include "cppa/util/shared_spinlock.hpp"
#include "cppa/util/shared_lock_guard.hpp"
#include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/singleton_manager.hpp"
namespace cppa { namespace cppa {
namespace { typedef std::unique_lock<std::mutex> guard_type; } actor::actor(abstract_actor* ptr) : m_ptr(ptr) { }
// m_exit_reason is guaranteed to be set to 0, i.e., exit_reason::not_exited,
// by std::atomic<> constructor
actor::actor(actor_id aid)
: m_id(aid), m_is_proxy(true), m_exit_reason(exit_reason::not_exited) { }
actor::actor()
: m_id(get_actor_registry()->next_id()), m_is_proxy(false)
, m_exit_reason(exit_reason::not_exited) { }
bool actor::link_to_impl(const actor_ptr& other) {
if (other && other != this) {
guard_type guard{m_mtx};
// send exit message if already exited
if (exited()) {
send_as(this, other, atom("EXIT"), exit_reason());
}
// add link if not already linked to other
// (checked by establish_backlink)
else if (other->establish_backlink(this)) {
m_links.push_back(other);
return true;
}
}
return false;
}
bool actor::attach(attachable_ptr ptr) {
if (ptr == nullptr) {
guard_type guard{m_mtx};
return m_exit_reason == exit_reason::not_exited;
}
std::uint32_t reason;
{ // lifetime scope of guard
guard_type guard{m_mtx};
reason = m_exit_reason;
if (reason == exit_reason::not_exited) {
m_attachables.push_back(std::move(ptr));
return true;
}
}
ptr->actor_exited(reason);
return false;
}
void actor::detach(const attachable::token& what) {
attachable_ptr ptr;
{ // lifetime scope of guard
guard_type guard{m_mtx};
auto end = m_attachables.end();
auto i = std::find_if(
m_attachables.begin(), end,
[&](attachable_ptr& p) { return p->matches(what); });
if (i != end) {
ptr = std::move(*i);
m_attachables.erase(i);
}
}
// ptr will be destroyed here, without locked mutex
}
void actor::link_to(const actor_ptr& other) {
static_cast<void>(link_to_impl(other));
}
void actor::unlink_from(const actor_ptr& other) { actor_id actor::id() const {
static_cast<void>(unlink_from_impl(other)); return (m_ptr) ? m_ptr->id() : 0;
} }
bool actor::remove_backlink(const actor_ptr& other) { actor_addr actor::address() const {
if (other && other != this) { return m_ptr ? m_ptr->address() : actor_addr{};
guard_type guard{m_mtx};
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i != m_links.end()) {
m_links.erase(i);
return true;
}
}
return false;
} }
bool actor::establish_backlink(const actor_ptr& other) { void actor::enqueue(const message_header& hdr, any_tuple msg) const {
std::uint32_t reason = exit_reason::not_exited; if (m_ptr) m_ptr->enqueue(hdr, std::move(msg));
if (other && other != this) {
guard_type guard{m_mtx};
reason = m_exit_reason;
if (reason == exit_reason::not_exited) {
auto i = std::find(m_links.begin(), m_links.end(), other);
if (i == m_links.end()) {
m_links.push_back(other);
return true;
}
}
}
// send exit message without lock
if (reason != exit_reason::not_exited) {
send_as(this, other, make_any_tuple(atom("EXIT"), reason));
}
return false;
} }
bool actor::unlink_from_impl(const actor_ptr& other) { bool actor::is_remote() const {
guard_type guard{m_mtx}; return m_ptr ? m_ptr->is_proxy() : false;
// remove_backlink returns true if this actor is linked to other
if (other && !exited() && other->remove_backlink(this)) {
auto i = std::find(m_links.begin(), m_links.end(), other);
CPPA_REQUIRE(i != m_links.end());
m_links.erase(i);
return true;
}
return false;
} }
void actor::cleanup(std::uint32_t reason) { intptr_t actor::compare(const actor& other) const {
// log as 'actor' return channel::compare(m_ptr.get(), other.m_ptr.get());
CPPA_LOGM_TRACE("cppa::actor", CPPA_ARG(m_id) << ", " << CPPA_ARG(reason));
CPPA_REQUIRE(reason != exit_reason::not_exited);
// move everyhting out of the critical section before processing it
decltype(m_links) mlinks;
decltype(m_attachables) mattachables;
{ // lifetime scope of guard
guard_type guard{m_mtx};
if (m_exit_reason != exit_reason::not_exited) {
// already exited
return;
}
m_exit_reason = reason;
mlinks = std::move(m_links);
mattachables = std::move(m_attachables);
// make sure lists are empty
m_links.clear();
m_attachables.clear();
}
CPPA_LOGC_INFO_IF(not is_proxy(), "cppa::actor", __func__,
"actor with ID " << m_id << " had " << mlinks.size()
<< " links and " << mattachables.size()
<< " attached functors; exit reason = " << reason
<< ", class = " << detail::demangle(typeid(*this)));
// send exit messages
auto msg = make_any_tuple(atom("EXIT"), reason);
CPPA_LOGM_DEBUG("cppa::actor", "send EXIT to " << mlinks.size() << " links");
for (actor_ptr& aptr : mlinks) {
message_header hdr{this, aptr, message_priority::high};
hdr.deliver(msg);
}
for (attachable_ptr& ptr : mattachables) {
ptr->actor_exited(reason);
}
} }
} // namespace cppa } // namespace cppa
...@@ -25,128 +25,55 @@ ...@@ -25,128 +25,55 @@
* * * *
* You should have received a copy of the GNU Lesser General Public License * * You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#include <pthread.h> #include "cppa/actor.hpp"
#include "cppa/actor_addr.hpp"
#include "cppa/self.hpp"
#include "cppa/logging.hpp"
#include "cppa/any_tuple.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/thread_mapped_actor.hpp"
namespace cppa { namespace cppa {
namespace { namespace {
intptr_t compare_impl(const abstract_actor* lhs, const abstract_actor* rhs) {
pthread_key_t s_key; return reinterpret_cast<intptr_t>(lhs) - reinterpret_cast<intptr_t>(rhs);
pthread_once_t s_key_once = PTHREAD_ONCE_INIT;
local_actor* tss_constructor() {
local_actor* result = detail::memory::create<thread_mapped_actor>();
CPPA_LOGF_INFO("converted thread to actor; ID = " << result->id());
result->ref();
get_scheduler()->register_converted_context(result);
return result;
}
void tss_destructor(void* vptr) {
if (vptr) self_type::cleanup_fun(reinterpret_cast<local_actor*>(vptr));
}
void tss_make_key() {
pthread_key_create(&s_key, tss_destructor);
}
local_actor* tss_get() {
pthread_once(&s_key_once, tss_make_key);
return reinterpret_cast<local_actor*>(pthread_getspecific(s_key));
}
local_actor* tss_release() {
pthread_once(&s_key_once, tss_make_key);
auto result = reinterpret_cast<local_actor*>(pthread_getspecific(s_key));
if (result) {
pthread_setspecific(s_key, nullptr);
}
return result;
} }
local_actor* tss_get_or_create() {
pthread_once(&s_key_once, tss_make_key);
auto result = reinterpret_cast<local_actor*>(pthread_getspecific(s_key));
if (!result) {
result = tss_constructor();
pthread_setspecific(s_key, reinterpret_cast<void*>(result));
}
return result;
}
void tss_reset(local_actor* ptr, bool inc_ref_count = true) {
pthread_once(&s_key_once, tss_make_key);
auto old_ptr = reinterpret_cast<local_actor*>(pthread_getspecific(s_key));
if (old_ptr) {
tss_destructor(old_ptr);
}
if (ptr != nullptr && inc_ref_count) {
ptr->ref();
}
pthread_setspecific(s_key, reinterpret_cast<void*>(ptr));
}
} // namespace <anonymous> } // namespace <anonymous>
void self_type::cleanup_fun(cppa::local_actor* what) { actor_addr::actor_addr(const invalid_actor_addr_t&) : m_ptr(nullptr) { }
if (what) {
auto ptr = dynamic_cast<thread_mapped_actor*>(what);
if (ptr) {
// make sure "unspawned" actors quit properly
what->cleanup(cppa::exit_reason::normal);
}
what->deref();
}
}
void self_type::set_impl(self_type::pointer ptr) { actor_addr::actor_addr(abstract_actor* ptr) : m_ptr(ptr) { }
tss_reset(ptr);
}
self_type::pointer self_type::get_impl() { actor_addr::operator bool() const {
return tss_get_or_create(); return static_cast<bool>(m_ptr);
} }
actor* self_type::convert_impl() { bool actor_addr::operator!() const {
return get_impl(); return !m_ptr;
} }
self_type::pointer self_type::get_unchecked_impl() { intptr_t actor_addr::compare(const actor& other) const {
return tss_get(); return compare_impl(m_ptr.get(), other.m_ptr.get());
} }
void self_type::adopt_impl(self_type::pointer ptr) { intptr_t actor_addr::compare(const actor_addr& other) const {
tss_reset(ptr, false); return compare_impl(m_ptr.get(), other.m_ptr.get());
} }
self_type::pointer self_type::release_impl() { intptr_t actor_addr::compare(const local_actor* other) const {
return tss_release(); return compare_impl(m_ptr.get(), other);
} }
bool operator==(const actor_ptr& lhs, const self_type& rhs) { actor_id actor_addr::id() const {
return lhs.get() == rhs.get(); return m_ptr->id();
} }
bool operator==(const self_type& lhs, const actor_ptr& rhs) { const node_id& actor_addr::node() const {
return rhs == lhs; return m_ptr ? m_ptr->node() : *node_id::get();
} }
bool operator!=(const actor_ptr& lhs, const self_type& rhs) { bool actor_addr::is_remote() const {
return !(lhs == rhs); return m_ptr ? m_ptr->is_proxy() : false;
} }
bool operator!=(const self_type& lhs, const actor_ptr& rhs) {
return !(rhs == lhs);
}
} // namespace cppa } // namespace cppa
...@@ -44,32 +44,26 @@ ...@@ -44,32 +44,26 @@
namespace cppa { namespace cppa {
void actor_namespace::write(serializer* sink, const actor_ptr& ptr) { void actor_namespace::write(serializer* sink, const actor_addr& ptr) {
CPPA_REQUIRE(sink != nullptr); CPPA_REQUIRE(sink != nullptr);
if (ptr == nullptr) { if (!ptr) {
CPPA_LOG_DEBUG("serialize nullptr"); CPPA_LOG_DEBUG("serialize nullptr");
sink->write_value(static_cast<actor_id>(0)); sink->write_value(static_cast<actor_id>(0));
node_id::serialize_invalid(sink); node_id::serialize_invalid(sink);
} }
else { else {
// local actor? // register locally running actors to be able to deserialize them later
if (!ptr->is_proxy()) { if (!ptr.is_remote()) {
get_actor_registry()->put(ptr->id(), ptr); get_actor_registry()->put(ptr.id(), detail::actor_addr_cast<abstract_actor>(ptr));
} }
auto pinf = node_id::get(); auto& pinf = ptr.node();
if (ptr->is_proxy()) { sink->write_value(ptr.id());
auto dptr = ptr.downcast<io::remote_actor_proxy>(); sink->write_value(pinf.process_id());
if (dptr) pinf = dptr->process_info(); sink->write_raw(node_id::host_id_size, pinf.host_id().data());
else CPPA_LOG_ERROR("downcast failed");
}
sink->write_value(ptr->id());
sink->write_value(pinf->process_id());
sink->write_raw(node_id::host_id_size,
pinf->host_id().data());
} }
} }
actor_ptr actor_namespace::read(deserializer* source) { actor_addr actor_namespace::read(deserializer* source) {
CPPA_REQUIRE(source != nullptr); CPPA_REQUIRE(source != nullptr);
node_id::host_id_type nid; node_id::host_id_type nid;
auto aid = source->read<uint32_t>(); auto aid = source->read<uint32_t>();
...@@ -78,16 +72,15 @@ actor_ptr actor_namespace::read(deserializer* source) { ...@@ -78,16 +72,15 @@ actor_ptr actor_namespace::read(deserializer* source) {
// local actor? // local actor?
auto pinf = node_id::get(); auto pinf = node_id::get();
if (aid == 0 && pid == 0) { if (aid == 0 && pid == 0) {
return nullptr; return invalid_actor_addr;
} }
else if (pid == pinf->process_id() && nid == pinf->host_id()) { else if (pid == pinf->process_id() && nid == pinf->host_id()) {
return get_actor_registry()->get(aid); return actor{get_actor_registry()->get(aid)};
} }
else { else {
node_id_ptr tmp = new node_id{pid, nid}; node_id_ptr tmp = new node_id{pid, nid};
return get_or_put(tmp, aid); return actor{get_or_put(tmp, aid)};
} }
return nullptr;
} }
size_t actor_namespace::count_proxies(const node_id& node) { size_t actor_namespace::count_proxies(const node_id& node) {
...@@ -95,7 +88,7 @@ size_t actor_namespace::count_proxies(const node_id& node) { ...@@ -95,7 +88,7 @@ size_t actor_namespace::count_proxies(const node_id& node) {
return (i != m_proxies.end()) ? i->second.size() : 0; return (i != m_proxies.end()) ? i->second.size() : 0;
} }
actor_ptr actor_namespace::get(const node_id& node, actor_id aid) { actor_proxy_ptr actor_namespace::get(const node_id& node, actor_id aid) {
auto& submap = m_proxies[node]; auto& submap = m_proxies[node];
auto i = submap.find(aid); auto i = submap.find(aid);
if (i != submap.end()) { if (i != submap.end()) {
...@@ -109,7 +102,7 @@ actor_ptr actor_namespace::get(const node_id& node, actor_id aid) { ...@@ -109,7 +102,7 @@ actor_ptr actor_namespace::get(const node_id& node, actor_id aid) {
return nullptr; return nullptr;
} }
actor_ptr actor_namespace::get_or_put(node_id_ptr node, actor_id aid) { actor_proxy_ptr actor_namespace::get_or_put(node_id_ptr node, actor_id aid) {
auto result = get(*node, aid); auto result = get(*node, aid);
if (result == nullptr && m_factory) { if (result == nullptr && m_factory) {
auto ptr = m_factory(aid, node); auto ptr = m_factory(aid, node);
...@@ -127,13 +120,6 @@ void actor_namespace::put(const node_id& node, ...@@ -127,13 +120,6 @@ void actor_namespace::put(const node_id& node,
if (i == submap.end()) { if (i == submap.end()) {
submap.insert(std::make_pair(aid, proxy)); submap.insert(std::make_pair(aid, proxy));
if (m_new_element_callback) m_new_element_callback(aid, node); if (m_new_element_callback) m_new_element_callback(aid, node);
/*if (m_parent) {
m_parent->enqueue(node,
{nullptr, nullptr},
make_any_tuple(atom("MONITOR"),
node_id::get(),
aid));
}*/
} }
else { else {
CPPA_LOG_ERROR("proxy for " << aid << ":" CPPA_LOG_ERROR("proxy for " << aid << ":"
...@@ -151,7 +137,7 @@ void actor_namespace::erase(node_id& inf) { ...@@ -151,7 +137,7 @@ void actor_namespace::erase(node_id& inf) {
} }
void actor_namespace::erase(node_id& inf, actor_id aid) { void actor_namespace::erase(node_id& inf, actor_id aid) {
CPPA_LOGMF(CPPA_TRACE, self, CPPA_TARG(inf, to_string) << ", " << CPPA_ARG(aid)); CPPA_LOG_TRACE(CPPA_TARG(inf, to_string) << ", " << CPPA_ARG(aid));
auto i = m_proxies.find(inf); auto i = m_proxies.find(inf);
if (i != m_proxies.end()) { if (i != m_proxies.end()) {
i->second.erase(aid); i->second.erase(aid);
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include <limits> #include <limits>
#include <stdexcept> #include <stdexcept>
#include "cppa/self.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/attachable.hpp" #include "cppa/attachable.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
...@@ -62,7 +61,7 @@ actor_registry::value_type actor_registry::get_entry(actor_id key) const { ...@@ -62,7 +61,7 @@ actor_registry::value_type actor_registry::get_entry(actor_id key) const {
return {nullptr, exit_reason::not_exited}; return {nullptr, exit_reason::not_exited};
} }
void actor_registry::put(actor_id key, const actor_ptr& value) { void actor_registry::put(actor_id key, const abstract_actor_ptr& value) {
bool add_attachable = false; bool add_attachable = false;
if (value != nullptr) { if (value != nullptr) {
shared_guard guard(m_instances_mtx); shared_guard guard(m_instances_mtx);
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
#include <stdexcept> #include <stdexcept>
#include <type_traits> #include <type_traits>
#include "cppa/self.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/type_lookup_table.hpp" #include "cppa/type_lookup_table.hpp"
#include "cppa/binary_deserializer.hpp" #include "cppa/binary_deserializer.hpp"
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <cstring> #include <cstring>
#include <type_traits> #include <type_traits>
#include "cppa/config.hpp"
#include "cppa/primitive_variant.hpp" #include "cppa/primitive_variant.hpp"
#include "cppa/binary_serializer.hpp" #include "cppa/binary_serializer.hpp"
#include "cppa/type_lookup_table.hpp" #include "cppa/type_lookup_table.hpp"
......
...@@ -68,7 +68,7 @@ class default_broker : public broker { ...@@ -68,7 +68,7 @@ class default_broker : public broker {
: broker{std::forward<Ts>(args)...}, m_fun{move(fun)} { } : broker{std::forward<Ts>(args)...}, m_fun{move(fun)} { }
void init() override { void init() override {
enqueue(nullptr, make_any_tuple(atom("INITMSG"))); enqueue({invalid_actor_addr, this}, make_any_tuple(atom("INITMSG")));
become( become(
on(atom("INITMSG")) >> [=] { on(atom("INITMSG")) >> [=] {
unbecome(); unbecome();
...@@ -136,7 +136,7 @@ class broker::servant : public continuable { ...@@ -136,7 +136,7 @@ class broker::servant : public continuable {
if (!m_disconnected) { if (!m_disconnected) {
m_disconnected = true; m_disconnected = true;
if (m_broker->exit_reason() == exit_reason::not_exited) { if (m_broker->exit_reason() == exit_reason::not_exited) {
m_broker->invoke_message(nullptr, disconnect_message()); //TODO: m_broker->invoke_message(nullptr, disconnect_message());
} }
} }
} }
...@@ -207,7 +207,7 @@ class broker::scribe : public extend<broker::servant>::with<buffered_writing> { ...@@ -207,7 +207,7 @@ class broker::scribe : public extend<broker::servant>::with<buffered_writing> {
|| m_policy == broker::exactly || m_policy == broker::exactly
|| m_policy == broker::at_most) { || m_policy == broker::at_most) {
CPPA_LOG_DEBUG("invoke io actor"); CPPA_LOG_DEBUG("invoke io actor");
m_broker->invoke_message(nullptr, m_read_msg); m_broker->invoke_message({invalid_actor_addr, nullptr}, m_read_msg);
CPPA_LOG_INFO_IF(!m_read_msg.vals()->unique(), "detached buffer"); CPPA_LOG_INFO_IF(!m_read_msg.vals()->unique(), "detached buffer");
get_ref<2>(m_read_msg).clear(); get_ref<2>(m_read_msg).clear();
} }
...@@ -264,7 +264,7 @@ class broker::doorman : public broker::servant { ...@@ -264,7 +264,7 @@ class broker::doorman : public broker::servant {
auto& p = *opt; auto& p = *opt;
get_ref<2>(m_accept_msg) = m_broker->add_scribe(move(p.first), get_ref<2>(m_accept_msg) = m_broker->add_scribe(move(p.first),
move(p.second)); move(p.second));
m_broker->invoke_message(nullptr, m_accept_msg); m_broker->invoke_message({invalid_actor_addr, nullptr}, m_accept_msg);
} }
else return read_continue_later; else return read_continue_later;
} }
...@@ -298,7 +298,6 @@ void broker::invoke_message(const message_header& hdr, any_tuple msg) { ...@@ -298,7 +298,6 @@ void broker::invoke_message(const message_header& hdr, any_tuple msg) {
m_dummy_node.mid = hdr.id; m_dummy_node.mid = hdr.id;
try { try {
using detail::receive_policy; using detail::receive_policy;
scoped_self_setter sss{this};
auto bhvr = m_bhvr_stack.back(); auto bhvr = m_bhvr_stack.back();
switch (m_recv_policy.handle_message(this, switch (m_recv_policy.handle_message(this,
&m_dummy_node, &m_dummy_node,
...@@ -335,7 +334,7 @@ void broker::invoke_message(const message_header& hdr, any_tuple msg) { ...@@ -335,7 +334,7 @@ void broker::invoke_message(const message_header& hdr, any_tuple msg) {
quit(exit_reason::unhandled_exception); quit(exit_reason::unhandled_exception);
} }
// restore dummy node // restore dummy node
m_dummy_node.sender.reset(); m_dummy_node.sender = actor_addr{};
m_dummy_node.msg.reset(); m_dummy_node.msg.reset();
} }
...@@ -397,7 +396,6 @@ void broker::write(const connection_handle& hdl, util::buffer&& buf) { ...@@ -397,7 +396,6 @@ void broker::write(const connection_handle& hdl, util::buffer&& buf) {
} }
local_actor_ptr init_and_launch(broker_ptr ptr) { local_actor_ptr init_and_launch(broker_ptr ptr) {
scoped_self_setter sss{ptr.get()};
ptr->init(); ptr->init();
// continue reader only if not inherited from default_broker_impl // continue reader only if not inherited from default_broker_impl
CPPA_LOGF_WARNING_IF(!ptr->has_behavior(), "broker w/o behavior spawned"); CPPA_LOGF_WARNING_IF(!ptr->has_behavior(), "broker w/o behavior spawned");
...@@ -454,8 +452,8 @@ accept_handle broker::add_doorman(acceptor_uptr ptr) { ...@@ -454,8 +452,8 @@ accept_handle broker::add_doorman(acceptor_uptr ptr) {
return id; return id;
} }
actor_ptr broker::fork_impl(std::function<void (broker*)> fun, actor_addr broker::fork_impl(std::function<void (broker*)> fun,
connection_handle hdl) { connection_handle hdl) {
auto i = m_io.find(hdl); auto i = m_io.find(hdl);
if (i == m_io.end()) throw std::invalid_argument("invalid handle"); if (i == m_io.end()) throw std::invalid_argument("invalid handle");
scribe* sptr = i->second.get(); // non-owning pointer scribe* sptr = i->second.get(); // non-owning pointer
...@@ -463,7 +461,7 @@ actor_ptr broker::fork_impl(std::function<void (broker*)> fun, ...@@ -463,7 +461,7 @@ actor_ptr broker::fork_impl(std::function<void (broker*)> fun,
init_and_launch(result); init_and_launch(result);
sptr->set_broker(result); // set new broker sptr->set_broker(result); // set new broker
m_io.erase(i); m_io.erase(i);
return result; return {result};
} }
void broker::receive_policy(const connection_handle& hdl, void broker::receive_policy(const connection_handle& hdl,
......
...@@ -28,18 +28,36 @@ ...@@ -28,18 +28,36 @@
\******************************************************************************/ \******************************************************************************/
#include "cppa/actor.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
namespace cppa { namespace cppa {
channel::~channel() { } intptr_t channel::compare(const abstract_channel* lhs, const abstract_channel* rhs) {
return reinterpret_cast<intptr_t>(lhs) - reinterpret_cast<intptr_t>(rhs);
}
channel::channel(abstract_channel* ptr) : m_ptr(ptr) { }
bool channel::chained_enqueue(const message_header& hdr, any_tuple msg) { channel::operator bool() const {
enqueue(hdr, std::move(msg)); return static_cast<bool>(m_ptr);
return false;
} }
void channel::unchain() { } bool channel::operator!() const {
return !m_ptr;
}
void channel::enqueue(const message_header& hdr, any_tuple msg) const {
if (m_ptr) m_ptr->enqueue(hdr, std::move(msg));
}
intptr_t channel::compare(const channel& other) const {
return compare(m_ptr.get(), other.m_ptr.get());
}
intptr_t channel::compare(const actor& other) const {
return compare(m_ptr.get(), other.m_ptr.get());
}
} // namespace cppa } // namespace cppa
\ No newline at end of file
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/self.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
...@@ -46,34 +45,13 @@ class default_scheduled_actor : public event_based_actor { ...@@ -46,34 +45,13 @@ class default_scheduled_actor : public event_based_actor {
public: public:
typedef std::function<void()> fun_type; typedef std::function<behavior(event_based_actor*)> fun_type;
default_scheduled_actor(fun_type&& fun) default_scheduled_actor(fun_type&& fun)
: super(actor_state::ready), m_fun(std::move(fun)), m_initialized(false) { } : super(actor_state::ready), m_fun(std::move(fun)) { }
void init() { } behavior make_behavior() override {
return m_fun(this);
resume_result resume(util::fiber* f, actor_ptr& next) {
if (!m_initialized) {
scoped_self_setter sss{this};
m_initialized = true;
m_fun();
if (m_bhvr_stack.empty()) {
if (exit_reason() == exit_reason::not_exited) {
quit(exit_reason::normal);
}
else {
set_state(actor_state::done);
m_bhvr_stack.clear();
m_bhvr_stack.cleanup();
on_exit();
next.swap(m_chained_actor);
set_state(actor_state::done);
}
return resume_result::actor_done;
}
}
return event_based_actor::resume(f, next);
} }
scheduled_actor_type impl_type() { scheduled_actor_type impl_type() {
...@@ -83,21 +61,39 @@ class default_scheduled_actor : public event_based_actor { ...@@ -83,21 +61,39 @@ class default_scheduled_actor : public event_based_actor {
private: private:
fun_type m_fun; fun_type m_fun;
bool m_initialized;
}; };
intrusive_ptr<event_based_actor> event_based_actor::from(std::function<void()> fun) { intrusive_ptr<event_based_actor> event_based_actor::from(std::function<behavior()> fun) {
return make_counted<default_scheduled_actor>([=](event_based_actor*) -> behavior { return fun(); });
}
intrusive_ptr<event_based_actor> event_based_actor::from(std::function<behavior(event_based_actor*)> fun) {
return make_counted<default_scheduled_actor>(std::move(fun)); return make_counted<default_scheduled_actor>(std::move(fun));
} }
intrusive_ptr<event_based_actor> event_based_actor::from(std::function<void(event_based_actor*)> fun) {
auto result = make_counted<default_scheduled_actor>([=](event_based_actor* self) -> behavior {
return (
on(atom("INIT")) >> [=] {
fun(self);
}
);
});
result->enqueue({result->address(), result}, make_any_tuple(atom("INIT")));
return result;
}
intrusive_ptr<event_based_actor> event_based_actor::from(std::function<void()> fun) {
return from([=](event_based_actor*) { fun(); });
}
event_based_actor::event_based_actor(actor_state st) : super(st, true) { } event_based_actor::event_based_actor(actor_state st) : super(st, true) { }
resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) { resume_result event_based_actor::resume(util::fiber*) {
CPPA_LOG_TRACE("id = " << id() << ", state = " << static_cast<int>(state())); CPPA_LOG_TRACE("id = " << id() << ", state = " << static_cast<int>(state()));
CPPA_REQUIRE( state() == actor_state::ready CPPA_REQUIRE( state() == actor_state::ready
|| state() == actor_state::pending); || state() == actor_state::pending);
scoped_self_setter sss{this};
auto done_cb = [&]() -> bool { auto done_cb = [&]() -> bool {
CPPA_LOG_TRACE(""); CPPA_LOG_TRACE("");
if (exit_reason() == exit_reason::not_exited) { if (exit_reason() == exit_reason::not_exited) {
...@@ -116,7 +112,6 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) { ...@@ -116,7 +112,6 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) {
m_bhvr_stack.cleanup(); m_bhvr_stack.cleanup();
on_exit(); on_exit();
CPPA_REQUIRE(next_job == nullptr); CPPA_REQUIRE(next_job == nullptr);
next_job.swap(m_chained_actor);
return true; return true;
}; };
CPPA_REQUIRE(next_job == nullptr); CPPA_REQUIRE(next_job == nullptr);
...@@ -127,7 +122,6 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) { ...@@ -127,7 +122,6 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) {
if (e == nullptr) { if (e == nullptr) {
CPPA_REQUIRE(next_job == nullptr); CPPA_REQUIRE(next_job == nullptr);
CPPA_LOGMF(CPPA_DEBUG, self, "no more element in mailbox; going to block"); CPPA_LOGMF(CPPA_DEBUG, self, "no more element in mailbox; going to block");
next_job.swap(m_chained_actor);
set_state(actor_state::about_to_block); set_state(actor_state::about_to_block);
std::atomic_thread_fence(std::memory_order_seq_cst); std::atomic_thread_fence(std::memory_order_seq_cst);
if (this->m_mailbox.can_fetch_more() == false) { if (this->m_mailbox.can_fetch_more() == false) {
...@@ -137,7 +131,6 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) { ...@@ -137,7 +131,6 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) {
// interrupted by arriving message // interrupted by arriving message
// restore members // restore members
CPPA_REQUIRE(m_chained_actor == nullptr); CPPA_REQUIRE(m_chained_actor == nullptr);
next_job.swap(m_chained_actor);
CPPA_LOGMF(CPPA_DEBUG, self, "switched back to ready: " CPPA_LOGMF(CPPA_DEBUG, self, "switched back to ready: "
"interrupted by arriving message"); "interrupted by arriving message");
break; break;
...@@ -155,7 +148,6 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) { ...@@ -155,7 +148,6 @@ resume_result event_based_actor::resume(util::fiber*, actor_ptr& next_job) {
"mailbox can fetch more"); "mailbox can fetch more");
set_state(actor_state::ready); set_state(actor_state::ready);
CPPA_REQUIRE(m_chained_actor == nullptr); CPPA_REQUIRE(m_chained_actor == nullptr);
next_job.swap(m_chained_actor);
} }
} }
else { else {
......
...@@ -58,7 +58,7 @@ group::module_ptr group::get_module(const std::string& module_name) { ...@@ -58,7 +58,7 @@ group::module_ptr group::get_module(const std::string& module_name) {
return get_group_manager()->get_module(module_name); return get_group_manager()->get_module(module_name);
} }
group::subscription::subscription(const channel_ptr& s, group::subscription::subscription(const channel& s,
const intrusive_ptr<group>& g) const intrusive_ptr<group>& g)
: m_subscriber(s), m_group(g) { } : m_subscriber(s), m_group(g) { }
...@@ -88,8 +88,8 @@ const std::string& group::module_name() const { ...@@ -88,8 +88,8 @@ const std::string& group::module_name() const {
} }
struct group_nameserver : event_based_actor { struct group_nameserver : event_based_actor {
void init() { behavior make_behavior() override {
become ( return (
on(atom("GET_GROUP"), arg_match) >> [](const std::string& name) { on(atom("GET_GROUP"), arg_match) >> [](const std::string& name) {
return make_cow_tuple(atom("GROUP"), group::get("local", name)); return make_cow_tuple(atom("GROUP"), group::get("local", name));
}, },
...@@ -106,7 +106,7 @@ void publish_local_groups_at(std::uint16_t port, const char* addr) { ...@@ -106,7 +106,7 @@ void publish_local_groups_at(std::uint16_t port, const char* addr) {
publish(gn, port, addr); publish(gn, port, addr);
} }
catch (std::exception&) { catch (std::exception&) {
gn->enqueue(nullptr, make_any_tuple(atom("SHUTDOWN"))); gn.enqueue({invalid_actor_addr, nullptr}, make_any_tuple(atom("SHUTDOWN")));
throw; throw;
} }
} }
......
...@@ -67,23 +67,23 @@ class local_group : public group { ...@@ -67,23 +67,23 @@ class local_group : public group {
public: public:
void send_all_subscribers(const actor_ptr& sender, const any_tuple& msg) { void send_all_subscribers(const message_header& hdr, const any_tuple& msg) {
CPPA_LOG_TRACE(CPPA_TARG(sender, to_string) << ", " CPPA_LOG_TRACE(CPPA_TARG(sender, to_string) << ", "
<< CPPA_TARG(msg, to_string)); << CPPA_TARG(msg, to_string));
shared_guard guard(m_mtx); shared_guard guard(m_mtx);
for (auto& s : m_subscribers) { for (auto& s : m_subscribers) {
send_tuple_as(sender, s, msg); s.enqueue(hdr, msg);
} }
} }
void enqueue(const message_header& hdr, any_tuple msg) override { void enqueue(const message_header& hdr, any_tuple msg) override {
CPPA_LOG_TRACE(CPPA_TARG(hdr, to_string) << ", " CPPA_LOG_TRACE(CPPA_TARG(hdr, to_string) << ", "
<< CPPA_TARG(msg, to_string)); << CPPA_TARG(msg, to_string));
send_all_subscribers(hdr.sender, msg); send_all_subscribers(hdr, msg);
m_broker->enqueue(hdr, move(msg)); m_broker.enqueue(hdr, msg);
} }
pair<bool, size_t> add_subscriber(const channel_ptr& who) { pair<bool, size_t> add_subscriber(const channel& who) {
CPPA_LOG_TRACE(CPPA_TARG(who, to_string)); CPPA_LOG_TRACE(CPPA_TARG(who, to_string));
exclusive_guard guard(m_mtx); exclusive_guard guard(m_mtx);
if (m_subscribers.insert(who).second) { if (m_subscribers.insert(who).second) {
...@@ -92,14 +92,14 @@ class local_group : public group { ...@@ -92,14 +92,14 @@ class local_group : public group {
return {false, m_subscribers.size()}; return {false, m_subscribers.size()};
} }
pair<bool, size_t> erase_subscriber(const channel_ptr& who) { pair<bool, size_t> erase_subscriber(const channel& who) {
CPPA_LOG_TRACE(CPPA_TARG(who, to_string)); CPPA_LOG_TRACE(CPPA_TARG(who, to_string));
exclusive_guard guard(m_mtx); exclusive_guard guard(m_mtx);
auto success = m_subscribers.erase(who) > 0; auto success = m_subscribers.erase(who) > 0;
return {success, m_subscribers.size()}; return {success, m_subscribers.size()};
} }
group::subscription subscribe(const channel_ptr& who) { group::subscription subscribe(const channel& who) {
CPPA_LOG_TRACE(CPPA_TARG(who, to_string)); CPPA_LOG_TRACE(CPPA_TARG(who, to_string));
if (add_subscriber(who).first) { if (add_subscriber(who).first) {
return {who, this}; return {who, this};
...@@ -107,14 +107,14 @@ class local_group : public group { ...@@ -107,14 +107,14 @@ class local_group : public group {
return {}; return {};
} }
void unsubscribe(const channel_ptr& who) { void unsubscribe(const channel& who) {
CPPA_LOG_TRACE(CPPA_TARG(who, to_string)); CPPA_LOG_TRACE(CPPA_TARG(who, to_string));
erase_subscriber(who); erase_subscriber(who);
} }
void serialize(serializer* sink); void serialize(serializer* sink);
const actor_ptr& broker() const { const actor& broker() const {
return m_broker; return m_broker;
} }
...@@ -123,8 +123,8 @@ class local_group : public group { ...@@ -123,8 +123,8 @@ class local_group : public group {
protected: protected:
util::shared_spinlock m_mtx; util::shared_spinlock m_mtx;
set<channel_ptr> m_subscribers; set<channel> m_subscribers;
actor_ptr m_broker; actor m_broker;
}; };
...@@ -136,16 +136,16 @@ class local_broker : public event_based_actor { ...@@ -136,16 +136,16 @@ class local_broker : public event_based_actor {
local_broker(local_group_ptr g) : m_group(move(g)) { } local_broker(local_group_ptr g) : m_group(move(g)) { }
void init() { behavior make_behavior() {
become ( return (
on(atom("JOIN"), arg_match) >> [=](const actor_ptr& other) { on(atom("JOIN"), arg_match) >> [=](const actor_addr& other) {
CPPA_LOGC_TRACE("cppa::local_broker", "init$JOIN", CPPA_LOGC_TRACE("cppa::local_broker", "init$JOIN",
CPPA_TARG(other, to_string)); CPPA_TARG(other, to_string));
if (other && m_acquaintances.insert(other).second) { if (other && m_acquaintances.insert(other).second) {
monitor(other); monitor(other);
} }
}, },
on(atom("LEAVE"), arg_match) >> [=](const actor_ptr& other) { on(atom("LEAVE"), arg_match) >> [=](const actor_addr& other) {
CPPA_LOGC_TRACE("cppa::local_broker", "init$LEAVE", CPPA_LOGC_TRACE("cppa::local_broker", "init$LEAVE",
CPPA_TARG(other, to_string)); CPPA_TARG(other, to_string));
if (other && m_acquaintances.erase(other) > 0) { if (other && m_acquaintances.erase(other) > 0) {
...@@ -156,15 +156,16 @@ class local_broker : public event_based_actor { ...@@ -156,15 +156,16 @@ class local_broker : public event_based_actor {
CPPA_LOGC_TRACE("cppa::local_broker", "init$FORWARD", CPPA_LOGC_TRACE("cppa::local_broker", "init$FORWARD",
CPPA_TARG(what, to_string)); CPPA_TARG(what, to_string));
// local forwarding // local forwarding
m_group->send_all_subscribers(last_sender(), what); message_header hdr{last_sender(), nullptr};
m_group->send_all_subscribers(hdr, what);
// forward to all acquaintances // forward to all acquaintances
send_to_acquaintances(what); send_to_acquaintances(what);
}, },
on(atom("DOWN"), arg_match) >> [=](uint32_t) { on(atom("DOWN"), arg_match) >> [=](uint32_t) {
actor_ptr other = last_sender(); auto sender = last_sender();
CPPA_LOGC_TRACE("cppa::local_broker", "init$DOWN", CPPA_LOGC_TRACE("cppa::local_broker", "init$DOWN",
CPPA_TARG(other, to_string)); CPPA_TARG(other, to_string));
if (other) m_acquaintances.erase(other); if (sender) m_acquaintances.erase(sender);
}, },
others() >> [=] { others() >> [=] {
auto msg = last_dequeued(); auto msg = last_dequeued();
...@@ -184,12 +185,13 @@ class local_broker : public event_based_actor { ...@@ -184,12 +185,13 @@ class local_broker : public event_based_actor {
<< " acquaintances; " << CPPA_TSARG(sender) << " acquaintances; " << CPPA_TSARG(sender)
<< ", " << CPPA_TSARG(what)); << ", " << CPPA_TSARG(what));
for (auto& acquaintance : m_acquaintances) { for (auto& acquaintance : m_acquaintances) {
acquaintance->enqueue({sender, acquaintance}, what); auto ptr = detail::actor_addr_cast<abstract_actor>(acquaintance);
ptr->enqueue({sender, ptr}, what);
} }
} }
local_group_ptr m_group; local_group_ptr m_group;
set<actor_ptr> m_acquaintances; set<actor_addr> m_acquaintances;
}; };
...@@ -206,7 +208,7 @@ class local_group_proxy : public local_group { ...@@ -206,7 +208,7 @@ class local_group_proxy : public local_group {
public: public:
template<typename... Ts> template<typename... Ts>
local_group_proxy(actor_ptr remote_broker, Ts&&... args) local_group_proxy(actor remote_broker, Ts&&... args)
: super(false, forward<Ts>(args)...) { : super(false, forward<Ts>(args)...) {
CPPA_REQUIRE(m_broker == nullptr); CPPA_REQUIRE(m_broker == nullptr);
CPPA_REQUIRE(remote_broker != nullptr); CPPA_REQUIRE(remote_broker != nullptr);
...@@ -215,7 +217,7 @@ class local_group_proxy : public local_group { ...@@ -215,7 +217,7 @@ class local_group_proxy : public local_group {
m_proxy_broker = spawn<proxy_broker, hidden>(this); m_proxy_broker = spawn<proxy_broker, hidden>(this);
} }
group::subscription subscribe(const channel_ptr& who) { group::subscription subscribe(const channel& who) {
CPPA_LOG_TRACE(CPPA_TSARG(who)); CPPA_LOG_TRACE(CPPA_TSARG(who));
auto res = add_subscriber(who); auto res = add_subscriber(who);
if (res.first) { if (res.first) {
...@@ -228,7 +230,7 @@ class local_group_proxy : public local_group { ...@@ -228,7 +230,7 @@ class local_group_proxy : public local_group {
return {}; return {};
} }
void unsubscribe(const channel_ptr& who) { void unsubscribe(const channel& who) {
CPPA_LOG_TRACE(CPPA_TSARG(who)); CPPA_LOG_TRACE(CPPA_TSARG(who));
auto res = erase_subscriber(who); auto res = erase_subscriber(who);
if (res.first && res.second == 0) { if (res.first && res.second == 0) {
...@@ -240,12 +242,12 @@ class local_group_proxy : public local_group { ...@@ -240,12 +242,12 @@ class local_group_proxy : public local_group {
void enqueue(const message_header& hdr, any_tuple msg) override { void enqueue(const message_header& hdr, any_tuple msg) override {
// forward message to the broker // forward message to the broker
m_broker->enqueue(hdr, make_any_tuple(atom("FORWARD"), move(msg))); m_broker.enqueue(hdr, make_any_tuple(atom("FORWARD"), move(msg)));
} }
private: private:
actor_ptr m_proxy_broker; actor m_proxy_broker;
}; };
...@@ -257,10 +259,11 @@ class proxy_broker : public event_based_actor { ...@@ -257,10 +259,11 @@ class proxy_broker : public event_based_actor {
proxy_broker(local_group_proxy_ptr grp) : m_group(move(grp)) { } proxy_broker(local_group_proxy_ptr grp) : m_group(move(grp)) { }
void init() { behavior make_behavior() {
become ( return (
others() >> [=] { others() >> [=] {
m_group->send_all_subscribers(last_sender(), last_dequeued()); message_header hdr{last_sender(), nullptr};
m_group->send_all_subscribers(hdr, last_dequeued());
} }
); );
} }
...@@ -279,7 +282,7 @@ class local_group_module : public group::module { ...@@ -279,7 +282,7 @@ class local_group_module : public group::module {
local_group_module() local_group_module()
: super("local"), m_process(node_id::get()) : super("local"), m_process(node_id::get())
, m_actor_utype(uniform_typeid<actor_ptr>()){ } , m_actor_utype(uniform_typeid<actor>()){ }
group_ptr get(const string& identifier) { group_ptr get(const string& identifier) {
shared_guard guard(m_instances_mtx); shared_guard guard(m_instances_mtx);
...@@ -302,11 +305,10 @@ class local_group_module : public group::module { ...@@ -302,11 +305,10 @@ class local_group_module : public group::module {
// deserialize {identifier, process_id, node_id} // deserialize {identifier, process_id, node_id}
auto identifier = source->read<string>(); auto identifier = source->read<string>();
// deserialize broker // deserialize broker
actor_ptr broker; actor broker;
m_actor_utype->deserialize(&broker, source); m_actor_utype->deserialize(&broker, source);
CPPA_REQUIRE(broker != nullptr);
if (!broker) return nullptr; if (!broker) return nullptr;
if (!broker->is_proxy()) { if (!broker.is_remote()) {
return this->get(identifier); return this->get(identifier);
} }
else { else {
...@@ -344,7 +346,7 @@ class local_group_module : public group::module { ...@@ -344,7 +346,7 @@ class local_group_module : public group::module {
util::shared_spinlock m_instances_mtx; util::shared_spinlock m_instances_mtx;
map<string, local_group_ptr> m_instances; map<string, local_group_ptr> m_instances;
util::shared_spinlock m_proxies_mtx; util::shared_spinlock m_proxies_mtx;
map<actor_ptr, local_group_ptr> m_proxies; map<actor, local_group_ptr> m_proxies;
}; };
...@@ -357,12 +359,12 @@ class remote_group : public group { ...@@ -357,12 +359,12 @@ class remote_group : public group {
remote_group(group::module_ptr parent, string id, local_group_ptr decorated) remote_group(group::module_ptr parent, string id, local_group_ptr decorated)
: super(parent, move(id)), m_decorated(decorated) { } : super(parent, move(id)), m_decorated(decorated) { }
group::subscription subscribe(const channel_ptr& who) { group::subscription subscribe(const channel& who) {
CPPA_LOG_TRACE(CPPA_TSARG(who)); CPPA_LOG_TRACE(CPPA_TSARG(who));
return m_decorated->subscribe(who); return m_decorated->subscribe(who);
} }
void unsubscribe(const channel_ptr&) { void unsubscribe(const channel&) {
CPPA_LOG_ERROR("should never be called"); CPPA_LOG_ERROR("should never be called");
} }
...@@ -376,7 +378,7 @@ class remote_group : public group { ...@@ -376,7 +378,7 @@ class remote_group : public group {
void group_down() { void group_down() {
CPPA_LOG_TRACE(""); CPPA_LOG_TRACE("");
group_ptr _this{this}; group_ptr _this{this};
m_decorated->send_all_subscribers(nullptr, m_decorated->send_all_subscribers({invalid_actor_addr, nullptr},
make_any_tuple(atom("GROUP_DOWN"), make_any_tuple(atom("GROUP_DOWN"),
_this)); _this));
} }
...@@ -430,7 +432,7 @@ class shared_map : public ref_counted { ...@@ -430,7 +432,7 @@ class shared_map : public ref_counted {
m_cond.notify_all(); m_cond.notify_all();
} }
actor_ptr m_worker; actor m_worker;
private: private:
...@@ -452,15 +454,15 @@ class remote_group_module : public group::module { ...@@ -452,15 +454,15 @@ class remote_group_module : public group::module {
auto sm = make_counted<shared_map>(); auto sm = make_counted<shared_map>();
group::module_ptr _this = this; group::module_ptr _this = this;
m_map = sm; m_map = sm;
auto worker = spawn<blocking_api+hidden>([_this, sm] { m_map->m_worker = spawn<hidden>([=](event_based_actor* self) -> behavior {
CPPA_LOGC_TRACE(detail::demangle(typeid(*_this)), CPPA_LOGC_TRACE(detail::demangle(typeid(*_this)),
"remote_group_module$worker", "remote_group_module$worker",
""); "");
typedef map<string, pair<actor_ptr, vector<pair<string, remote_group_ptr>>>> typedef map<string, pair<actor, vector<pair<string, remote_group_ptr>>>>
peer_map; peer_map;
peer_map peers; auto peers = std::make_shared<peer_map>();
receive_loop ( return (
on(atom("FETCH"), arg_match) >> [_this, sm, &peers](const string& key) { on(atom("FETCH"), arg_match) >> [=](const string& key) {
// format is group@host:port // format is group@host:port
auto pos1 = key.find('@'); auto pos1 = key.find('@');
auto pos2 = key.find(':'); auto pos2 = key.find(':');
...@@ -469,9 +471,9 @@ class remote_group_module : public group::module { ...@@ -469,9 +471,9 @@ class remote_group_module : public group::module {
if (pos1 != last && pos2 != last && pos1 < pos2) { if (pos1 != last && pos2 != last && pos1 < pos2) {
auto name = key.substr(0, pos1); auto name = key.substr(0, pos1);
authority = key.substr(pos1 + 1); authority = key.substr(pos1 + 1);
auto i = peers.find(authority); auto i = peers->find(authority);
actor_ptr nameserver; actor nameserver;
if (i != peers.end()) { if (i != peers->end()) {
nameserver = i->second.first; nameserver = i->second.first;
} }
else { else {
...@@ -483,7 +485,7 @@ class remote_group_module : public group::module { ...@@ -483,7 +485,7 @@ class remote_group_module : public group::module {
try { try {
nameserver = remote_actor(host, port); nameserver = remote_actor(host, port);
self->monitor(nameserver); self->monitor(nameserver);
peers[authority].first = nameserver; (*peers)[authority].first = nameserver;
} }
catch (exception&) { catch (exception&) {
sm->put(key, nullptr); sm->put(key, nullptr);
...@@ -491,13 +493,13 @@ class remote_group_module : public group::module { ...@@ -491,13 +493,13 @@ class remote_group_module : public group::module {
} }
} }
} }
sync_send(nameserver, atom("GET_GROUP"), name).await ( self->timed_sync_send(chrono::seconds(10), nameserver, atom("GET_GROUP"), name).then (
on(atom("GROUP"), arg_match) >> [&](const group_ptr& g) { on(atom("GROUP"), arg_match) >> [&](const group_ptr& g) {
auto gg = dynamic_cast<local_group*>(g.get()); auto gg = dynamic_cast<local_group*>(g.get());
if (gg) { if (gg) {
auto rg = make_counted<remote_group>(_this, key, gg); auto rg = make_counted<remote_group>(_this, key, gg);
sm->put(key, rg); sm->put(key, rg);
peers[authority].second.push_back(make_pair(key, rg)); (*peers)[authority].second.push_back(make_pair(key, rg));
} }
else { else {
cerr << "*** WARNING: received a non-local " cerr << "*** WARNING: received a non-local "
...@@ -509,7 +511,7 @@ class remote_group_module : public group::module { ...@@ -509,7 +511,7 @@ class remote_group_module : public group::module {
sm->put(key, nullptr); sm->put(key, nullptr);
} }
}, },
after(chrono::seconds(10)) >> [sm, &key] { on(atom("TIMEOUT")) >> [sm, &key] {
sm->put(key, nullptr); sm->put(key, nullptr);
} }
); );
...@@ -518,22 +520,21 @@ class remote_group_module : public group::module { ...@@ -518,22 +520,21 @@ class remote_group_module : public group::module {
on<atom("DOWN"), std::uint32_t>() >> [&] { on<atom("DOWN"), std::uint32_t>() >> [&] {
auto who = self->last_sender(); auto who = self->last_sender();
auto find_peer = [&] { auto find_peer = [&] {
return find_if(begin(peers), end(peers), [&](const peer_map::value_type& kvp) { return find_if(begin(*peers), end(*peers), [&](const peer_map::value_type& kvp) {
return kvp.second.first == who; return kvp.second.first == who;
}); });
}; };
for (auto i = find_peer(); i != peers.end(); i = find_peer()) { for (auto i = find_peer(); i != peers->end(); i = find_peer()) {
for (auto& kvp: i->second.second) { for (auto& kvp: i->second.second) {
sm->put(kvp.first, nullptr); sm->put(kvp.first, nullptr);
kvp.second->group_down(); kvp.second->group_down();
} }
peers.erase(i); peers->erase(i);
} }
}, },
others() >> [] { } others() >> [] { }
); );
}); });
sm->m_worker = worker;
} }
intrusive_ptr<group> get(const std::string& group_name) { intrusive_ptr<group> get(const std::string& group_name) {
......
...@@ -42,12 +42,12 @@ namespace { ...@@ -42,12 +42,12 @@ namespace {
class down_observer : public attachable { class down_observer : public attachable {
actor_ptr m_observer; actor_addr m_observer;
actor_ptr m_observed; actor_addr m_observed;
public: public:
down_observer(actor_ptr observer, actor_ptr observed) down_observer(actor_addr observer, actor_addr observed)
: m_observer(std::move(observer)), m_observed(std::move(observed)) { : m_observer(std::move(observer)), m_observed(std::move(observed)) {
CPPA_REQUIRE(m_observer != nullptr); CPPA_REQUIRE(m_observer != nullptr);
CPPA_REQUIRE(m_observed != nullptr); CPPA_REQUIRE(m_observed != nullptr);
...@@ -55,7 +55,8 @@ class down_observer : public attachable { ...@@ -55,7 +55,8 @@ class down_observer : public attachable {
void actor_exited(std::uint32_t reason) { void actor_exited(std::uint32_t reason) {
if (m_observer) { if (m_observer) {
message_header hdr{m_observed, m_observer, message_priority::high}; auto ptr = detail::actor_addr_cast<abstract_actor>(m_observer);
message_header hdr{m_observed, ptr, message_priority::high};
hdr.deliver(make_any_tuple(atom("DOWN"), reason)); hdr.deliver(make_any_tuple(atom("DOWN"), reason));
} }
} }
...@@ -63,7 +64,7 @@ class down_observer : public attachable { ...@@ -63,7 +64,7 @@ class down_observer : public attachable {
bool matches(const attachable::token& match_token) { bool matches(const attachable::token& match_token) {
if (match_token.subtype == typeid(down_observer)) { if (match_token.subtype == typeid(down_observer)) {
auto ptr = reinterpret_cast<const local_actor*>(match_token.ptr); auto ptr = reinterpret_cast<const local_actor*>(match_token.ptr);
return m_observer == ptr; return m_observer == ptr->address();
} }
return false; return false;
} }
...@@ -75,7 +76,7 @@ constexpr const char* s_default_debug_name = "actor"; ...@@ -75,7 +76,7 @@ constexpr const char* s_default_debug_name = "actor";
} // namespace <anonymous> } // namespace <anonymous>
local_actor::local_actor(bool sflag) local_actor::local_actor(bool sflag)
: m_chaining(sflag), m_trap_exit(false) : m_trap_exit(false)
, m_is_scheduled(sflag), m_dummy_node(), m_current_node(&m_dummy_node) , m_is_scheduled(sflag), m_dummy_node(), m_current_node(&m_dummy_node)
, m_planned_exit_reason(exit_reason::not_exited) { , m_planned_exit_reason(exit_reason::not_exited) {
# ifdef CPPA_DEBUG_MODE # ifdef CPPA_DEBUG_MODE
...@@ -107,13 +108,17 @@ void local_actor::debug_name(std::string str) { ...@@ -107,13 +108,17 @@ void local_actor::debug_name(std::string str) {
# endif // CPPA_DEBUG_MODE # endif // CPPA_DEBUG_MODE
} }
void local_actor::monitor(const actor_ptr& whom) { void local_actor::monitor(const actor_addr& whom) {
if (whom) whom->attach(attachable_ptr{new down_observer(this, whom)}); if (!whom) return;
auto ptr = detail::actor_addr_cast<abstract_actor>(whom);
ptr->attach(attachable_ptr{new down_observer(address(), whom)});
} }
void local_actor::demonitor(const actor_ptr& whom) { void local_actor::demonitor(const actor_addr& whom) {
if (!whom) return;
auto ptr = detail::actor_addr_cast<abstract_actor>(whom);
attachable::token mtoken{typeid(down_observer), this}; attachable::token mtoken{typeid(down_observer), this};
if (whom) whom->detach(mtoken); ptr->detach(mtoken);
} }
void local_actor::on_exit() { } void local_actor::on_exit() { }
...@@ -139,43 +144,35 @@ std::vector<group_ptr> local_actor::joined_groups() const { ...@@ -139,43 +144,35 @@ std::vector<group_ptr> local_actor::joined_groups() const {
} }
void local_actor::reply_message(any_tuple&& what) { void local_actor::reply_message(any_tuple&& what) {
auto& whom = last_sender(); auto& whom = m_current_node->sender;
if (whom == nullptr) { if (!whom) return;
return;
}
auto& id = m_current_node->mid; auto& id = m_current_node->mid;
if (id.valid() == false || id.is_response()) { if (id.valid() == false || id.is_response()) {
send_tuple(whom, std::move(what)); send_tuple(detail::actor_addr_cast<abstract_actor>(whom), std::move(what));
} }
else if (!id.is_answered()) { else if (!id.is_answered()) {
if (chaining_enabled()) { auto ptr = detail::actor_addr_cast<abstract_actor>(whom);
if (whom->chained_enqueue({this, whom, id.response_id()}, std::move(what))) { ptr->enqueue({address(), ptr, id.response_id()}, std::move(what));
chained_actor(whom);
}
}
else whom->enqueue({this, whom, id.response_id()}, std::move(what));
id.mark_as_answered(); id.mark_as_answered();
} }
} }
void local_actor::forward_message(const actor_ptr& dest, message_priority p) { void local_actor::forward_message(const actor& dest, message_priority p) {
if (dest == nullptr) return; if (!dest) return;
auto& id = m_current_node->mid; auto& id = m_current_node->mid;
dest->enqueue({last_sender(), dest, id, p}, m_current_node->msg); dest.m_ptr->enqueue({m_current_node->sender, dest.m_ptr, id, p}, m_current_node->msg);
// treat this message as asynchronous message from now on // treat this message as asynchronous message from now on
id = message_id{}; id = message_id{};
} }
/* TODO:
response_handle local_actor::make_response_handle() { response_handle local_actor::make_response_handle() {
auto n = m_current_node; auto n = m_current_node;
response_handle result{this, n->sender, n->mid.response_id()}; response_handle result{this, n->sender, n->mid.response_id()};
n->mid.mark_as_answered(); n->mid.mark_as_answered();
return result; return result;
} }
*/
void local_actor::exec_behavior_stack() {
// default implementation does nothing
}
void local_actor::cleanup(std::uint32_t reason) { void local_actor::cleanup(std::uint32_t reason) {
m_subscriptions.clear(); m_subscriptions.clear();
......
...@@ -72,11 +72,11 @@ class logging_impl : public logging { ...@@ -72,11 +72,11 @@ class logging_impl : public logging {
void initialize() { void initialize() {
m_thread = thread([this] { (*this)(); }); m_thread = thread([this] { (*this)(); });
log("TRACE", "logging", "run", __FILE__, __LINE__, nullptr, "ENTRY"); log("TRACE", "logging", "run", __FILE__, __LINE__, invalid_actor_addr, "ENTRY");
} }
void destroy() { void destroy() {
log("TRACE", "logging", "run", __FILE__, __LINE__, nullptr, "EXIT"); log("TRACE", "logging", "run", __FILE__, __LINE__, invalid_actor_addr, "EXIT");
// an empty string means: shut down // an empty string means: shut down
m_queue.push_back(new log_event{0, ""}); m_queue.push_back(new log_event{0, ""});
m_thread.join(); m_thread.join();
...@@ -103,7 +103,7 @@ class logging_impl : public logging { ...@@ -103,7 +103,7 @@ class logging_impl : public logging {
const char* function_name, const char* function_name,
const char* c_full_file_name, const char* c_full_file_name,
int line_num, int line_num,
const actor_ptr& from, actor_addr from,
const std::string& msg) { const std::string& msg) {
string class_name = c_class_name; string class_name = c_class_name;
replace_all(class_name, "::", "."); replace_all(class_name, "::", ".");
...@@ -118,6 +118,7 @@ class logging_impl : public logging { ...@@ -118,6 +118,7 @@ class logging_impl : public logging {
} }
else file_name = move(full_file_name); else file_name = move(full_file_name);
auto print_from = [&](ostream& oss) -> ostream& { auto print_from = [&](ostream& oss) -> ostream& {
/*TODO:
if (!from) { if (!from) {
if (strcmp(c_class_name, "logging") == 0) oss << "logging"; if (strcmp(c_class_name, "logging") == 0) oss << "logging";
else oss << "null"; else oss << "null";
...@@ -130,6 +131,7 @@ class logging_impl : public logging { ...@@ -130,6 +131,7 @@ class logging_impl : public logging {
oss << from->id() << "@local"; oss << from->id() << "@local";
# endif // CPPA_DEBUG_MODE # endif // CPPA_DEBUG_MODE
} }
*/
return oss; return oss;
}; };
ostringstream line; ostringstream line;
...@@ -158,7 +160,7 @@ logging::trace_helper::trace_helper(std::string class_name, ...@@ -158,7 +160,7 @@ logging::trace_helper::trace_helper(std::string class_name,
const char* fun_name, const char* fun_name,
const char* file_name, const char* file_name,
int line_num, int line_num,
actor_ptr ptr, actor_addr ptr,
const std::string& msg) const std::string& msg)
: m_class(std::move(class_name)), m_fun_name(fun_name) : m_class(std::move(class_name)), m_fun_name(fun_name)
, m_file_name(file_name), m_line_num(line_num), m_self(std::move(ptr)) { , m_file_name(file_name), m_line_num(line_num), m_self(std::move(ptr)) {
......
...@@ -28,32 +28,19 @@ ...@@ -28,32 +28,19 @@
\******************************************************************************/ \******************************************************************************/
#include "cppa/self.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/message_header.hpp" #include "cppa/message_header.hpp"
namespace cppa { namespace cppa {
message_header::message_header(const std::nullptr_t&) message_header::message_header(actor_addr source,
: priority(message_priority::normal) { } channel dest,
message_header::message_header(const self_type&)
: sender(self), receiver(self), priority(message_priority::normal) { }
message_header::message_header(channel_ptr dest, message_id mid, message_priority prio)
: sender(self), receiver(dest), id(mid), priority(prio) { }
message_header::message_header(channel_ptr dest, message_priority prio)
: sender(self), receiver(dest), priority(prio) { }
message_header::message_header(actor_ptr source,
channel_ptr dest,
message_id mid, message_id mid,
message_priority prio) message_priority prio)
: sender(source), receiver(dest), id(mid), priority(prio) { } : sender(source), receiver(dest), id(mid), priority(prio) { }
message_header::message_header(actor_ptr source, message_header::message_header(actor_addr source,
channel_ptr dest, channel dest,
message_priority prio) message_priority prio)
: sender(source), receiver(dest), priority(prio) { } : sender(source), receiver(dest), priority(prio) { }
...@@ -69,7 +56,7 @@ bool operator!=(const message_header& lhs, const message_header& rhs) { ...@@ -69,7 +56,7 @@ bool operator!=(const message_header& lhs, const message_header& rhs) {
} }
void message_header::deliver(any_tuple msg) const { void message_header::deliver(any_tuple msg) const {
if (receiver) receiver->enqueue(*this, std::move(msg)); receiver.enqueue(*this, std::move(msg));
} }
} // namespace cppa::network } // namespace cppa::network
...@@ -135,7 +135,7 @@ class middleman_impl : public middleman { ...@@ -135,7 +135,7 @@ class middleman_impl : public middleman {
}); });
m_namespace.set_new_element_callback([=](actor_id aid, const node_id& node) { m_namespace.set_new_element_callback([=](actor_id aid, const node_id& node) {
deliver(node, deliver(node,
{nullptr, nullptr}, {invalid_actor_addr, nullptr},
make_any_tuple(atom("MONITOR"), make_any_tuple(atom("MONITOR"),
node_id::get(), node_id::get(),
aid)); aid));
...@@ -237,7 +237,7 @@ class middleman_impl : public middleman { ...@@ -237,7 +237,7 @@ class middleman_impl : public middleman {
if (node) register_peer(*node, ptr); if (node) register_peer(*node, ptr);
} }
void register_acceptor(const actor_ptr& whom, peer_acceptor* ptr) override { void register_acceptor(const actor_addr& whom, peer_acceptor* ptr) override {
run_later([=] { run_later([=] {
CPPA_LOGC_TRACE("cppa::io::middleman", CPPA_LOGC_TRACE("cppa::io::middleman",
"register_acceptor$lambda", ""); "register_acceptor$lambda", "");
...@@ -288,9 +288,9 @@ class middleman_impl : public middleman { ...@@ -288,9 +288,9 @@ class middleman_impl : public middleman {
default_message_queue_ptr queue; default_message_queue_ptr queue;
}; };
std::map<actor_ptr, std::vector<peer_acceptor*>> m_acceptors; std::map<actor_addr, std::vector<peer_acceptor*>> m_acceptors;
std::map<node_id, peer_entry> m_peers; std::map<node_id, peer_entry> m_peers;
}; };
class middleman_overseer : public continuable { class middleman_overseer : public continuable {
...@@ -349,7 +349,6 @@ middleman::~middleman() { } ...@@ -349,7 +349,6 @@ middleman::~middleman() { }
void middleman_loop(middleman_impl* impl) { void middleman_loop(middleman_impl* impl) {
# ifdef CPPA_LOG_LEVEL # ifdef CPPA_LOG_LEVEL
auto mself = make_counted<thread_mapped_actor>(); auto mself = make_counted<thread_mapped_actor>();
scoped_self_setter sss(mself.get());
CPPA_SET_DEBUG_NAME("middleman"); CPPA_SET_DEBUG_NAME("middleman");
# endif # endif
middleman_event_handler* handler = impl->m_handler.get(); middleman_event_handler* handler = impl->m_handler.get();
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
#include <cstdint> #include <cstdint>
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/send.hpp" #include "cppa/cppa.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/match.hpp" #include "cppa/match.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
...@@ -84,9 +84,7 @@ void peer::io_failed(event_bitmask mask) { ...@@ -84,9 +84,7 @@ void peer::io_failed(event_bitmask mask) {
auto& children = parent()->get_namespace().proxies(*m_node); auto& children = parent()->get_namespace().proxies(*m_node);
for (auto& kvp : children) { for (auto& kvp : children) {
auto ptr = kvp.second.promote(); auto ptr = kvp.second.promote();
if (ptr) ptr->enqueue(nullptr, send_as(ptr, ptr, atom("KILL_PROXY"), exit_reason::remote_link_unreachable);
make_any_tuple(atom("KILL_PROXY"),
exit_reason::remote_link_unreachable));
} }
parent()->get_namespace().erase(*m_node); parent()->get_namespace().erase(*m_node);
} }
...@@ -160,10 +158,10 @@ continue_reading_result peer::continue_reading() { ...@@ -160,10 +158,10 @@ continue_reading_result peer::continue_reading() {
on(atom("KILL_PROXY"), arg_match) >> [&](const node_id_ptr& node, actor_id aid, std::uint32_t reason) { on(atom("KILL_PROXY"), arg_match) >> [&](const node_id_ptr& node, actor_id aid, std::uint32_t reason) {
kill_proxy(hdr.sender, node, aid, reason); kill_proxy(hdr.sender, node, aid, reason);
}, },
on(atom("LINK"), arg_match) >> [&](const actor_ptr& ptr) { on(atom("LINK"), arg_match) >> [&](const actor_addr& ptr) {
link(hdr.sender, ptr); link(hdr.sender, ptr);
}, },
on(atom("UNLINK"), arg_match) >> [&](const actor_ptr& ptr) { on(atom("UNLINK"), arg_match) >> [&](const actor_addr& ptr) {
unlink(hdr.sender, ptr); unlink(hdr.sender, ptr);
}, },
on(atom("ADD_TYPE"), arg_match) >> [&](std::uint32_t id, const std::string& name) { on(atom("ADD_TYPE"), arg_match) >> [&](std::uint32_t id, const std::string& name) {
...@@ -188,9 +186,9 @@ continue_reading_result peer::continue_reading() { ...@@ -188,9 +186,9 @@ continue_reading_result peer::continue_reading() {
} }
} }
void peer::monitor(const actor_ptr&, void peer::monitor(const actor_addr&,
const node_id_ptr& node, const node_id_ptr& node,
actor_id aid) { actor_id aid) {
CPPA_LOG_TRACE(CPPA_MARG(node, get) << ", " << CPPA_ARG(aid)); CPPA_LOG_TRACE(CPPA_MARG(node, get) << ", " << CPPA_ARG(aid));
if (!node) { if (!node) {
CPPA_LOGMF(CPPA_ERROR, self, "received MONITOR from invalid peer"); CPPA_LOGMF(CPPA_ERROR, self, "received MONITOR from invalid peer");
...@@ -232,10 +230,10 @@ void peer::monitor(const actor_ptr&, ...@@ -232,10 +230,10 @@ void peer::monitor(const actor_ptr&,
} }
} }
void peer::kill_proxy(const actor_ptr& sender, void peer::kill_proxy(const actor_addr& sender,
const node_id_ptr& node, const node_id_ptr& node,
actor_id aid, actor_id aid,
std::uint32_t reason) { std::uint32_t reason) {
CPPA_LOG_TRACE(CPPA_TARG(sender, to_string) CPPA_LOG_TRACE(CPPA_TARG(sender, to_string)
<< ", " << CPPA_MARG(node, get) << ", " << CPPA_MARG(node, get)
<< ", " << CPPA_ARG(aid) << ", " << CPPA_ARG(aid)
...@@ -250,9 +248,9 @@ void peer::kill_proxy(const actor_ptr& sender, ...@@ -250,9 +248,9 @@ void peer::kill_proxy(const actor_ptr& sender,
} }
auto proxy = parent()->get_namespace().get(*node, aid); auto proxy = parent()->get_namespace().get(*node, aid);
if (proxy) { if (proxy) {
CPPA_LOGMF(CPPA_DEBUG, self, "received KILL_PROXY for " << aid CPPA_LOG_DEBUG("received KILL_PROXY for " << aid
<< ":" << to_string(*node)); << ":" << to_string(*node));
send_as(nullptr, proxy, atom("KILL_PROXY"), reason); send_as(proxy, proxy, atom("KILL_PROXY"), reason);
} }
else { else {
CPPA_LOG_INFO("received KILL_PROXY message but " CPPA_LOG_INFO("received KILL_PROXY message but "
...@@ -263,46 +261,62 @@ void peer::kill_proxy(const actor_ptr& sender, ...@@ -263,46 +261,62 @@ void peer::kill_proxy(const actor_ptr& sender,
void peer::deliver(const message_header& hdr, any_tuple msg) { void peer::deliver(const message_header& hdr, any_tuple msg) {
CPPA_LOG_TRACE(""); CPPA_LOG_TRACE("");
if (hdr.sender && hdr.sender->is_proxy()) { if (hdr.sender && hdr.sender.is_remote()) {
hdr.sender.downcast<actor_proxy>()->deliver(hdr, std::move(msg)); auto ptr = detail::actor_addr_cast<actor_proxy>(hdr.sender);
ptr->deliver(hdr, std::move(msg));
} }
else hdr.deliver(std::move(msg)); else hdr.deliver(std::move(msg));
} }
void peer::link(const actor_ptr& sender, const actor_ptr& ptr) { void peer::link(const actor_addr& sender, const actor_addr& receiver) {
// this message is sent from default_actor_proxy in link_to and // this message is sent from default_actor_proxy in link_to and
// establish_backling to cause the original actor (sender) to establish // establish_backling to cause the original actor (sender) to establish
// a link to ptr as well // a link to ptr as well
CPPA_LOG_TRACE(CPPA_MARG(sender, get) CPPA_LOG_TRACE(CPPA_MARG(sender, get)
<< ", " << CPPA_MARG(ptr, get)); << ", " << CPPA_MARG(ptr, get));
CPPA_LOG_ERROR_IF(!sender, "received 'LINK' from invalid sender"); CPPA_LOG_ERROR_IF(!sender, "received 'LINK' from invalid sender");
CPPA_LOG_ERROR_IF(!ptr, "received 'LINK' with invalid target"); CPPA_LOG_ERROR_IF(!receiver, "received 'LINK' with invalid receiver");
if (!sender || !ptr) return; if (!sender || !receiver) return;
CPPA_LOG_ERROR_IF(sender->is_proxy(), auto locally_link_proxy = [](const actor_addr& lhs, const actor_addr& rhs) {
"received 'LINK' for a non-local actor"); detail::actor_addr_cast<actor_proxy>(lhs)->local_link_to(rhs);
if (ptr->is_proxy()) { };
// make sure to not send a needless 'LINK' message back switch ((sender.is_remote() ? 0x10 : 0x00) | (receiver.is_remote() ? 0x01 : 0x00)) {
ptr.downcast<actor_proxy>()->local_link_to(sender); case 0x00: // both local
} case 0x11: // both remote
else sender->link_to(ptr); detail::actor_addr_cast<abstract_actor>(sender)->link_to(receiver);
if (ptr && sender && sender->is_proxy()) { break;
sender.downcast<actor_proxy>()->local_link_to(ptr); case 0x10: // sender is remote
locally_link_proxy(sender, receiver);
break;
case 0x01: // receiver is remote
locally_link_proxy(receiver, sender);
break;
default: CPPA_LOG_ERROR("logic error");
} }
} }
void peer::unlink(const actor_ptr& sender, const actor_ptr& ptr) { void peer::unlink(const actor_addr& sender, const actor_addr& receiver) {
CPPA_LOG_TRACE(CPPA_MARG(sender, get) CPPA_LOG_TRACE(CPPA_MARG(sender, get)
<< ", " << CPPA_MARG(ptr, get)); << ", " << CPPA_MARG(ptr, get));
CPPA_LOG_ERROR_IF(!sender, "received 'UNLINK' from invalid sender"); CPPA_LOG_ERROR_IF(!sender, "received 'UNLINK' from invalid sender");
CPPA_LOG_ERROR_IF(!ptr, "received 'UNLINK' with invalid target"); CPPA_LOG_ERROR_IF(!receiver, "received 'UNLINK' with invalid target");
if (!sender || !ptr) return; if (!sender || !receiver) return;
CPPA_LOG_ERROR_IF(sender->is_proxy(), auto locally_unlink_proxy = [](const actor_addr& lhs, const actor_addr& rhs) {
"received 'UNLINK' for a non-local actor"); detail::actor_addr_cast<actor_proxy>(lhs)->local_unlink_from(rhs);
if (ptr->is_proxy()) { };
// make sure to not send a needles 'UNLINK' message back switch ((sender.is_remote() ? 0x10 : 0x00) | (receiver.is_remote() ? 0x01 : 0x00)) {
ptr.downcast<actor_proxy>()->local_unlink_from(sender); case 0x00: // both local
case 0x11: // both remote
detail::actor_addr_cast<abstract_actor>(sender)->unlink_from(receiver);
break;
case 0x10: // sender is remote
locally_unlink_proxy(sender, receiver);
break;
case 0x01: // receiver is remote
locally_unlink_proxy(receiver, sender);
break;
default: CPPA_LOG_ERROR("logic error");
} }
else sender->unlink_from(ptr);
} }
continue_writing_result peer::continue_writing() { continue_writing_result peer::continue_writing() {
...@@ -327,7 +341,7 @@ void peer::add_type_if_needed(const std::string& tname) { ...@@ -327,7 +341,7 @@ void peer::add_type_if_needed(const std::string& tname) {
auto imap = get_uniform_type_info_map(); auto imap = get_uniform_type_info_map();
auto uti = imap->by_uniform_name(tname); auto uti = imap->by_uniform_name(tname);
m_outgoing_types.emplace(id, uti); m_outgoing_types.emplace(id, uti);
enqueue_impl({nullptr}, make_any_tuple(atom("ADD_TYPE"), id, tname)); enqueue_impl({invalid_actor_addr, nullptr}, make_any_tuple(atom("ADD_TYPE"), id, tname));
} }
} }
......
...@@ -46,7 +46,7 @@ namespace cppa { namespace io { ...@@ -46,7 +46,7 @@ namespace cppa { namespace io {
peer_acceptor::peer_acceptor(middleman* parent, peer_acceptor::peer_acceptor(middleman* parent,
acceptor_uptr aur, acceptor_uptr aur,
const actor_ptr& pa) const actor_addr& pa)
: super(aur->file_handle()), m_parent(parent), m_ptr(std::move(aur)), m_pa(pa) { } : super(aur->file_handle()), m_parent(parent), m_ptr(std::move(aur)), m_pa(pa) { }
continue_reading_result peer_acceptor::continue_reading() { continue_reading_result peer_acceptor::continue_reading() {
...@@ -64,7 +64,7 @@ continue_reading_result peer_acceptor::continue_reading() { ...@@ -64,7 +64,7 @@ continue_reading_result peer_acceptor::continue_reading() {
auto& pself = node_id::get(); auto& pself = node_id::get();
uint32_t process_id = pself->process_id(); uint32_t process_id = pself->process_id();
try { try {
actor_id aid = published_actor()->id(); actor_id aid = published_actor().id();
pair.second->write(&aid, sizeof(actor_id)); pair.second->write(&aid, sizeof(actor_id));
pair.second->write(&process_id, sizeof(uint32_t)); pair.second->write(&process_id, sizeof(uint32_t));
pair.second->write(pself->host_id().data(), pair.second->write(pself->host_id().data(),
......
...@@ -44,11 +44,11 @@ using namespace std; ...@@ -44,11 +44,11 @@ using namespace std;
namespace cppa { namespace io { namespace cppa { namespace io {
inline sync_request_info* new_req_info(actor_ptr sptr, message_id id) { inline sync_request_info* new_req_info(actor_addr sptr, message_id id) {
return detail::memory::create<sync_request_info>(std::move(sptr), id); return detail::memory::create<sync_request_info>(std::move(sptr), id);
} }
sync_request_info::sync_request_info(actor_ptr sptr, message_id id) sync_request_info::sync_request_info(actor_addr sptr, message_id id)
: next(nullptr), sender(std::move(sptr)), mid(id) { } : next(nullptr), sender(std::move(sptr)), mid(id) { }
remote_actor_proxy::remote_actor_proxy(actor_id mid, remote_actor_proxy::remote_actor_proxy(actor_id mid,
...@@ -113,7 +113,7 @@ void remote_actor_proxy::forward_msg(const message_header& hdr, any_tuple msg) { ...@@ -113,7 +113,7 @@ void remote_actor_proxy::forward_msg(const message_header& hdr, any_tuple msg) {
"forward_msg$bouncer", "forward_msg$bouncer",
"bounce message for reason " << rsn); "bounce message for reason " << rsn);
detail::sync_request_bouncer f{rsn}; detail::sync_request_bouncer f{rsn};
f(hdr.sender.get(), hdr.id); f(hdr.sender, hdr.id);
}); });
return; // no need to forward message return; // no need to forward message
} }
...@@ -147,57 +147,51 @@ void remote_actor_proxy::enqueue(const message_header& hdr, any_tuple msg) { ...@@ -147,57 +147,51 @@ void remote_actor_proxy::enqueue(const message_header& hdr, any_tuple msg) {
_this->cleanup(reason); _this->cleanup(reason);
detail::sync_request_bouncer f{reason}; detail::sync_request_bouncer f{reason};
_this->m_pending_requests.close([&](const sync_request_info& e) { _this->m_pending_requests.close([&](const sync_request_info& e) {
f(e.sender.get(), e.mid); f(e.sender, e.mid);
}); });
}); });
} }
else forward_msg(hdr, move(msg)); else forward_msg(hdr, move(msg));
} }
void remote_actor_proxy::link_to(const intrusive_ptr<actor>& other) { void remote_actor_proxy::link_to(const actor_addr& other) {
CPPA_LOG_TRACE(CPPA_MARG(other, get));
if (link_to_impl(other)) { if (link_to_impl(other)) {
// causes remote actor to link to (proxy of) other // causes remote actor to link to (proxy of) other
// receiving peer will call: this->local_link_to(other) // receiving peer will call: this->local_link_to(other)
forward_msg({this, this}, make_any_tuple(atom("LINK"), other)); forward_msg({address(), this}, make_any_tuple(atom("LINK"), other));
} }
} }
void remote_actor_proxy::unlink_from(const intrusive_ptr<actor>& other) { void remote_actor_proxy::unlink_from(const actor_addr& other) {
CPPA_LOG_TRACE(CPPA_MARG(other, get));
if (unlink_from_impl(other)) { if (unlink_from_impl(other)) {
// causes remote actor to unlink from (proxy of) other // causes remote actor to unlink from (proxy of) other
forward_msg({this, this}, make_any_tuple(atom("UNLINK"), other)); forward_msg({address(), this}, make_any_tuple(atom("UNLINK"), other));
} }
} }
bool remote_actor_proxy::establish_backlink(const intrusive_ptr<actor>& other) { bool remote_actor_proxy::establish_backlink(const actor_addr& other) {
CPPA_LOG_TRACE(CPPA_MARG(other, get));
if (super::establish_backlink(other)) { if (super::establish_backlink(other)) {
// causes remote actor to unlink from (proxy of) other // causes remote actor to unlink from (proxy of) other
forward_msg({this, this}, make_any_tuple(atom("LINK"), other)); forward_msg({address(), this}, make_any_tuple(atom("LINK"), other));
return true; return true;
} }
return false; return false;
} }
bool remote_actor_proxy::remove_backlink(const intrusive_ptr<actor>& other) { bool remote_actor_proxy::remove_backlink(const actor_addr& other) {
CPPA_LOG_TRACE(CPPA_MARG(other, get));
if (super::remove_backlink(other)) { if (super::remove_backlink(other)) {
// causes remote actor to unlink from (proxy of) other // causes remote actor to unlink from (proxy of) other
forward_msg({this, this}, make_any_tuple(atom("UNLINK"), other)); forward_msg({address(), this}, make_any_tuple(atom("UNLINK"), other));
return true; return true;
} }
return false; return false;
} }
void remote_actor_proxy::local_link_to(const intrusive_ptr<actor>& other) { void remote_actor_proxy::local_link_to(const actor_addr& other) {
CPPA_LOG_TRACE(CPPA_MARG(other, get));
link_to_impl(other); link_to_impl(other);
} }
void remote_actor_proxy::local_unlink_from(const intrusive_ptr<actor>& other) { void remote_actor_proxy::local_unlink_from(const actor_addr& other) {
CPPA_LOG_TRACE(CPPA_MARG(other, get));
unlink_from_impl(other); unlink_from_impl(other);
} }
......
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
#include <utility> #include <utility>
#include "cppa/self.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/response_handle.hpp" #include "cppa/response_handle.hpp"
...@@ -38,8 +37,8 @@ using std::move; ...@@ -38,8 +37,8 @@ using std::move;
namespace cppa { namespace cppa {
response_handle::response_handle(const actor_ptr& from, response_handle::response_handle(const actor_addr& from,
const actor_ptr& to, const actor_addr& to,
const message_id& id) const message_id& id)
: m_from(from), m_to(to), m_id(id) { : m_from(from), m_to(to), m_id(id) {
CPPA_REQUIRE(id.is_response() || !id.valid()); CPPA_REQUIRE(id.is_response() || !id.valid());
...@@ -55,14 +54,8 @@ bool response_handle::synchronous() const { ...@@ -55,14 +54,8 @@ bool response_handle::synchronous() const {
void response_handle::apply(any_tuple msg) const { void response_handle::apply(any_tuple msg) const {
if (valid()) { if (valid()) {
local_actor* sptr = self.unchecked(); auto ptr = detail::actor_addr_cast<abstract_actor>(m_to);
bool use_chaining = sptr && sptr == m_from && sptr->chaining_enabled(); ptr->enqueue({m_from, ptr, m_id}, move(msg));
if (use_chaining) {
if (m_to->chained_enqueue({m_from, m_to, m_id}, move(msg))) {
sptr->chained_actor(m_to);
}
}
else m_to->enqueue({m_from, m_to, m_id}, move(msg));
} }
} }
......
...@@ -44,16 +44,9 @@ void scheduled_actor::attach_to_scheduler(scheduler* sched, bool hidden) { ...@@ -44,16 +44,9 @@ void scheduled_actor::attach_to_scheduler(scheduler* sched, bool hidden) {
CPPA_REQUIRE(sched != nullptr); CPPA_REQUIRE(sched != nullptr);
m_scheduler = sched; m_scheduler = sched;
m_hidden = hidden; m_hidden = hidden;
// init is called by the spawning actor, manipulate self to
// point to this actor
scoped_self_setter sss{this};
// initialize this actor // initialize this actor
try { init(); } try { init(); }
catch (...) { } catch (...) { }
// check whether init() did send a chained message
actor_ptr ca;
ca.swap(m_chained_actor);
if (ca) ca->unchain();
} }
bool scheduled_actor::initialized() const { bool scheduled_actor::initialized() const {
...@@ -136,16 +129,4 @@ void scheduled_actor::enqueue(const message_header& hdr, any_tuple msg) { ...@@ -136,16 +129,4 @@ void scheduled_actor::enqueue(const message_header& hdr, any_tuple msg) {
enqueue_impl(actor_state::ready, hdr, std::move(msg)); enqueue_impl(actor_state::ready, hdr, std::move(msg));
} }
bool scheduled_actor::chained_enqueue(const message_header& hdr, any_tuple msg) {
return enqueue_impl(actor_state::pending, hdr, std::move(msg));
}
void scheduled_actor::unchain() {
auto state = actor_state::pending;
if (m_state.compare_exchange_weak(state, actor_state::ready)) {
CPPA_REQUIRE(m_scheduler != nullptr);
m_scheduler->enqueue(this);
}
}
} // namespace cppa } // namespace cppa
...@@ -43,7 +43,7 @@ void scheduled_actor_dummy::do_become(behavior&&, bool) { } ...@@ -43,7 +43,7 @@ void scheduled_actor_dummy::do_become(behavior&&, bool) { }
void scheduled_actor_dummy::become_waiting_for(behavior, message_id) { } void scheduled_actor_dummy::become_waiting_for(behavior, message_id) { }
bool scheduled_actor_dummy::has_behavior() { return false; } bool scheduled_actor_dummy::has_behavior() { return false; }
resume_result scheduled_actor_dummy::resume(util::fiber*, actor_ptr&) { resume_result scheduled_actor_dummy::resume(util::fiber*) {
return resume_result::actor_blocked; return resume_result::actor_blocked;
} }
......
...@@ -34,8 +34,6 @@ ...@@ -34,8 +34,6 @@
#include <iostream> #include <iostream>
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/self.hpp"
#include "cppa/receive.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/anything.hpp" #include "cppa/anything.hpp"
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
...@@ -107,23 +105,23 @@ class scheduler_helper { ...@@ -107,23 +105,23 @@ class scheduler_helper {
void stop() { void stop() {
auto msg = make_any_tuple(atom("DIE")); auto msg = make_any_tuple(atom("DIE"));
m_timer->enqueue(nullptr, msg); m_timer.enqueue({invalid_actor_addr, nullptr}, msg);
m_printer->enqueue(nullptr, msg); m_printer.enqueue({invalid_actor_addr, nullptr}, msg);
m_timer_thread.join(); m_timer_thread.join();
m_printer_thread.join(); m_printer_thread.join();
} }
actor_ptr m_timer; actor m_timer;
std::thread m_timer_thread; std::thread m_timer_thread;
actor_ptr m_printer; actor m_printer;
std::thread m_printer_thread; std::thread m_printer_thread;
private: private:
static void timer_loop(ptr_type m_self); static void timer_loop(thread_mapped_actor* self);
static void printer_loop(ptr_type m_self); static void printer_loop(thread_mapped_actor* self);
}; };
...@@ -138,9 +136,8 @@ inline void insert_dmsg(Map& storage, ...@@ -138,9 +136,8 @@ inline void insert_dmsg(Map& storage,
storage.insert(std::make_pair(std::move(tout), std::move(dmsg))); storage.insert(std::make_pair(std::move(tout), std::move(dmsg)));
} }
void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) { void scheduler_helper::timer_loop(thread_mapped_actor* self) {
// setup & local variables // setup & local variables
self.set(m_self.get());
bool done = false; bool done = false;
std::unique_ptr<mailbox_element, detail::disposer> msg_ptr; std::unique_ptr<mailbox_element, detail::disposer> msg_ptr;
auto tout = hrc::now(); auto tout = hrc::now();
...@@ -166,7 +163,7 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) { ...@@ -166,7 +163,7 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) {
// loop // loop
while (!done) { while (!done) {
while (!msg_ptr) { while (!msg_ptr) {
if (messages.empty()) msg_ptr.reset(m_self->pop()); if (messages.empty()) msg_ptr.reset(self->pop());
else { else {
tout = hrc::now(); tout = hrc::now();
// handle timeouts (send messages) // handle timeouts (send messages)
...@@ -178,7 +175,7 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) { ...@@ -178,7 +175,7 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) {
} }
// wait for next message or next timeout // wait for next message or next timeout
if (it != messages.end()) { if (it != messages.end()) {
msg_ptr.reset(m_self->try_pop(it->first)); msg_ptr.reset(self->try_pop(it->first));
} }
} }
} }
...@@ -187,10 +184,9 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) { ...@@ -187,10 +184,9 @@ void scheduler_helper::timer_loop(scheduler_helper::ptr_type m_self) {
} }
} }
void scheduler_helper::printer_loop(ptr_type m_self) { void scheduler_helper::printer_loop(thread_mapped_actor* self) {
self.set(m_self.get()); std::map<actor, std::string> out;
std::map<actor_ptr, std::string> out; auto flush_output = [&out](const actor& s) {
auto flush_output = [&out](const actor_ptr& s) {
auto i = out.find(s); auto i = out.find(s);
if (i != out.end()) { if (i != out.end()) {
auto& line = i->second; auto& line = i->second;
...@@ -207,7 +203,7 @@ void scheduler_helper::printer_loop(ptr_type m_self) { ...@@ -207,7 +203,7 @@ void scheduler_helper::printer_loop(ptr_type m_self) {
} }
}; };
bool running = true; bool running = true;
receive_while (gref(running)) ( self->receive_while (gref(running)) (
on(atom("add"), arg_match) >> [&](std::string& str) { on(atom("add"), arg_match) >> [&](std::string& str) {
auto s = self->last_sender(); auto s = self->last_sender();
if (!str.empty() && s != nullptr) { if (!str.empty() && s != nullptr) {
...@@ -261,7 +257,7 @@ scheduler::~scheduler() { ...@@ -261,7 +257,7 @@ scheduler::~scheduler() {
delete m_helper; delete m_helper;
} }
const actor_ptr& scheduler::delayed_send_helper() { actor& scheduler::delayed_send_helper() {
return m_helper->m_timer; return m_helper->m_timer;
} }
...@@ -291,7 +287,7 @@ scheduler* scheduler::create_singleton() { ...@@ -291,7 +287,7 @@ scheduler* scheduler::create_singleton() {
return new detail::thread_pool_scheduler; return new detail::thread_pool_scheduler;
} }
const actor_ptr& scheduler::printer() const { const actor& scheduler::printer() const {
return m_helper->m_printer; return m_helper->m_printer;
} }
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
\******************************************************************************/ \******************************************************************************/
#include "cppa/send.hpp"
#include "cppa/scheduler.hpp" #include "cppa/scheduler.hpp"
#include "cppa/singletons.hpp" #include "cppa/singletons.hpp"
......
...@@ -75,13 +75,6 @@ std::atomic<logging*> s_logger; ...@@ -75,13 +75,6 @@ std::atomic<logging*> s_logger;
} // namespace <anonymous> } // namespace <anonymous>
void singleton_manager::shutdown() { void singleton_manager::shutdown() {
CPPA_LOGF(CPPA_DEBUG, nullptr, "prepare to shutdown");
if (self.unchecked() != nullptr) {
try { self.unchecked()->quit(exit_reason::normal); }
catch (actor_exited&) { }
}
//auto rptr = s_actor_registry.load();
//if (rptr) rptr->await_running_count_equal(0);
CPPA_LOGF(CPPA_DEBUG, nullptr, "shutdown scheduler"); CPPA_LOGF(CPPA_DEBUG, nullptr, "shutdown scheduler");
destroy(s_scheduler); destroy(s_scheduler);
CPPA_LOGF(CPPA_DEBUG, nullptr, "shutdown middleman"); CPPA_LOGF(CPPA_DEBUG, nullptr, "shutdown middleman");
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011-2013 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation; either version 2.1 of the License, *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#include "cppa/atom.hpp"
#include "cppa/config.hpp"
#include "cppa/message_id.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/detail/sync_request_bouncer.hpp"
namespace cppa { namespace detail {
sync_request_bouncer::sync_request_bouncer(std::uint32_t r)
: rsn(r == exit_reason::not_exited ? exit_reason::normal : r) { }
void sync_request_bouncer::operator()(const actor_addr& sender, const message_id& mid) const {
CPPA_REQUIRE(rsn != exit_reason::not_exited);
if (sender && mid.is_request()) {
auto ptr = detail::actor_addr_cast<abstract_actor>(sender);
ptr->enqueue({nullptr, ptr, mid.response_id(),
make_any_tuple(atom("EXITED"), rsn));
}
}
void sync_request_bouncer::operator()(const mailbox_element& e) const {
(*this)(e.sender, e.mid);
}
} } // namespace cppa::detail
...@@ -33,7 +33,6 @@ ...@@ -33,7 +33,6 @@
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include "cppa/self.hpp"
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/exception.hpp" #include "cppa/exception.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
......
...@@ -37,8 +37,10 @@ ...@@ -37,8 +37,10 @@
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/prioritizing.hpp" #include "cppa/prioritizing.hpp"
#include "cppa/untyped_actor.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
#include "cppa/thread_mapped_actor.hpp" #include "cppa/thread_mapped_actor.hpp"
#include "cppa/blocking_untyped_actor.hpp"
#include "cppa/context_switching_actor.hpp" #include "cppa/context_switching_actor.hpp"
#include "cppa/detail/actor_registry.hpp" #include "cppa/detail/actor_registry.hpp"
...@@ -97,7 +99,6 @@ struct thread_pool_scheduler::worker { ...@@ -97,7 +99,6 @@ struct thread_pool_scheduler::worker {
CPPA_LOG_TRACE(""); CPPA_LOG_TRACE("");
util::fiber fself; util::fiber fself;
job_ptr job = nullptr; job_ptr job = nullptr;
actor_ptr next;
for (;;) { for (;;) {
aggressive(job) || moderate(job) || relaxed(job); aggressive(job) || moderate(job) || relaxed(job);
CPPA_LOGMF(CPPA_DEBUG, self, "dequeued new job"); CPPA_LOGMF(CPPA_DEBUG, self, "dequeued new job");
...@@ -107,23 +108,14 @@ struct thread_pool_scheduler::worker { ...@@ -107,23 +108,14 @@ struct thread_pool_scheduler::worker {
m_job_queue->push_back(job); // kill the next guy m_job_queue->push_back(job); // kill the next guy
return; // and say goodbye return; // and say goodbye
} }
do { CPPA_LOG_DEBUG("resume actor with ID " << job->id());
CPPA_LOGMF(CPPA_DEBUG, self, "resume actor with ID " << job->id()); if (job->resume(&fself) == resume_result::actor_done) {
CPPA_REQUIRE(next == nullptr); CPPA_LOGMF(CPPA_DEBUG, self, "actor is done");
if (job->resume(&fself, next) == resume_result::actor_done) { bool hidden = job->is_hidden();
CPPA_LOGMF(CPPA_DEBUG, self, "actor is done"); job->deref();
bool hidden = job->is_hidden(); if (!hidden) get_actor_registry()->dec_running();
job->deref();
if (!hidden) get_actor_registry()->dec_running();
}
if (next) {
CPPA_LOGMF(CPPA_DEBUG, self, "got new job trough chaining");
job = static_cast<job_ptr>(next.get());
next.reset();
}
else job = nullptr;
} }
while (job); // loops until next == nullptr job = nullptr;
} }
} }
...@@ -186,12 +178,10 @@ void thread_pool_scheduler::enqueue(scheduled_actor* what) { ...@@ -186,12 +178,10 @@ void thread_pool_scheduler::enqueue(scheduled_actor* what) {
m_queue.push_back(what); m_queue.push_back(what);
} }
template<typename F> void exec_as_thread(bool is_hidden, intrusive_ptr<untyped_actor> ptr) {
void exec_as_thread(bool is_hidden, local_actor_ptr p, F f) {
if (!is_hidden) get_actor_registry()->inc_running(); if (!is_hidden) get_actor_registry()->inc_running();
std::thread([=] { std::thread([=] {
scoped_self_setter sss(p.get()); try { ptr->exec_bhvr_stack(); }
try { f(); }
catch (...) { } catch (...) { }
if (!is_hidden) { if (!is_hidden) {
std::atomic_thread_fence(std::memory_order_seq_cst); std::atomic_thread_fence(std::memory_order_seq_cst);
...@@ -204,7 +194,7 @@ local_actor_ptr thread_pool_scheduler::exec(spawn_options os, scheduled_actor_pt ...@@ -204,7 +194,7 @@ local_actor_ptr thread_pool_scheduler::exec(spawn_options os, scheduled_actor_pt
CPPA_REQUIRE(p != nullptr); CPPA_REQUIRE(p != nullptr);
bool is_hidden = has_hide_flag(os); bool is_hidden = has_hide_flag(os);
if (has_detach_flag(os)) { if (has_detach_flag(os)) {
exec_as_thread(is_hidden, p, [p] { exec_as_thread(is_hidden, [p] {
p->run_detached(); p->run_detached();
}); });
return p; return p;
...@@ -221,7 +211,7 @@ local_actor_ptr thread_pool_scheduler::exec(spawn_options os, scheduled_actor_pt ...@@ -221,7 +211,7 @@ local_actor_ptr thread_pool_scheduler::exec(spawn_options os, scheduled_actor_pt
local_actor_ptr thread_pool_scheduler::exec(spawn_options os, local_actor_ptr thread_pool_scheduler::exec(spawn_options os,
init_callback cb, init_callback cb,
void_function f) { actor_fun f) {
local_actor_ptr result; local_actor_ptr result;
auto set_result = [&](local_actor_ptr value) { auto set_result = [&](local_actor_ptr value) {
CPPA_REQUIRE(result == nullptr && value != nullptr); CPPA_REQUIRE(result == nullptr && value != nullptr);
...@@ -229,12 +219,11 @@ local_actor_ptr thread_pool_scheduler::exec(spawn_options os, ...@@ -229,12 +219,11 @@ local_actor_ptr thread_pool_scheduler::exec(spawn_options os,
if (cb) cb(result.get()); if (cb) cb(result.get());
}; };
if (has_priority_aware_flag(os)) { if (has_priority_aware_flag(os)) {
using impl = extend<thread_mapped_actor>::with<prioritizing>; using impl = extend<local_actor>::with<stackless, threaded, prioritizing>;
set_result(make_counted<impl>()); set_result(make_counted<impl>());
exec_as_thread(has_hide_flag(os), result, [result, f] { exec_as_thread(has_hide_flag(os), [result, f] {
try { try {
f(); f();
result->exec_behavior_stack();
} }
catch (actor_exited& e) { } catch (actor_exited& e) { }
catch (std::exception& e) { catch (std::exception& e) {
...@@ -262,7 +251,7 @@ local_actor_ptr thread_pool_scheduler::exec(spawn_options os, ...@@ -262,7 +251,7 @@ local_actor_ptr thread_pool_scheduler::exec(spawn_options os,
/* else tree */ { /* else tree */ {
auto p = make_counted<thread_mapped_actor>(std::move(f)); auto p = make_counted<thread_mapped_actor>(std::move(f));
set_result(p); set_result(p);
exec_as_thread(has_hide_flag(os), p, [p] { exec_as_thread(has_hide_flag(os), [p] {
p->run(); p->run();
p->on_exit(); p->on_exit();
}); });
......
...@@ -63,22 +63,22 @@ namespace cppa { ...@@ -63,22 +63,22 @@ namespace cppa {
using namespace detail; using namespace detail;
using namespace io; using namespace io;
void publish(actor_ptr whom, std::unique_ptr<acceptor> aptr) { void publish(actor whom, std::unique_ptr<acceptor> aptr) {
CPPA_LOG_TRACE(CPPA_TARG(whom, to_string) << ", " << CPPA_MARG(ptr, get) CPPA_LOG_TRACE(CPPA_TARG(whom, to_string) << ", " << CPPA_MARG(ptr, get)
<< ", args.size() = " << args.size()); << ", args.size() = " << args.size());
if (!whom) return; if (!whom) return;
CPPA_REQUIRE(args.size() == 0); CPPA_REQUIRE(args.size() == 0);
get_actor_registry()->put(whom->id(), whom); get_actor_registry()->put(whom.id(), detail::actor_addr_cast<abstract_actor>(whom));
auto mm = get_middleman(); auto mm = get_middleman();
mm->register_acceptor(whom, new peer_acceptor(mm, move(aptr), whom)); mm->register_acceptor(whom, new peer_acceptor(mm, move(aptr), whom));
} }
void publish(actor_ptr whom, std::uint16_t port, const char* addr) { void publish(actor whom, std::uint16_t port, const char* addr) {
if (!whom) return; if (!whom) return;
publish(whom, ipv4_acceptor::create(port, addr)); publish(whom, ipv4_acceptor::create(port, addr));
} }
actor_ptr remote_actor(stream_ptr_pair io) { actor remote_actor(stream_ptr_pair io) {
CPPA_LOG_TRACE("io{" << io.first.get() << ", " << io.second.get() << "}"); CPPA_LOG_TRACE("io{" << io.first.get() << ", " << io.second.get() << "}");
auto pinf = node_id::get(); auto pinf = node_id::get();
std::uint32_t process_id = pinf->process_id(); std::uint32_t process_id = pinf->process_id();
...@@ -98,7 +98,7 @@ actor_ptr remote_actor(stream_ptr_pair io) { ...@@ -98,7 +98,7 @@ actor_ptr remote_actor(stream_ptr_pair io) {
return get_actor_registry()->get(remote_aid); return get_actor_registry()->get(remote_aid);
} }
auto mm = get_middleman(); auto mm = get_middleman();
struct remote_actor_result { remote_actor_result* next; actor_ptr value; }; struct remote_actor_result { remote_actor_result* next; actor value; };
intrusive::blocking_single_reader_queue<remote_actor_result> q; intrusive::blocking_single_reader_queue<remote_actor_result> q;
mm->run_later([mm, io, pinfptr, remote_aid, &q] { mm->run_later([mm, io, pinfptr, remote_aid, &q] {
CPPA_LOGC_TRACE("cppa", CPPA_LOGC_TRACE("cppa",
...@@ -114,7 +114,7 @@ actor_ptr remote_actor(stream_ptr_pair io) { ...@@ -114,7 +114,7 @@ actor_ptr remote_actor(stream_ptr_pair io) {
return result->value; return result->value;
} }
actor_ptr remote_actor(const char* host, std::uint16_t port) { actor remote_actor(const char* host, std::uint16_t port) {
auto io = ipv4_io_stream::connect_to(host, port); auto io = ipv4_io_stream::connect_to(host, port);
return remote_actor(stream_ptr_pair(io, io)); return remote_actor(stream_ptr_pair(io, io));
} }
......
...@@ -57,23 +57,24 @@ namespace cppa { namespace detail { ...@@ -57,23 +57,24 @@ namespace cppa { namespace detail {
// maps demangled names to libcppa names // maps demangled names to libcppa names
// WARNING: this map is sorted, insert new elements *in sorted order* as well! // WARNING: this map is sorted, insert new elements *in sorted order* as well!
/* extern */ const char* mapped_type_names[][2] = { /* extern */ const char* mapped_type_names[][2] = {
{ "bool", "bool" }, { "cppa::actor", "@actor" },
{ "cppa::any_tuple", "@tuple" }, { "cppa::actor_addr", "@addr" },
{ "cppa::atom_value", "@atom" }, { "bool", "bool" },
{ "cppa::intrusive_ptr<cppa::actor>", "@actor" }, { "cppa::any_tuple", "@tuple" },
{ "cppa::intrusive_ptr<cppa::channel>", "@channel" }, { "cppa::atom_value", "@atom" },
{ "cppa::intrusive_ptr<cppa::group>", "@group" }, { "cppa::intrusive_ptr<cppa::channel>", "@channel" },
{ "cppa::intrusive_ptr<cppa::node_id>", "@proc"}, { "cppa::intrusive_ptr<cppa::group>", "@group" },
{ "cppa::io::accept_handle", "@ac_hdl" }, { "cppa::intrusive_ptr<cppa::node_id>", "@proc" },
{ "cppa::io::connection_handle", "@cn_hdl" }, { "cppa::io::accept_handle", "@ac_hdl" },
{ "cppa::message_header", "@header" }, { "cppa::io::connection_handle", "@cn_hdl" },
{ "cppa::nullptr_t", "@null" }, { "cppa::message_header", "@header" },
{ "cppa::unit_t", "@0" }, { "cppa::nullptr_t", "@null" },
{ "cppa::util::buffer", "@buffer" }, { "cppa::unit_t", "@0" },
{ "cppa::util::buffer", "@buffer" },
{ "cppa::util::duration", "@duration" }, { "cppa::util::duration", "@duration" },
{ "double", "double" }, { "double", "double" },
{ "float", "float" }, { "float", "float" },
{ "long double", "@ldouble" }, { "long double", "@ldouble" },
// std::u16string // std::u16string
{ "std::basic_string<@i16,std::char_traits<@i16>,std::allocator<@i16>>", { "std::basic_string<@i16,std::char_traits<@i16>,std::allocator<@i16>>",
"@u16str" }, "@u16str" },
...@@ -163,20 +164,30 @@ inline void serialize_impl(const unit_t&, serializer*) { } ...@@ -163,20 +164,30 @@ inline void serialize_impl(const unit_t&, serializer*) { }
inline void deserialize_impl(unit_t&, deserializer*) { } inline void deserialize_impl(unit_t&, deserializer*) { }
void serialize_impl(const actor_ptr& ptr, serializer* sink) { void serialize_impl(const actor_addr& addr, serializer* sink) {
auto ns = sink->get_namespace(); auto ns = sink->get_namespace();
if (ns) ns->write(sink, ptr); if (ns) ns->write(sink, addr);
else throw std::runtime_error("unable to serialize actor_ptr: " else throw std::runtime_error("unable to serialize actor_ptr: "
"no actor addressing defined"); "no actor addressing defined");
} }
void deserialize_impl(actor_ptr& ptrref, deserializer* source) { void deserialize_impl(actor_addr& addr, deserializer* source) {
auto ns = source->get_namespace(); auto ns = source->get_namespace();
if (ns) ptrref = ns->read(source); if (ns) addr = ns->read(source);
else throw std::runtime_error("unable to deserialize actor_ptr: " else throw std::runtime_error("unable to deserialize actor_ptr: "
"no actor addressing defined"); "no actor addressing defined");
} }
void serialize_impl(const actor& ptr, serializer* sink) {
serialize_impl(ptr.address(), sink);
}
void deserialize_impl(actor& ptr, deserializer* source) {
actor_addr addr;
deserialize_impl(addr, source);
ptr = detail::actor_addr_cast<abstract_actor>(addr);
}
void serialize_impl(const group_ptr& ptr, serializer* sink) { void serialize_impl(const group_ptr& ptr, serializer* sink) {
if (ptr == nullptr) { if (ptr == nullptr) {
// write an empty string as module name // write an empty string as module name
...@@ -195,7 +206,7 @@ void deserialize_impl(group_ptr& ptrref, deserializer* source) { ...@@ -195,7 +206,7 @@ void deserialize_impl(group_ptr& ptrref, deserializer* source) {
else ptrref = group::get_module(modname)->deserialize(source); else ptrref = group::get_module(modname)->deserialize(source);
} }
void serialize_impl(const channel_ptr& ptr, serializer* sink) { void serialize_impl(const channel& ptr, serializer* sink) {
// channel is an abstract base class that's either an actor or a group // channel is an abstract base class that's either an actor or a group
// to indicate that, we write a flag first, that is // to indicate that, we write a flag first, that is
// 0 if ptr == nullptr // 0 if ptr == nullptr
...@@ -207,11 +218,11 @@ void serialize_impl(const channel_ptr& ptr, serializer* sink) { ...@@ -207,11 +218,11 @@ void serialize_impl(const channel_ptr& ptr, serializer* sink) {
}; };
if (ptr == nullptr) wr_nullptr(); if (ptr == nullptr) wr_nullptr();
else { else {
auto aptr = ptr.downcast<actor>(); auto aptr = ptr.downcast<abstract_actor>();
if (aptr != nullptr) { if (aptr != nullptr) {
flag = 1; flag = 1;
sink->write_value(flag); sink->write_value(flag);
serialize_impl(aptr, sink); serialize_impl(actor{aptr}, sink);
} }
else { else {
auto gptr = ptr.downcast<group>(); auto gptr = ptr.downcast<group>();
...@@ -228,7 +239,7 @@ void serialize_impl(const channel_ptr& ptr, serializer* sink) { ...@@ -228,7 +239,7 @@ void serialize_impl(const channel_ptr& ptr, serializer* sink) {
} }
} }
void deserialize_impl(channel_ptr& ptrref, deserializer* source) { void deserialize_impl(channel& ptrref, deserializer* source) {
auto flag = source->read<uint8_t>(); auto flag = source->read<uint8_t>();
switch (flag) { switch (flag) {
case 0: { case 0: {
...@@ -236,9 +247,9 @@ void deserialize_impl(channel_ptr& ptrref, deserializer* source) { ...@@ -236,9 +247,9 @@ void deserialize_impl(channel_ptr& ptrref, deserializer* source) {
break; break;
} }
case 1: { case 1: {
actor_ptr tmp; actor tmp;
deserialize_impl(tmp, source); deserialize_impl(tmp, source);
ptrref = tmp; ptrref = detail::actor_addr_cast<abstract_actor>(tmp);
break; break;
} }
case 2: { case 2: {
...@@ -248,7 +259,7 @@ void deserialize_impl(channel_ptr& ptrref, deserializer* source) { ...@@ -248,7 +259,7 @@ void deserialize_impl(channel_ptr& ptrref, deserializer* source) {
break; break;
} }
default: { default: {
CPPA_LOGF_ERROR("invalid flag while deserializing 'channel_ptr'"); CPPA_LOGF_ERROR("invalid flag while deserializing 'channel'");
throw std::runtime_error("invalid flag"); throw std::runtime_error("invalid flag");
} }
} }
...@@ -416,7 +427,7 @@ class uti_impl : public uti_base<T> { ...@@ -416,7 +427,7 @@ class uti_impl : public uti_base<T> {
protected: protected:
void serialize(const void *instance, serializer *sink) const { void serialize(const void* instance, serializer* sink) const {
serialize_impl(super::deref(instance), sink); serialize_impl(super::deref(instance), sink);
} }
...@@ -701,6 +712,7 @@ class utim_impl : public uniform_type_info_map { ...@@ -701,6 +712,7 @@ class utim_impl : public uniform_type_info_map {
m_builtin_types[i++] = &m_type_unit; // @0 m_builtin_types[i++] = &m_type_unit; // @0
m_builtin_types[i++] = &m_ac_hdl; // @ac_hdl m_builtin_types[i++] = &m_ac_hdl; // @ac_hdl
m_builtin_types[i++] = &m_type_actor; // @actor m_builtin_types[i++] = &m_type_actor; // @actor
m_builtin_types[i++] = &m_type_actor_addr; // @actor_addr
m_builtin_types[i++] = &m_type_atom; // @atom m_builtin_types[i++] = &m_type_atom; // @atom
m_builtin_types[i++] = &m_type_buffer; // @buffer m_builtin_types[i++] = &m_type_buffer; // @buffer
m_builtin_types[i++] = &m_type_channel; // @channel m_builtin_types[i++] = &m_type_channel; // @channel
...@@ -754,7 +766,7 @@ class utim_impl : public uniform_type_info_map { ...@@ -754,7 +766,7 @@ class utim_impl : public uniform_type_info_map {
push_hint<atom_value>(this); push_hint<atom_value>(this);
push_hint<atom_value, std::uint32_t>(this); push_hint<atom_value, std::uint32_t>(this);
push_hint<atom_value, node_id_ptr>(this); push_hint<atom_value, node_id_ptr>(this);
push_hint<atom_value, actor_ptr>(this); push_hint<atom_value, actor>(this);
push_hint<atom_value, node_id_ptr, std::uint32_t, std::uint32_t>(this); push_hint<atom_value, node_id_ptr, std::uint32_t, std::uint32_t>(this);
push_hint<atom_value, std::uint32_t, std::string>(this); push_hint<atom_value, std::uint32_t, std::string>(this);
} }
...@@ -819,12 +831,13 @@ class utim_impl : public uniform_type_info_map { ...@@ -819,12 +831,13 @@ class utim_impl : public uniform_type_info_map {
typedef std::map<std::string, std::string> strmap; typedef std::map<std::string, std::string> strmap;
uti_impl<node_id_ptr> m_type_proc; uti_impl<node_id_ptr> m_type_proc;
uti_impl<io::accept_handle> m_ac_hdl; uti_impl<io::accept_handle> m_ac_hdl;
uti_impl<io::connection_handle> m_cn_hdl; uti_impl<io::connection_handle> m_cn_hdl;
uti_impl<channel_ptr> m_type_channel; uti_impl<channel> m_type_channel;
buffer_type_info_impl m_type_buffer; buffer_type_info_impl m_type_buffer;
uti_impl<actor_ptr> m_type_actor; uti_impl<actor> m_type_actor;
uti_impl<actor_addr> m_type_actor_addr;
uti_impl<group_ptr> m_type_group; uti_impl<group_ptr> m_type_group;
uti_impl<any_tuple> m_type_tuple; uti_impl<any_tuple> m_type_tuple;
uti_impl<util::duration> m_type_duration; uti_impl<util::duration> m_type_duration;
...@@ -849,7 +862,7 @@ class utim_impl : public uniform_type_info_map { ...@@ -849,7 +862,7 @@ class utim_impl : public uniform_type_info_map {
int_tinfo<std::uint64_t> m_type_u64; int_tinfo<std::uint64_t> m_type_u64;
// both containers are sorted by uniform name // both containers are sorted by uniform name
std::array<pointer, 28> m_builtin_types; std::array<pointer, 29> m_builtin_types;
std::vector<uniform_type_info*> m_user_types; std::vector<uniform_type_info*> m_user_types;
mutable util::shared_spinlock m_lock; mutable util::shared_spinlock m_lock;
......
...@@ -169,7 +169,7 @@ int main(int argc, char** argv) { ...@@ -169,7 +169,7 @@ int main(int argc, char** argv) {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
child.join(); child.join();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
shutdown(); shutdown();
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
......
...@@ -50,7 +50,7 @@ int main() { ...@@ -50,7 +50,7 @@ int main() {
}); });
} }
send(foo_group, 2); send(foo_group, 2);
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
...@@ -387,7 +387,7 @@ int main(int argc, char** argv) { ...@@ -387,7 +387,7 @@ int main(int argc, char** argv) {
} }
); );
// wait until separate process (in sep. thread) finished execution // wait until separate process (in sep. thread) finished execution
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
if (run_remote_actor) child.join(); if (run_remote_actor) child.join();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
......
...@@ -203,7 +203,7 @@ string behavior_test(actor_ptr et) { ...@@ -203,7 +203,7 @@ string behavior_test(actor_ptr et) {
} }
); );
send_exit(et, exit_reason::user_shutdown); send_exit(et, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
return result; return result;
} }
...@@ -386,7 +386,7 @@ void test_serial_reply() { ...@@ -386,7 +386,7 @@ void test_serial_reply() {
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
send_exit(master, exit_reason::user_shutdown); send_exit(master, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
} }
...@@ -411,7 +411,7 @@ void test_or_else() { ...@@ -411,7 +411,7 @@ void test_or_else() {
CPPA_CHECK_EQUAL(i, 3); CPPA_CHECK_EQUAL(i, 3);
}); });
send_exit(testee, exit_reason::user_shutdown); send_exit(testee, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
}); });
run_testee( run_testee(
spawn([=] { spawn([=] {
...@@ -461,7 +461,7 @@ void test_continuation() { ...@@ -461,7 +461,7 @@ void test_continuation() {
} }
); );
}); });
await_all_others_done(); await_all_actors_done();
} }
int main() { int main() {
...@@ -476,7 +476,7 @@ int main() { ...@@ -476,7 +476,7 @@ int main() {
spawn<slave>(m); spawn<slave>(m);
spawn<slave>(m); spawn<slave>(m);
send(m, atom("done")); send(m, atom("done"));
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_PRINT("test send()"); CPPA_PRINT("test send()");
...@@ -508,7 +508,7 @@ int main() { ...@@ -508,7 +508,7 @@ int main() {
on(atom("DOWN"), exit_reason::user_shutdown) >> CPPA_CHECKPOINT_CB(), on(atom("DOWN"), exit_reason::user_shutdown) >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
} }
...@@ -524,7 +524,7 @@ int main() { ...@@ -524,7 +524,7 @@ int main() {
on(atom("DOWN"), exit_reason::user_shutdown) >> CPPA_CHECKPOINT_CB(), on(atom("DOWN"), exit_reason::user_shutdown) >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
} }
...@@ -541,7 +541,7 @@ int main() { ...@@ -541,7 +541,7 @@ int main() {
on(atom("DOWN"), exit_reason::user_shutdown) >> CPPA_CHECKPOINT_CB(), on(atom("DOWN"), exit_reason::user_shutdown) >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
} }
...@@ -552,7 +552,7 @@ int main() { ...@@ -552,7 +552,7 @@ int main() {
on("hello echo") >> [] { }, on("hello echo") >> [] { },
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_PRINT("test delayed_send()"); CPPA_PRINT("test delayed_send()");
...@@ -565,11 +565,11 @@ int main() { ...@@ -565,11 +565,11 @@ int main() {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
spawn(testee1); spawn(testee1);
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
spawn_event_testee2(); spawn_event_testee2();
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto cstk = spawn<chopstick>(); auto cstk = spawn<chopstick>();
...@@ -580,7 +580,7 @@ int main() { ...@@ -580,7 +580,7 @@ int main() {
send(cstk, atom("break")); send(cstk, atom("break"));
} }
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto factory = factory::event_based([&](int* i, float*, string*) { auto factory = factory::event_based([&](int* i, float*, string*) {
...@@ -611,7 +611,7 @@ int main() { ...@@ -611,7 +611,7 @@ int main() {
CPPA_CHECK_EQUAL(value, 42); CPPA_CHECK_EQUAL(value, 42);
} }
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto st = spawn<fixed_stack>(10); auto st = spawn<fixed_stack>(10);
...@@ -641,7 +641,7 @@ int main() { ...@@ -641,7 +641,7 @@ int main() {
} }
// terminate st // terminate st
send_exit(st, exit_reason::user_shutdown); send_exit(st, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto sync_testee1 = spawn<blocking_api>([] { auto sync_testee1 = spawn<blocking_api>([] {
...@@ -679,7 +679,7 @@ int main() { ...@@ -679,7 +679,7 @@ int main() {
others() >> CPPA_UNEXPECTED_MSG_CB(), others() >> CPPA_UNEXPECTED_MSG_CB(),
after(chrono::seconds(0)) >> [] { } after(chrono::seconds(0)) >> [] { }
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_PRINT("test sync send with factory spawned actor"); CPPA_PRINT("test sync send with factory spawned actor");
...@@ -727,7 +727,7 @@ int main() { ...@@ -727,7 +727,7 @@ int main() {
CPPA_CHECK_EQUAL(self->last_sender(), sync_testee); CPPA_CHECK_EQUAL(self->last_sender(), sync_testee);
} }
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
sync_send(sync_testee, "!?").await( sync_send(sync_testee, "!?").await(
...@@ -759,7 +759,7 @@ int main() { ...@@ -759,7 +759,7 @@ int main() {
auto poison_pill = make_any_tuple(atom("done")); auto poison_pill = make_any_tuple(atom("done"));
joe << poison_pill; joe << poison_pill;
bob << poison_pill; bob << poison_pill;
await_all_others_done(); await_all_actors_done();
function<actor_ptr (const string&, const actor_ptr&)> spawn_next; function<actor_ptr (const string&, const actor_ptr&)> spawn_next;
auto kr34t0r = factory::event_based( auto kr34t0r = factory::event_based(
...@@ -786,7 +786,7 @@ int main() { ...@@ -786,7 +786,7 @@ int main() {
}; };
auto joe_the_second = kr34t0r.spawn("Joe"); auto joe_the_second = kr34t0r.spawn("Joe");
send(joe_the_second, atom("done")); send(joe_the_second, atom("done"));
await_all_others_done(); await_all_actors_done();
int zombie_init_called = 0; int zombie_init_called = 0;
int zombie_on_exit_called = 0; int zombie_on_exit_called = 0;
...@@ -839,7 +839,7 @@ int main() { ...@@ -839,7 +839,7 @@ int main() {
); );
send_exit(a1, exit_reason::user_shutdown); send_exit(a1, exit_reason::user_shutdown);
send_exit(a2, exit_reason::user_shutdown); send_exit(a2, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
factory::event_based([](int* i) { factory::event_based([](int* i) {
become( become(
...@@ -849,7 +849,7 @@ int main() { ...@@ -849,7 +849,7 @@ int main() {
); );
}).spawn(); }).spawn();
await_all_others_done(); await_all_actors_done();
auto res1 = behavior_test<testee_actor>(spawn<blocking_api>(testee_actor{})); auto res1 = behavior_test<testee_actor>(spawn<blocking_api>(testee_actor{}));
CPPA_CHECK_EQUAL("wait4int", res1); CPPA_CHECK_EQUAL("wait4int", res1);
...@@ -865,7 +865,7 @@ int main() { ...@@ -865,7 +865,7 @@ int main() {
become(others() >> CPPA_UNEXPECTED_MSG_CB()); become(others() >> CPPA_UNEXPECTED_MSG_CB());
}); });
send_exit(legion, exit_reason::user_shutdown); send_exit(legion, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
self->trap_exit(true); self->trap_exit(true);
auto ping_actor = spawn<monitored+blocking_api>(ping, 10); auto ping_actor = spawn<monitored+blocking_api>(ping, 10);
...@@ -904,16 +904,16 @@ int main() { ...@@ -904,16 +904,16 @@ int main() {
} }
); );
// wait for termination of all spawned actors // wait for termination of all spawned actors
await_all_others_done(); await_all_actors_done();
CPPA_CHECK_EQUAL(flags, 0x0F); CPPA_CHECK_EQUAL(flags, 0x0F);
// verify pong messages // verify pong messages
CPPA_CHECK_EQUAL(pongs(), 10); CPPA_CHECK_EQUAL(pongs(), 10);
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
spawn<priority_aware>(high_priority_testee); spawn<priority_aware>(high_priority_testee);
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
spawn<high_priority_testee_class, priority_aware>(); spawn<high_priority_testee_class, priority_aware>();
await_all_others_done(); await_all_actors_done();
// don't try this at home, kids // don't try this at home, kids
send(self, atom("check")); send(self, atom("check"));
try { try {
......
...@@ -216,7 +216,7 @@ int main() { ...@@ -216,7 +216,7 @@ int main() {
self->exec_behavior_stack(); self->exec_behavior_stack();
CPPA_CHECK_EQUAL(continuation_called, true); CPPA_CHECK_EQUAL(continuation_called, true);
send_exit(mirror, exit_reason::user_shutdown); send_exit(mirror, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto await_success_message = [&] { auto await_success_message = [&] {
receive ( receive (
...@@ -231,11 +231,11 @@ int main() { ...@@ -231,11 +231,11 @@ int main() {
send(spawn<A, monitored>(self), atom("go"), spawn<B>(spawn<C>())); send(spawn<A, monitored>(self), atom("go"), spawn<B>(spawn<C>()));
await_success_message(); await_success_message();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
await_all_others_done(); await_all_actors_done();
send(spawn<A, monitored>(self), atom("go"), spawn<D>(spawn<C>())); send(spawn<A, monitored>(self), atom("go"), spawn<D>(spawn<C>()));
await_success_message(); await_success_message();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
timed_sync_send(self, std::chrono::milliseconds(50), atom("NoWay")).await( timed_sync_send(self, std::chrono::milliseconds(50), atom("NoWay")).await(
on(atom("TIMEOUT")) >> CPPA_CHECKPOINT_CB(), on(atom("TIMEOUT")) >> CPPA_CHECKPOINT_CB(),
...@@ -276,7 +276,7 @@ int main() { ...@@ -276,7 +276,7 @@ int main() {
.continue_with(CPPA_CHECKPOINT_CB()); .continue_with(CPPA_CHECKPOINT_CB());
self->exec_behavior_stack(); self->exec_behavior_stack();
send_exit(c, exit_reason::user_shutdown); send_exit(c, exit_reason::user_shutdown);
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
// test use case 3 // test use case 3
...@@ -312,7 +312,7 @@ int main() { ...@@ -312,7 +312,7 @@ int main() {
on(atom("DOWN"), exit_reason::user_shutdown) >> CPPA_CHECKPOINT_CB(), on(atom("DOWN"), exit_reason::user_shutdown) >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
shutdown(); shutdown();
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
......
...@@ -463,7 +463,7 @@ int main() { ...@@ -463,7 +463,7 @@ int main() {
check_wildcards(); check_wildcards();
check_move_ops(); check_move_ops();
check_drop(); check_drop();
await_all_others_done(); await_all_actors_done();
shutdown(); shutdown();
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
...@@ -173,7 +173,7 @@ int main() { ...@@ -173,7 +173,7 @@ int main() {
} }
); );
}); });
await_all_others_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
shutdown(); shutdown();
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
......
...@@ -88,7 +88,7 @@ int main() { ...@@ -88,7 +88,7 @@ int main() {
"@header", // message_header "@header", // message_header
"@actor", // actor_ptr "@actor", // actor_ptr
"@group", // group_ptr "@group", // group_ptr
"@channel", // channel_ptr "@channel", // channel
"@proc", // intrusive_ptr<node_id> "@proc", // intrusive_ptr<node_id>
"@duration", // util::duration "@duration", // util::duration
"@buffer", // util::buffer "@buffer", // util::buffer
...@@ -135,7 +135,7 @@ int main() { ...@@ -135,7 +135,7 @@ int main() {
float, double, float, double,
atom_value, any_tuple, message_header, atom_value, any_tuple, message_header,
actor_ptr, group_ptr, actor_ptr, group_ptr,
channel_ptr, node_id_ptr channel, node_id_ptr
>::arr; >::arr;
CPPA_CHECK(sarr.is_pure()); CPPA_CHECK(sarr.is_pure());
...@@ -159,7 +159,7 @@ int main() { ...@@ -159,7 +159,7 @@ int main() {
uniform_typeid<message_header>(), uniform_typeid<message_header>(),
uniform_typeid<actor_ptr>(), uniform_typeid<actor_ptr>(),
uniform_typeid<group_ptr>(), uniform_typeid<group_ptr>(),
uniform_typeid<channel_ptr>(), uniform_typeid<channel>(),
uniform_typeid<node_id_ptr>() uniform_typeid<node_id_ptr>()
}; };
......
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