Commit c91bf3fc authored by Dominik Charousset's avatar Dominik Charousset

API refactoring

parent 3eee072f
...@@ -138,6 +138,7 @@ set(LIBCPPA_SRC ...@@ -138,6 +138,7 @@ set(LIBCPPA_SRC
src/binary_serializer.cpp src/binary_serializer.cpp
src/broker.cpp src/broker.cpp
src/buffer.cpp src/buffer.cpp
src/blocking_untyped_actor.cpp
src/channel.cpp src/channel.cpp
src/common_actor_ops.cpp src/common_actor_ops.cpp
src/context_switching_resume.cpp src/context_switching_resume.cpp
...@@ -150,11 +151,12 @@ set(LIBCPPA_SRC ...@@ -150,11 +151,12 @@ set(LIBCPPA_SRC
src/deserializer.cpp src/deserializer.cpp
src/duration.cpp src/duration.cpp
src/empty_tuple.cpp src/empty_tuple.cpp
src/event_based_resume.cpp
src/exception.cpp src/exception.cpp
src/exit_reason.cpp src/exit_reason.cpp
src/fd_util.cpp src/fd_util.cpp
src/fiber.cpp src/fiber.cpp
src/functor_based_actor.cpp
src/functor_based_blocking_actor.cpp
src/get_root_uuid.cpp src/get_root_uuid.cpp
src/get_mac_addresses.cpp src/get_mac_addresses.cpp
src/group.cpp src/group.cpp
...@@ -178,11 +180,10 @@ set(LIBCPPA_SRC ...@@ -178,11 +180,10 @@ set(LIBCPPA_SRC
src/partial_function.cpp src/partial_function.cpp
src/primitive_variant.cpp src/primitive_variant.cpp
src/ref_counted.cpp src/ref_counted.cpp
src/resumable.cpp
src/remote_actor_proxy.cpp src/remote_actor_proxy.cpp
src/response_handle.cpp src/response_handle.cpp
src/ripemd_160.cpp src/ripemd_160.cpp
src/scheduled_actor.cpp
src/scheduled_actor_dummy.cpp
src/scheduler.cpp src/scheduler.cpp
src/scoped_actor.cpp src/scoped_actor.cpp
src/serializer.cpp src/serializer.cpp
...@@ -190,13 +191,13 @@ set(LIBCPPA_SRC ...@@ -190,13 +191,13 @@ set(LIBCPPA_SRC
src/singleton_manager.cpp src/singleton_manager.cpp
src/string_serialization.cpp src/string_serialization.cpp
src/sync_request_bouncer.cpp src/sync_request_bouncer.cpp
src/thread_mapped_actor.cpp
src/thread_pool_scheduler.cpp src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp src/to_uniform_name.cpp
src/type_lookup_table.cpp src/type_lookup_table.cpp
src/unicast_network.cpp src/unicast_network.cpp
src/uniform_type_info.cpp src/uniform_type_info.cpp
src/uniform_type_info_map.cpp src/uniform_type_info_map.cpp
src/untyped_actor.cpp
src/weak_ptr_anchor.cpp src/weak_ptr_anchor.cpp
src/yield_interface.cpp) src/yield_interface.cpp)
......
...@@ -13,7 +13,6 @@ cppa/attachable.hpp ...@@ -13,7 +13,6 @@ cppa/attachable.hpp
cppa/behavior.hpp cppa/behavior.hpp
cppa/binary_deserializer.hpp cppa/binary_deserializer.hpp
cppa/binary_serializer.hpp cppa/binary_serializer.hpp
cppa/blocking_actor.hpp
cppa/blocking_untyped_actor.hpp cppa/blocking_untyped_actor.hpp
cppa/channel.hpp cppa/channel.hpp
cppa/common_actor_ops.hpp cppa/common_actor_ops.hpp
...@@ -37,7 +36,6 @@ cppa/detail/demangle.hpp ...@@ -37,7 +36,6 @@ cppa/detail/demangle.hpp
cppa/detail/disablable_delete.hpp cppa/detail/disablable_delete.hpp
cppa/detail/empty_tuple.hpp cppa/detail/empty_tuple.hpp
cppa/detail/fd_util.hpp cppa/detail/fd_util.hpp
cppa/detail/get_behavior.hpp
cppa/detail/group_manager.hpp cppa/detail/group_manager.hpp
cppa/detail/handle.hpp cppa/detail/handle.hpp
cppa/detail/ieee_754.hpp cppa/detail/ieee_754.hpp
...@@ -53,7 +51,6 @@ cppa/detail/projection.hpp ...@@ -53,7 +51,6 @@ cppa/detail/projection.hpp
cppa/detail/pseudo_tuple.hpp cppa/detail/pseudo_tuple.hpp
cppa/detail/ptype_to_type.hpp cppa/detail/ptype_to_type.hpp
cppa/detail/raw_access.hpp cppa/detail/raw_access.hpp
cppa/detail/scheduled_actor_dummy.hpp
cppa/detail/serialize_tuple.hpp cppa/detail/serialize_tuple.hpp
cppa/detail/singleton_manager.hpp cppa/detail/singleton_manager.hpp
cppa/detail/singleton_mixin.hpp cppa/detail/singleton_mixin.hpp
...@@ -105,7 +102,6 @@ cppa/io/remote_actor_proxy.hpp ...@@ -105,7 +102,6 @@ cppa/io/remote_actor_proxy.hpp
cppa/io/stream.hpp cppa/io/stream.hpp
cppa/local_actor.hpp cppa/local_actor.hpp
cppa/logging.hpp cppa/logging.hpp
cppa/mailbox_based.hpp
cppa/mailbox_element.hpp cppa/mailbox_element.hpp
cppa/match.hpp cppa/match.hpp
cppa/match_expr.hpp cppa/match_expr.hpp
...@@ -117,7 +113,6 @@ cppa/message_header.hpp ...@@ -117,7 +113,6 @@ cppa/message_header.hpp
cppa/message_id.hpp cppa/message_id.hpp
cppa/message_priority.hpp cppa/message_priority.hpp
cppa/node_id.hpp cppa/node_id.hpp
cppa/nonblocking_actor.hpp
cppa/none.hpp cppa/none.hpp
cppa/object.hpp cppa/object.hpp
cppa/on.hpp cppa/on.hpp
...@@ -133,7 +128,7 @@ cppa/opt.hpp ...@@ -133,7 +128,7 @@ cppa/opt.hpp
cppa/optional.hpp cppa/optional.hpp
cppa/optional_variant.hpp cppa/optional_variant.hpp
cppa/partial_function.hpp cppa/partial_function.hpp
cppa/policy/invoke_policy_base.hpp cppa/policy/invoke_policy.hpp
cppa/policy/nestable_invoke.hpp cppa/policy/nestable_invoke.hpp
cppa/policy/prioritizing.hpp cppa/policy/prioritizing.hpp
cppa/policy/sequential_invoke.hpp cppa/policy/sequential_invoke.hpp
...@@ -144,7 +139,6 @@ cppa/ref_counted.hpp ...@@ -144,7 +139,6 @@ cppa/ref_counted.hpp
cppa/replies_to.hpp cppa/replies_to.hpp
cppa/response_handle.hpp cppa/response_handle.hpp
cppa/sb_actor.hpp cppa/sb_actor.hpp
cppa/scheduled_actor.hpp
cppa/scheduler.hpp cppa/scheduler.hpp
cppa/scoped_actor.hpp cppa/scoped_actor.hpp
cppa/send.hpp cppa/send.hpp
...@@ -152,7 +146,6 @@ cppa/serializer.hpp ...@@ -152,7 +146,6 @@ cppa/serializer.hpp
cppa/singletons.hpp cppa/singletons.hpp
cppa/spawn.hpp cppa/spawn.hpp
cppa/spawn_options.hpp cppa/spawn_options.hpp
cppa/thread_mapped_actor.hpp
cppa/timeout_definition.hpp cppa/timeout_definition.hpp
cppa/to_string.hpp cppa/to_string.hpp
cppa/tpartial_function.hpp cppa/tpartial_function.hpp
...@@ -245,7 +238,6 @@ src/demangle.cpp ...@@ -245,7 +238,6 @@ src/demangle.cpp
src/deserializer.cpp src/deserializer.cpp
src/duration.cpp src/duration.cpp
src/empty_tuple.cpp src/empty_tuple.cpp
src/event_based_resume.cpp
src/exception.cpp src/exception.cpp
src/exit_reason.cpp src/exit_reason.cpp
src/factory.cpp src/factory.cpp
...@@ -286,8 +278,6 @@ src/ref_counted.cpp ...@@ -286,8 +278,6 @@ src/ref_counted.cpp
src/remote_actor_proxy.cpp src/remote_actor_proxy.cpp
src/response_handle.cpp src/response_handle.cpp
src/ripemd_160.cpp src/ripemd_160.cpp
src/scheduled_actor.cpp
src/scheduled_actor_dummy.cpp
src/scheduler.cpp src/scheduler.cpp
src/scoped_actor.cpp src/scoped_actor.cpp
src/send.cpp src/send.cpp
...@@ -296,7 +286,6 @@ src/shared_spinlock.cpp ...@@ -296,7 +286,6 @@ src/shared_spinlock.cpp
src/singleton_manager.cpp src/singleton_manager.cpp
src/string_serialization.cpp src/string_serialization.cpp
src/sync_request_bouncer.cpp src/sync_request_bouncer.cpp
src/thread_mapped_actor.cpp
src/thread_pool_scheduler.cpp src/thread_pool_scheduler.cpp
src/to_uniform_name.cpp src/to_uniform_name.cpp
src/type_lookup_table.cpp src/type_lookup_table.cpp
...@@ -338,3 +327,14 @@ cppa/policy/resume_policy.hpp ...@@ -338,3 +327,14 @@ cppa/policy/resume_policy.hpp
cppa/policy/cooperative_scheduling.hpp cppa/policy/cooperative_scheduling.hpp
cppa/policy/scheduling_policy.hpp cppa/policy/scheduling_policy.hpp
cppa/policy/priority_policy.hpp cppa/policy/priority_policy.hpp
cppa/policy/not_prioritizing.hpp
cppa/detail/functor_based_blocking_actor.hpp
src/functor_based_actor.cpp
cppa/mailbox_based.hpp
cppa/behavior_stack_based.hpp
cppa/resumable.hpp
src/resumable.cpp
cppa/policy/middleman_scheduling.hpp
src/untyped_actor.cpp
src/functor_based_blocking_actor.cpp
src/blocking_untyped_actor.cpp
...@@ -143,6 +143,12 @@ class abstract_actor : public abstract_channel { ...@@ -143,6 +143,12 @@ class abstract_actor : public abstract_channel {
*/ */
inline const node_id& node() const; inline const node_id& node() 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;
protected: protected:
abstract_actor(); abstract_actor();
...@@ -166,12 +172,6 @@ class abstract_actor : public abstract_channel { ...@@ -166,12 +172,6 @@ class abstract_actor : public abstract_channel {
*/ */
bool unlink_from_impl(const actor_addr& other); 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>. * @brief Returns <tt>exit_reason() != exit_reason::not_exited</tt>.
*/ */
......
...@@ -45,6 +45,10 @@ namespace cppa { ...@@ -45,6 +45,10 @@ namespace cppa {
namespace detail { class raw_access; } namespace detail { class raw_access; }
struct invalid_actor_t { constexpr invalid_actor_t() { } };
constexpr invalid_actor_t invalid_actor = invalid_actor_t{};
/** /**
* @brief Identifies an untyped actor. * @brief Identifies an untyped actor.
*/ */
...@@ -65,6 +69,8 @@ class actor : util::comparable<actor> { ...@@ -65,6 +69,8 @@ class actor : util::comparable<actor> {
inline bool operator!() const; inline bool operator!() const;
actor(const invalid_actor_t&);
void enqueue(const message_header& hdr, any_tuple msg) const; void enqueue(const message_header& hdr, any_tuple msg) const;
inline common_actor_ops* operator->() const { inline common_actor_ops* operator->() const {
......
...@@ -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_ACTOR_ADDR_HPP #ifndef CPPA_ACTOR_ADDR_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_ACTOR_NAMESPACE_HPP #ifndef CPPA_ACTOR_NAMESPACE_HPP
......
...@@ -28,12 +28,9 @@ ...@@ -28,12 +28,9 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_STACKLESS_HPP #ifndef CPPA_BEHAVIOR_STACK_BASED_HPP
#define CPPA_STACKLESS_HPP #define CPPA_BEHAVIOR_STACK_BASED_HPP
#include "cppa/util/dptr.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/detail/behavior_stack.hpp" #include "cppa/detail/behavior_stack.hpp"
namespace cppa { namespace cppa {
...@@ -41,14 +38,14 @@ namespace cppa { ...@@ -41,14 +38,14 @@ namespace cppa {
#ifdef CPPA_DOCUMENTATION #ifdef CPPA_DOCUMENTATION
/** /**
* @brief Policy tag that causes {@link event_based_actor::become} to * @brief Policy tag that causes {@link untyped_actor::become} to
* discard the current behavior. * discard the current behavior.
* @relates local_actor * @relates local_actor
*/ */
constexpr auto discard_behavior; constexpr auto discard_behavior;
/** /**
* @brief Policy tag that causes {@link event_based_actor::become} to * @brief Policy tag that causes {@link untyped_actor::become} to
* keep the current behavior available. * keep the current behavior available.
* @relates local_actor * @relates local_actor
*/ */
...@@ -75,25 +72,14 @@ constexpr keep_behavior_t keep_behavior = keep_behavior_t{}; ...@@ -75,25 +72,14 @@ constexpr keep_behavior_t keep_behavior = keep_behavior_t{};
#endif #endif
template<class Base, class Subtype> template<class Base, class Subtype>
class stackless : public Base { class behavior_stack_based : public Base {
protected:
typedef stackless combined_type;
public: public:
template<typename... Ts> typedef behavior_stack_based combined_type;
stackless(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
static constexpr auto receive_flag = detail::rp_sequential;
bool has_behavior() {
return this->m_bhvr_stack.empty() == false;
}
void unbecome() { inline void unbecome() {
this->m_bhvr_stack.pop_async_back(); m_bhvr_stack.pop_async_back();
} }
/** /**
...@@ -118,41 +104,27 @@ class stackless : public Base { ...@@ -118,41 +104,27 @@ class stackless : public Base {
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(); //FIXME
this->request_timeout(bhvr.timeout());
} }
this->m_bhvr_stack.push_back(std::move(bhvr), mf); m_bhvr_stack.push_back(std::move(bhvr), mf);
} }
void do_become(behavior&& bhvr, bool discard_old) { void do_become(behavior&& bhvr, bool discard_old) {
this->reset_timeout(); if (discard_old) m_bhvr_stack.pop_async_back();
this->request_timeout(bhvr.timeout()); m_bhvr_stack.push_back(std::move(bhvr));
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 m_bhvr_stack.empty() == false;
} }
inline behavior& get_behavior() { inline behavior& get_behavior() {
CPPA_REQUIRE(this->m_bhvr_stack.empty() == false); CPPA_REQUIRE(m_bhvr_stack.empty() == false);
return this->m_bhvr_stack.back(); return m_bhvr_stack.back();
} }
inline void handle_timeout(behavior& bhvr) { inline void handle_timeout(behavior& bhvr) {
CPPA_REQUIRE(bhvr.timeout().valid());
this->reset_timeout();
bhvr.handle_timeout(); bhvr.handle_timeout();
if (this->m_bhvr_stack.empty() == false) {
this->request_timeout(get_behavior().timeout());
}
}
void exec_bhvr_stack() {
while (!m_bhvr_stack.empty()) {
m_bhvr_stack.exec(m_recv_policy, util::dptr<Subtype>(this));
}
} }
inline detail::behavior_stack& bhvr_stack() { inline detail::behavior_stack& bhvr_stack() {
...@@ -168,11 +140,8 @@ class stackless : public Base { ...@@ -168,11 +140,8 @@ class stackless : public Base {
// allows actors to keep previous behaviors and enables unbecome() // allows actors to keep previous behaviors and enables unbecome()
detail::behavior_stack m_bhvr_stack; detail::behavior_stack m_bhvr_stack;
// used for message handling in subclasses
detail::receive_policy m_recv_policy;
}; };
} // namespace cppa } // namespace cppa
#endif // CPPA_STACKLESS_HPP #endif // CPPA_BEHAVIOR_STACK_BASED_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_STACKED_ACTOR_MIXIN_HPP
#define CPPA_STACKED_ACTOR_MIXIN_HPP
#include <chrono>
#include <memory>
#include <functional>
#include "cppa/behavior.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_element.hpp"
namespace cppa {
class blocking_actor : public local_actor {
friend class detail::receive_policy;
friend class detail::behavior_stack;
protected:
typedef stacked combined_type;
public:
static constexpr auto receive_flag = detail::rp_nestable;
struct receive_while_helper {
std::function<void(behavior&)> m_dq;
std::function<bool()> m_stmt;
template<typename... Ts>
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() {
if (m_behavior) m_behavior();
auto dthis = util::dptr<Subtype>(this);
auto rsn = dthis->planned_exit_reason();
dthis->cleanup(rsn == exit_reason::not_exited ? exit_reason::normal : rsn);
}
inline void set_behavior(std::function<void()> fun) {
m_behavior = std::move(fun);
}
inline optional<behavior&> sync_handler(message_id msg_id) {
auto i = m_sync_handler.find(msg_id);
if (i != m_sync_handler.end()) return i->second;
return none;
}
protected:
template<typename... Ts>
stacked(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
virtual bool has_behavior() {
return static_cast<bool>(m_behavior);
}
std::function<void()> m_behavior;
detail::receive_policy m_recv_policy;
private:
std::map<message_id, behavior> m_sync_handler;
std::function<void(behavior&)> make_dequeue_callback() {
return [=](behavior& bhvr) { dequeue(bhvr); };
}
void dequeue(behavior& bhvr) {
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr);
}
void dequeue_response(behavior& bhvr, message_id request_id) {
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr, request_id);
}
};
} // namespace cppa
#endif // CPPA_STACKED_ACTOR_MIXIN_HPP
...@@ -25,22 +25,209 @@ ...@@ -25,22 +25,209 @@
* * * *
* 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_BLOCKING_UNTYPED_ACTOR_HPP #ifndef CPPA_BLOCKING_UNTYPED_ACTOR_HPP
#define CPPA_BLOCKING_UNTYPED_ACTOR_HPP #define CPPA_BLOCKING_UNTYPED_ACTOR_HPP
#include "cppa/extend.hpp" #include "cppa/extend.hpp"
#include "cppa/stacked.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
namespace cppa { namespace cppa {
/** /**
* @extends local_actor * @extends local_actor
*/ */
class blocking_untyped_actor : public extend<local_actor>::with<stacked> { class blocking_untyped_actor : public extend<local_actor>::with<mailbox_based> {
public:
typedef std::chrono::high_resolution_clock::time_point timeout_type;
struct receive_while_helper {
std::function<void(behavior&)> m_dq;
std::function<bool()> m_stmt;
template<typename... Ts>
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 Handles a synchronous response message in an event-based way.
* @param handle A future for a synchronous response.
* @throws std::logic_error if @p handle is not valid or if the actor
* already received the response for @p handle
* @relates message_future
*/
inline sync_receive_helper receive_response(const message_future& f) {
return {f};
}
/**
* @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)...)};
}
inline optional<behavior&> sync_handler(message_id msg_id) {
auto i = m_sync_handler.find(msg_id);
if (i != m_sync_handler.end()) return i->second;
return none;
}
inline void dequeue(behavior&& bhvr) {
behavior tmp{std::move(bhvr)};
dequeue(tmp);
}
virtual void dequeue(behavior& bhvr) = 0;
virtual mailbox_element* dequeue() = 0;
virtual mailbox_element* try_dequeue() = 0;
virtual mailbox_element* try_dequeue(const timeout_type&) = 0;
void await_all_other_actors_done();
virtual void act() = 0;
private:
std::map<message_id, behavior> m_sync_handler;
std::function<void(behavior&)> make_dequeue_callback() {
return [=](behavior& bhvr) { dequeue(bhvr); };
}
/*
void dequeue_response(behavior& bhvr, message_id request_id) {
m_recv_policy.receive(util::dptr<Subtype>(this), bhvr, request_id);
}
*/
}; };
......
...@@ -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
......
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#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"
#include "cppa/threaded.hpp"
#include "cppa/scheduler.hpp" #include "cppa/scheduler.hpp"
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
...@@ -56,14 +55,12 @@ ...@@ -56,14 +55,12 @@
#include "cppa/typed_actor.hpp" #include "cppa/typed_actor.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/prioritizing.hpp" #include "cppa/scoped_actor.hpp"
#include "cppa/spawn_options.hpp" #include "cppa/spawn_options.hpp"
#include "cppa/untyped_actor.hpp" #include "cppa/untyped_actor.hpp"
#include "cppa/abstract_actor.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/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/blocking_untyped_actor.hpp" #include "cppa/blocking_untyped_actor.hpp"
#include "cppa/util/type_traits.hpp" #include "cppa/util/type_traits.hpp"
...@@ -79,7 +76,6 @@ ...@@ -79,7 +76,6 @@
#include "cppa/io/connection_handle.hpp" #include "cppa/io/connection_handle.hpp"
#include "cppa/detail/memory.hpp" #include "cppa/detail/memory.hpp"
#include "cppa/detail/get_behavior.hpp"
#include "cppa/detail/actor_registry.hpp" #include "cppa/detail/actor_registry.hpp"
/** /**
...@@ -436,8 +432,7 @@ ...@@ -436,8 +432,7 @@
namespace cppa { namespace cppa {
template<typename... Ts> inline void send_tuple_as(const actor& from, const channel& to, any_tuple msg) {
void send_tuple_as(const actor& from, const channel& to, any_tuple msg) {
to.enqueue({from->address(), to}, std::move(msg)); to.enqueue({from->address(), to}, std::move(msg));
} }
...@@ -450,6 +445,23 @@ template<typename... Ts> ...@@ -450,6 +445,23 @@ template<typename... Ts>
void send_as(const actor& from, const channel& to, Ts&&... args) { void send_as(const actor& from, const channel& to, Ts&&... args) {
send_tuple_as(from, to, make_any_tuple(std::forward<Ts>(args)...)); send_tuple_as(from, to, make_any_tuple(std::forward<Ts>(args)...));
} }
inline void anon_send_tuple(const channel& to, any_tuple msg) {
to.enqueue({invalid_actor_addr, to}, std::move(msg));
}
/**
* @brief Anonymously sends a message to @p receiver;
*/
template<typename... Ts>
inline void anon_send(const channel& receiver, Ts&&... args) {
anon_send_tuple(receiver, make_any_tuple(std::forward<Ts>(args)...));
}
inline void anon_send_exit(const actor_addr&, std::uint32_t) {
}
/** /**
* @brief Blocks execution of this actor until all * @brief Blocks execution of this actor until all
* other actors finished execution. * other actors finished execution.
...@@ -517,10 +529,16 @@ template<class Impl, spawn_options Options = no_spawn_options, typename... Ts> ...@@ -517,10 +529,16 @@ template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor 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 policy;
using namespace std; using proper_impl = detail::proper_actor<Impl,
auto ptr = make_counted<Impl>(move(in), move(out), forward<Ts>(args)...); middleman_scheduling,
return eval_sopts(Options, io::init_and_launch(move(ptr))); not_prioritizing,
no_resume,
cooperative_scheduling>;
auto ptr = make_counted<proper_impl>(std::move(in), std::move(out),
std::forward<Ts>(args)...);
ptr->launch();
return ptr;
} }
/** /**
...@@ -530,16 +548,12 @@ actor spawn_io(io::input_stream_ptr in, ...@@ -530,16 +548,12 @@ actor spawn_io(io::input_stream_ptr in,
* @returns An {@link actor_ptr} to the spawned {@link actor}. * @returns An {@link actor_ptr} to the spawned {@link actor}.
*/ */
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>
actor 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) { return spawn_io<io::default_broker>(std::move(fun), std::move(in),
using namespace std; std::move(out));
auto ptr = io::broker::from(move(fun), move(in), move(out),
forward<Ts>(args)...);
return eval_sopts(Options, io::init_and_launch(move(ptr)));
} }
/* /*
...@@ -551,21 +565,17 @@ actor_ptr spawn_io(const char* host, uint16_t port, Ts&&... args) { ...@@ -551,21 +565,17 @@ 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> actor spawn_io(F fun, const std::string& host, uint16_t port) {
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);
} }
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> actor spawn_io_server(F fun, uint16_t port) {
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), return spawn_io(move(fun), io::ipv4_acceptor::create(port));
forward<Ts>(args)...);
return eval_sopts(Options, io::init_and_launch(move(ptr)));
} }
/** /**
......
...@@ -31,13 +31,100 @@ ...@@ -31,13 +31,100 @@
#ifndef CPPA_FUNCTOR_BASED_ACTOR_HPP #ifndef CPPA_FUNCTOR_BASED_ACTOR_HPP
#define CPPA_FUNCTOR_BASED_ACTOR_HPP #define CPPA_FUNCTOR_BASED_ACTOR_HPP
#include <type_traits>
#include "cppa/untyped_actor.hpp" #include "cppa/untyped_actor.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
class functor_based_actor : public untyped_actor { class functor_based_actor : public untyped_actor {
public:
typedef std::function<behavior(untyped_actor*)> make_behavior_fun;
typedef std::function<void(untyped_actor*)> void_fun;
template<typename F, typename... Ts>
functor_based_actor(F f, Ts&&... vs) {
untyped_actor* dummy = nullptr;
create(dummy, f, std::forward<Ts>(vs)...);
}
behavior make_behavior() override;
private:
void create(untyped_actor*, void_fun);
template<class Actor, typename F, typename... Ts>
auto create(Actor*, F f, Ts&&... vs) ->
typename std::enable_if<
std::is_convertible<
decltype(f(std::forward<Ts>(vs)...)),
behavior
>::value
>::type {
auto fun = std::bind(f, std::forward<Ts>(vs)...);
m_make_behavior = [fun](Actor*) -> behavior { return fun(); };
}
template<class Actor, typename F, typename... Ts>
auto create(Actor* dummy, F f, Ts&&... vs) ->
typename std::enable_if<
std::is_convertible<
decltype(f(dummy, std::forward<Ts>(vs)...)),
behavior
>::value
>::type {
auto fun = std::bind(f, std::placeholders::_1, std::forward<Ts>(vs)...);
m_make_behavior = [fun](Actor* self) -> behavior { return fun(self); };
}
template<class Actor, typename F, typename... Ts>
auto create(Actor*, F f, Ts&&... vs) ->
typename std::enable_if<
std::is_same<
decltype(f(std::forward<Ts>(vs)...)),
void
>::value
>::type {
std::function<void()> fun = std::bind(f, std::forward<Ts>(vs)...);
m_make_behavior = [fun](Actor*) -> behavior {
fun();
return behavior{};
};
}
template<class Actor, typename F, typename... Ts>
auto create(Actor* dummy, F f, Ts&&... vs) ->
typename std::enable_if<
std::is_same<
decltype(f(dummy, std::forward<Ts>(vs)...)),
void
>::value
>::type {
std::function<void(Actor*)> fun = std::bind(f, std::placeholders::_1,
std::forward<Ts>(vs)...);
m_make_behavior = [fun](Actor* self) -> behavior {
fun(self);
return behavior{};
};
}
/*
template<class Actor, typename F, typename T0, typename... Ts>
void create(void*, F, T0&&, Ts&&...) {
// this overload acts as 'catch-all' rule to
// give the user a clear hint at what's wrong
// with the provided functor
static_assert(sizeof...(Ts) != sizeof...(Ts),
"spawn: provided functor must either return 'void'' "
"or 'cppa::behavior'");
}
*/
make_behavior_fun m_make_behavior;
}; };
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 FUNCTOR_BASED_BLOCKING_ACTOR_HPP
#define FUNCTOR_BASED_BLOCKING_ACTOR_HPP
#include "cppa/blocking_untyped_actor.hpp"
namespace cppa {
namespace detail {
class functor_based_blocking_actor : public blocking_untyped_actor {
public:
typedef std::function<void (blocking_untyped_actor*)> act_fun;
template<typename F, typename... Ts>
functor_based_blocking_actor(F f, Ts&&... vs) {
blocking_untyped_actor* dummy = nullptr;
create(dummy, f, std::forward<Ts>(vs)...);
}
protected:
void act() override;
private:
void create(blocking_untyped_actor*, act_fun);
template<class Actor, typename F, typename T0, typename... Ts>
auto create(Actor* dummy, F f, T0&& v0, Ts&&... vs) ->
typename std::enable_if<
std::is_same<
decltype(f(dummy, std::forward<T0>(v0), std::forward<Ts>(vs)...)),
void
>::value
>::type {
create(dummy, std::bind(f, std::placeholders::_1,
std::forward<T0>(v0), std::forward<Ts>(vs)...));
}
template<class Actor, typename F, typename T0, typename... Ts>
auto create(Actor* dummy, F f, T0&& v0, Ts&&... vs) ->
typename std::enable_if<
std::is_same<
decltype(f(std::forward<T0>(v0), std::forward<Ts>(vs)...)),
void
>::value
>::type {
std::function<void()> fun = std::bind(f, std::forward<T0>(v0),
std::forward<Ts>(vs)...);
create(dummy, [fun](Actor*) { fun(); });
}
act_fun m_act;
};
} // namespace detail
} // namespace cppa
#endif // FUNCTOR_BASED_BLOCKING_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_GET_BEHAVIOR_HPP
#define CPPA_GET_BEHAVIOR_HPP
#include <type_traits>
#include "cppa/util/call.hpp"
#include "cppa/util/int_list.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/detail/tdata.hpp"
#include "cppa/scheduled_actor.hpp"
namespace cppa { namespace detail {
// default: <true, false, F>
template<bool IsFunctionPtr, bool HasArguments, typename F, typename... Ts>
class ftor_behavior : public scheduled_actor {
F m_fun;
public:
ftor_behavior(F ptr) : m_fun(ptr) { }
virtual void act() { m_fun(); }
};
template<typename F, typename... Ts>
class ftor_behavior<true, true, F, Ts...> : public scheduled_actor {
static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0");
F m_fun;
typedef typename tdata_from_type_list<
typename util::tl_map<util::type_list<Ts...>,
implicit_conversions>::type>::type
tdata_type;
tdata_type m_args;
public:
ftor_behavior(F ptr, const Ts&... args) : m_fun(ptr), m_args(args...) { }
virtual void act() {
util::apply_args(m_fun, m_args, util::get_indices(m_args));
}
};
template<typename F>
class ftor_behavior<false, false, F> : public scheduled_actor {
F m_fun;
public:
ftor_behavior(const F& arg) : m_fun(arg) { }
ftor_behavior(F&& arg) : m_fun(std::move(arg)) { }
virtual void act() { m_fun(); }
};
template<typename F, typename... Ts>
class ftor_behavior<false, true, F, Ts...> : public scheduled_actor {
static_assert(sizeof...(Ts) > 0, "sizeof...(Ts) == 0");
F m_fun;
typedef typename tdata_from_type_list<
typename util::tl_map<util::type_list<Ts...>,
implicit_conversions>::type>::type
tdata_type;
tdata_type m_args;
public:
ftor_behavior(const F& f, const Ts&... args) : m_fun(f), m_args(args...) {
}
ftor_behavior(F&& f, const Ts&... args)
: m_fun(std::move(f)), m_args(args...) { }
virtual void act() {
util::apply_args(m_fun, m_args, util::get_indices(m_args));
}
};
template<typename R>
scheduled_actor* get_behavior(std::integral_constant<bool, true>, R (*fptr)()) {
static_assert(std::is_convertible<R, scheduled_actor*>::value == false,
"Spawning a function returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that function?");
return new ftor_behavior<true, false, R (*)()>(fptr);
}
template<typename F>
scheduled_actor* get_behavior(std::integral_constant<bool, false>, F&& ftor) {
static_assert(std::is_convertible<decltype(ftor()), scheduled_actor*>::value == false,
"Spawning a functor returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that functor?");
typedef typename util::rm_const_and_ref<F>::type ftype;
return new ftor_behavior<false, false, ftype>(std::forward<F>(ftor));
}
template<typename F, typename T, typename... Ts>
scheduled_actor* get_behavior(std::true_type, F fptr, const T& arg, const Ts&... args) {
static_assert(std::is_convertible<decltype(fptr(arg, args...)), scheduled_actor*>::value == false,
"Spawning a function returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that function?");
typedef ftor_behavior<true, true, F, T, Ts...> impl;
return new impl(fptr, arg, args...);
}
template<typename F, typename T, typename... Ts>
scheduled_actor* get_behavior(std::false_type, F ftor, const T& arg, const Ts&... args) {
static_assert(std::is_convertible<decltype(ftor(arg, args...)), scheduled_actor*>::value == false,
"Spawning a functor returning an actor_behavior? "
"Are you sure that you do not want to spawn the behavior "
"returned by that functor?");
typedef typename util::rm_const_and_ref<F>::type ftype;
typedef ftor_behavior<false, true, ftype, T, Ts...> impl;
return new impl(std::forward<F>(ftor), arg, args...);
}
} } // namespace cppa::detail
#endif // CPPA_GET_BEHAVIOR_HPP
...@@ -3,37 +3,46 @@ ...@@ -3,37 +3,46 @@
#include <type_traits> #include <type_traits>
#include "cppa/blocking_actor.hpp" #include "cppa/resumable.hpp"
#include "cppa/mailbox_element.hpp" #include "cppa/mailbox_element.hpp"
#include "cppa/blocking_untyped_actor.hpp"
namespace cppa { namespace util { class fiber; } } #include "cppa/util/duration.hpp"
namespace cppa { namespace detail { namespace cppa {
namespace util {
struct fiber;
} // namespace util
} // namespace cppa
namespace cppa {
namespace detail {
template<class Base, template<class Base,
class SchedulingPolicy, class SchedulingPolicy,
class PriorityPolicy, class PriorityPolicy,
class ResumePolicy, class ResumePolicy,
class InvokePolicy, class InvokePolicy,
bool OverrideDequeue = std::is_base_of<blocking_actor, Base>::value> bool OverrideDequeue = std::is_base_of<blocking_untyped_actor, Base>::value>
class proper_actor : public Base { class proper_actor : public ResumePolicy::template mixin<Base> {
friend SchedulingPolicy;
friend PriorityPolicy;
friend ResumePolicy;
friend InvokePolicy;
typedef typename ResumePolicy::template mixin<Base> super;
public: public:
template<typename... Ts> template <typename... Ts>
proper_actor(Ts&&... args) : Base(std::forward<Ts>(args)) { } proper_actor(Ts&&... args) : super(std::forward<Ts>(args)...) { }
void enqueue(const message_header& hdr, any_tuple msg) override { void enqueue(const message_header& hdr, any_tuple msg) override {
m_scheduling_policy.enqueue(this, hdr, msg); m_scheduling_policy.enqueue(this, hdr, msg);
} }
void resume(util::fiber* fb) override { inline void launch() { m_scheduling_policy.launch(this); }
m_resume_policy.resume(this, fb);
}
inline void launch() {
m_scheduling_policy.launch(this);
}
inline mailbox_element* next_message() { inline mailbox_element* next_message() {
return m_priority_policy.next_message(this); return m_priority_policy.next_message(this);
...@@ -44,10 +53,32 @@ class proper_actor : public Base { ...@@ -44,10 +53,32 @@ class proper_actor : public Base {
} }
// grant access to the actor's mailbox // grant access to the actor's mailbox
Base::mailbox_type& mailbox() { typename Base::mailbox_type& mailbox() { return this->m_mailbox; }
return this->m_mailbox;
SchedulingPolicy& scheduling_policy() { return m_scheduling_policy; }
PriorityPolicy& priority_policy() { return m_priority_policy; }
ResumePolicy& resume_policy() { return m_resume_policy; }
InvokePolicy& invoke_policy() { return m_invoke_policy; }
inline void push_timeout() {
m_scheduling_policy.push_timeout();
}
inline void current_node(mailbox_element* ptr) {
this->m_current_node = ptr;
} }
inline void request_timeout(const util::duration& rel_timeout) {
m_invoke_policy.request_timeout(this, rel_timeout);
}
inline mailbox_element* current_node() { return this->m_current_node; }
detail::behavior_stack& bhvr_stack() { return this->m_bhvr_stack; }
protected: protected:
SchedulingPolicy m_scheduling_policy; SchedulingPolicy m_scheduling_policy;
...@@ -58,60 +89,77 @@ class proper_actor : public Base { ...@@ -58,60 +89,77 @@ class proper_actor : public Base {
}; };
// for blocking actors, there's one more member function to implement // for blocking actors, there's one more member function to implement
template<class Base, template <class Base, class SchedulingPolicy, class PriorityPolicy,
class SchedulingPolicy, class ResumePolicy, class InvokePolicy>
class PriorityPolicy, class proper_actor<
class ResumePolicy, Base, SchedulingPolicy, PriorityPolicy, ResumePolicy, InvokePolicy,
class InvokePolicy> true> final : public proper_actor<Base, SchedulingPolicy, PriorityPolicy,
class proper_actor<Base, ResumePolicy, InvokePolicy, false> {
SchedulingPolicy,
PriorityPolicy, typedef proper_actor<Base, SchedulingPolicy, PriorityPolicy,
ResumePolicy, ResumePolicy, InvokePolicy, false>
InvokePolicy, super;
true> : public proper_actor<Base,
SchedulingPolicy,
PriorityPolicy,
ResumePolicy,
InvokePolicy,
false> {
public: public:
template <typename... Ts>
proper_actor(Ts&&... args) : super(std::forward<Ts>(args)...) { }
void dequeue(behavior& bhvr) override { void dequeue(behavior& bhvr) override {
if (bhvr.timeout().valid()) { if (bhvr.timeout().valid()) {
auto abs_time = m_scheduling_policy.init_timeout(this, bhvr.timeout()); auto tout =
this->m_scheduling_policy.init_timeout(this, bhvr.timeout());
auto done = false; auto done = false;
while (!done) { while (!done) {
if (!m_resume_policy.await_data(this, abs_time)) { if (!this->m_resume_policy.await_data(this, tout)) {
bhvr.handle_timeout(); bhvr.handle_timeout();
done = true; done = true;
} } else {
else { auto msg = this->m_priority_policy.next_message(this);
auto msg = m_priority_policy.next_message(this);
// must not return nullptr, because await_data guarantees // must not return nullptr, because await_data guarantees
// at least one message in our mailbox // at least one message in our mailbox
CPPA_REQUIRE(msg != nullptr); CPPA_REQUIRE(msg != nullptr);
done = m_invoke_policy.invoke(this, bhvr, msg); done = this->m_invoke_policy.invoke(this, msg, bhvr);
}
} }
} }
else { } else {
for (;;) { for (;;) {
auto msg = m_priority_policy.next_message(this); auto msg = this->m_priority_policy.next_message(this);
while (msg) { while (msg) {
if (m_invoke_policy.invoke(this, bhvr, msg)) { if (this->m_invoke_policy.invoke(this, msg, bhvr)) {
// we're done // we're done
return; return;
} }
msg = m_priority_policy.next_message(this); msg = this->m_priority_policy.next_message(this);
} }
m_resume_policy.await_data(this); this->m_resume_policy.await_data(this);
} }
} }
} }
mailbox_element* dequeue() override {
auto e = try_dequeue();
if (!e) {
this->m_resume_policy.await_data(this);
return try_dequeue(); // guaranteed to succeed after await_data
}
return e;
}
mailbox_element* try_dequeue() override {
return this->m_priority_policy.next_message(this);
}
mailbox_element* try_dequeue(const typename Base::timeout_type& tout) override {
if (this->m_resume_policy.await_data(this, tout)) {
return try_dequeue();
}
return nullptr;
}
}; };
} } // namespace cppa::detail } // namespace detail
} // namespace cppa
#endif // PROPER_ACTOR_HPP #endif // PROPER_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_RAW_ACCESS_HPP #ifndef CPPA_RAW_ACCESS_HPP
......
...@@ -33,10 +33,10 @@ ...@@ -33,10 +33,10 @@
#include <thread> #include <thread>
#include "cppa/resumable.hpp"
#include "cppa/scheduler.hpp" #include "cppa/scheduler.hpp"
#include "cppa/context_switching_actor.hpp"
#include "cppa/util/producer_consumer_list.hpp" #include "cppa/util/producer_consumer_list.hpp"
#include "cppa/detail/scheduled_actor_dummy.hpp"
namespace cppa { namespace detail { namespace cppa { namespace detail {
...@@ -46,8 +46,9 @@ class thread_pool_scheduler : public scheduler { ...@@ -46,8 +46,9 @@ class thread_pool_scheduler : public scheduler {
public: public:
using scheduler::init_callback; struct dummy : resumable {
using scheduler::actor_fun; resume_result resume(util::fiber*) override;
};
struct worker; struct worker;
...@@ -59,24 +60,20 @@ class thread_pool_scheduler : public scheduler { ...@@ -59,24 +60,20 @@ class thread_pool_scheduler : public scheduler {
void destroy(); void destroy();
void enqueue(scheduled_actor* what); void enqueue(resumable* what) override;
local_actor_ptr exec(spawn_options opts, scheduled_actor_ptr ptr) override;
local_actor_ptr exec(spawn_options opts, init_callback init_cb, actor_fun f) override;
private: private:
//typedef util::single_reader_queue<abstract_scheduled_actor> job_queue; //typedef util::single_reader_queue<abstract_scheduled_actor> job_queue;
typedef util::producer_consumer_list<scheduled_actor> job_queue; typedef util::producer_consumer_list<resumable> job_queue;
size_t m_num_threads; size_t m_num_threads;
job_queue m_queue; job_queue m_queue;
scheduled_actor_dummy m_dummy; dummy m_dummy;
std::thread m_supervisor; std::thread m_supervisor;
static void worker_loop(worker*); static void worker_loop(worker*);
static void supervisor_loop(job_queue*, scheduled_actor*, size_t); static void supervisor_loop(job_queue*, resumable*, size_t);
}; };
......
...@@ -51,8 +51,8 @@ struct extend_helper<D, B, M, Ms...> : extend_helper<D, M<B, D>, Ms...> { }; ...@@ -51,8 +51,8 @@ struct extend_helper<D, B, M, Ms...> : extend_helper<D, M<B, D>, Ms...> { };
/** /**
* @brief Allows convenient definition of types using mixins. * @brief Allows convenient definition of types using mixins.
* For example, @p extend<ar, T>::with<ob, fo> is an alias for * For example, "extend<ar, T>::with<ob, fo>" is an alias for
* @p fo<ob<ar, T>, T>. * "fo<ob<ar, T>, T>".
* *
* Mixins in libcppa always have two template parameters: base type and * Mixins in libcppa always have two template parameters: base type and
* derived type. This allows mixins to make use of the curiously recurring * derived type. This allows mixins to make use of the curiously recurring
...@@ -64,7 +64,7 @@ struct extend { ...@@ -64,7 +64,7 @@ struct extend {
/** /**
* @brief Identifies the combined type. * @brief Identifies the combined type.
*/ */
template<template<class, class> class... Mixins> template<CPPA_MIXIN... Mixins>
using with = typename detail::extend_helper<Derived, Base, Mixins...>::type; using with = typename detail::extend_helper<Derived, Base, Mixins...>::type;
}; };
......
...@@ -33,9 +33,9 @@ ...@@ -33,9 +33,9 @@
#include <map> #include <map>
#include "cppa/stackless.hpp" #include "cppa/extend.hpp"
#include "cppa/threadless.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/behavior_stack_based.hpp"
#include "cppa/util/buffer.hpp" #include "cppa/util/buffer.hpp"
...@@ -45,7 +45,10 @@ ...@@ -45,7 +45,10 @@
#include "cppa/io/accept_handle.hpp" #include "cppa/io/accept_handle.hpp"
#include "cppa/io/connection_handle.hpp" #include "cppa/io/connection_handle.hpp"
namespace cppa { namespace io { #include "cppa/policy/sequential_invoke.hpp"
namespace cppa {
namespace io {
class broker; class broker;
...@@ -58,7 +61,9 @@ local_actor_ptr init_and_launch(broker_ptr); ...@@ -58,7 +61,9 @@ local_actor_ptr init_and_launch(broker_ptr);
* and other components in the network. * and other components in the network.
* @extends local_actor * @extends local_actor
*/ */
class broker : public extend<local_actor>::with<threadless, stackless> { class broker : public extend<local_actor>::with<behavior_stack_based> {
friend class policy::sequential_invoke;
typedef combined_type super; typedef combined_type super;
...@@ -97,6 +102,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> { ...@@ -97,6 +102,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
void write(const connection_handle& hdl, util::buffer&& buf); void write(const connection_handle& hdl, util::buffer&& buf);
/*
template<typename F, typename... Ts> template<typename F, typename... Ts>
static broker_ptr from(F fun, static broker_ptr from(F fun,
input_stream_ptr in, input_stream_ptr in,
...@@ -121,6 +127,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> { ...@@ -121,6 +127,7 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
std::forward<Ts>(args)...), std::forward<Ts>(args)...),
std::move(in)); std::move(in));
} }
*/
template<typename F, typename... Ts> template<typename F, typename... Ts>
actor fork(F fun, connection_handle hdl, Ts&&... args) { actor fork(F fun, connection_handle hdl, Ts&&... args) {
...@@ -154,14 +161,16 @@ class broker : public extend<local_actor>::with<threadless, stackless> { ...@@ -154,14 +161,16 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
explicit broker(scribe_pointer); explicit broker(scribe_pointer);
virtual behavior make_behavior() = 0;
private: private:
actor_addr fork_impl(std::function<void (broker*)> fun, actor 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,
input_stream_ptr in, // input_stream_ptr in,
output_stream_ptr out); // output_stream_ptr out);
void invoke_message(const message_header& hdr, any_tuple msg); void invoke_message(const message_header& hdr, any_tuple msg);
...@@ -178,10 +187,27 @@ class broker : public extend<local_actor>::with<threadless, stackless> { ...@@ -178,10 +187,27 @@ class broker : public extend<local_actor>::with<threadless, stackless> {
std::map<accept_handle, doorman_pointer> m_accept; std::map<accept_handle, doorman_pointer> m_accept;
std::map<connection_handle, scribe_pointer> m_io; std::map<connection_handle, scribe_pointer> m_io;
policy::sequential_invoke m_invoke;
}; };
//typedef intrusive_ptr<broker> broker_ptr; class default_broker : public broker {
public:
typedef std::function<void (broker*)> function_type;
default_broker(input_stream_ptr in, output_stream_ptr out, function_type f);
behavior make_behavior() override;
private:
function_type m_fun;
};
} } // namespace cppa::network } // namespace io
} // namespace cppa
#endif // CPPA_BROKER_HPP #endif // CPPA_BROKER_HPP
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#ifndef CPPA_CONTEXT_HPP #ifndef CPPA_CONTEXT_HPP
#define CPPA_CONTEXT_HPP #define CPPA_CONTEXT_HPP
#include <atomic>
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
...@@ -42,9 +43,10 @@ ...@@ -42,9 +43,10 @@
#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/actor_state.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/typed_actor.hpp" #include "cppa/typed_actor.hpp"
#include "cppa/mailbox_based.hpp" #include "cppa/spawn_options.hpp"
#include "cppa/memory_cached.hpp" #include "cppa/memory_cached.hpp"
#include "cppa/message_future.hpp" #include "cppa/message_future.hpp"
#include "cppa/message_header.hpp" #include "cppa/message_header.hpp"
...@@ -58,6 +60,8 @@ ...@@ -58,6 +60,8 @@
#include "cppa/detail/behavior_stack.hpp" #include "cppa/detail/behavior_stack.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace cppa { namespace cppa {
// forward declarations // forward declarations
...@@ -66,22 +70,69 @@ class message_future; ...@@ -66,22 +70,69 @@ class message_future;
class local_scheduler; class local_scheduler;
class sync_handle_helper; class sync_handle_helper;
namespace detail { class receive_policy; } namespace util {
struct fiber;
} // namespace util
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args);
template<spawn_options Options = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args);
/** /**
* @brief Base class for local running Actors. * @brief Base class for local running Actors.
* @extends actor * @extends actor
*/ */
class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_based> { class local_actor : public extend<abstract_actor>::with<memory_cached> {
friend class detail::receive_policy;
typedef combined_type super; typedef combined_type super;
public: public:
typedef detail::disposer del;
typedef intrusive::single_reader_queue<mailbox_element, del> mailbox_type;
~local_actor(); ~local_actor();
inline actor eval_opts(spawn_options opts, actor res) {
if (has_monitor_flag(opts)) {
monitor(res);
}
if (has_link_flag(opts)) {
link_to(res);
}
return res;
}
template<class Impl, spawn_options Options = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args) {
auto res = cppa::spawn<Impl, make_unbound(Options)>(std::forward<Ts>(args)...);
return eval_opts(Options, std::move(res));
}
template<spawn_options Options = no_spawn_options, typename... Ts>
actor spawn(Ts&&... args) {
auto res = cppa::spawn<make_unbound(Options)>(std::forward<Ts>(args)...);
return eval_opts(Options, std::move(res));
}
/**
* @brief Sends @p what to the receiver specified in @p dest.
*/
void send_tuple(message_priority prio, const channel& dest, any_tuple what);
/**
* @brief Sends <tt>{what...}</tt> to the receiver specified in @p hdr.
* @pre <tt>sizeof...(Ts) > 0</tt>
*/
template<typename... Ts>
void send(message_priority prio, const channel& whom, Ts&&... what) {
send_tuple(prio, whom, make_any_tuple(std::forward<Ts>(what)...));
}
/** /**
* @brief Sends @p what to the receiver specified in @p dest. * @brief Sends @p what to the receiver specified in @p dest.
*/ */
...@@ -96,6 +147,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b ...@@ -96,6 +147,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
send_tuple(whom, make_any_tuple(std::forward<Ts>(what)...)); send_tuple(whom, make_any_tuple(std::forward<Ts>(what)...));
} }
void send_exit(const actor_addr& whom, std::uint32_t reason);
/** /**
* @brief Sends @p what as a synchronous message to @p whom. * @brief Sends @p what as a synchronous message to @p whom.
* @param whom Receiver of the message. * @param whom Receiver of the message.
...@@ -128,8 +181,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b ...@@ -128,8 +181,8 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
} }
template<typename... Ts> template<typename... Ts>
message_future timed_sync_send(const util::duration& rtime, message_future timed_sync_send(const actor& dest,
const actor& dest, const util::duration& rtime,
Ts&&... what) { Ts&&... what) {
static_assert(sizeof...(Ts) > 0, "no message to send"); static_assert(sizeof...(Ts) > 0, "no message to send");
return timed_sync_send_tuple(rtime, dest, make_any_tuple(std::forward<Ts>(what)...)); return timed_sync_send_tuple(rtime, dest, make_any_tuple(std::forward<Ts>(what)...));
...@@ -146,6 +199,12 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b ...@@ -146,6 +199,12 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
const util::duration& rtime, const util::duration& rtime,
any_tuple data); any_tuple data);
template<typename... Ts>
void delayed_send(const channel& dest, const util::duration& rtime,
Ts&&... args) {
delayed_send_tuple(dest, rtime, make_any_tuple(std::forward<Ts>(args)...));
}
/** /**
* @brief Causes this actor to subscribe to the group @p what. * @brief Causes this actor to subscribe to the group @p what.
* *
...@@ -234,15 +293,6 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b ...@@ -234,15 +293,6 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
demonitor(whom->address()); demonitor(whom->address());
} }
/**
* @brief Can be overridden to initialize an actor before any
* message is handled.
* @warning Must not call blocking functions such as
* {@link cppa::receive receive}.
* @note Calling {@link become} to set an initial behavior is supported.
*/
virtual void init();
/** /**
* @brief Can be overridden to perform cleanup code after an actor * @brief Can be overridden to perform cleanup code after an actor
* finished execution. * finished execution.
...@@ -309,9 +359,7 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b ...@@ -309,9 +359,7 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
else quit(exit_reason::unhandled_sync_failure); else quit(exit_reason::unhandled_sync_failure);
} }
local_actor(bool is_scheduled = false); local_actor();
virtual bool initialized() const = 0;
inline bool chaining_enabled(); inline bool chaining_enabled();
...@@ -332,20 +380,32 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b ...@@ -332,20 +380,32 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
inline void mark_arrived(message_id response_id); inline void mark_arrived(message_id response_id);
//virtual void become_waiting_for(behavior, message_id) = 0; inline std::uint32_t planned_exit_reason() const;
//inline detail::behavior_stack& bhvr_stack();
//virtual void do_become(behavior&& bhvr, bool discard_old) = 0; inline void planned_exit_reason(std::uint32_t value);
//inline void do_become(const behavior& bhvr, bool discard_old); actor_state cas_state(actor_state expected, actor_state desired) {
auto e = expected;
do { if (m_state.compare_exchange_weak(e, desired)) return desired; }
while (e == expected);
return e;
}
inline std::uint32_t planned_exit_reason() const; inline void set_state(actor_state new_value) {
m_state.store(new_value);
}
inline void planned_exit_reason(std::uint32_t value); inline actor_state state() const {
return m_state;
}
protected: protected:
template<typename... Ts>
inline mailbox_element* new_mailbox_element(Ts&&... args) {
return mailbox_element::create(std::forward<Ts>(args)...);
}
void remove_handler(message_id id); void remove_handler(message_id id);
void cleanup(std::uint32_t reason); void cleanup(std::uint32_t reason);
...@@ -353,9 +413,6 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b ...@@ -353,9 +413,6 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
// 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
bool m_is_scheduled;
// 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;
...@@ -372,12 +429,12 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b ...@@ -372,12 +429,12 @@ class local_actor : public extend<abstract_actor>::with<memory_cached, mailbox_b
// {group => subscription} map of all joined groups // {group => subscription} map of all joined groups
std::map<group_ptr, group::subscription> m_subscriptions; std::map<group_ptr, group::subscription> m_subscriptions;
// allows actors to keep previous behaviors and enables unbecome()
//detail::behavior_stack m_bhvr_stack;
// set by quit // set by quit
std::uint32_t m_planned_exit_reason; std::uint32_t m_planned_exit_reason;
// the state of the (possibly cooperatively scheduled) actor
std::atomic<actor_state> m_state;
/** @endcond */ /** @endcond */
private: private:
......
...@@ -53,6 +53,11 @@ class mailbox_based : public Base { ...@@ -53,6 +53,11 @@ class mailbox_based : public Base {
} }
} }
template<typename... Ts>
inline mailbox_element* new_mailbox_element(Ts&&... args) {
return mailbox_element::create(std::forward<Ts>(args)...);
}
protected: protected:
typedef mailbox_based combined_type; typedef mailbox_based combined_type;
...@@ -68,11 +73,6 @@ class mailbox_based : public Base { ...@@ -68,11 +73,6 @@ class mailbox_based : public Base {
Base::cleanup(reason); Base::cleanup(reason);
} }
template<typename... Ts>
inline mailbox_element* new_mailbox_element(Ts&&... args) {
return mailbox_element::create(std::forward<Ts>(args)...);
}
mailbox_type m_mailbox; mailbox_type m_mailbox;
}; };
......
...@@ -64,7 +64,7 @@ template<typename T1, typename T2> ...@@ -64,7 +64,7 @@ template<typename T1, typename T2>
inline const T2& deduce_const(const T1&, T2& rhs) { return rhs; } inline const T2& deduce_const(const T1&, T2& rhs) { return rhs; }
template<class FilteredPattern> template<class FilteredPattern>
struct invoke_policy_base { struct invoke_util_base {
typedef FilteredPattern filtered_pattern; typedef FilteredPattern filtered_pattern;
typedef typename pseudo_tuple_from_type_list<filtered_pattern>::type typedef typename pseudo_tuple_from_type_list<filtered_pattern>::type
tuple_type; tuple_type;
...@@ -72,9 +72,9 @@ struct invoke_policy_base { ...@@ -72,9 +72,9 @@ struct invoke_policy_base {
// covers wildcard_position::multiple and wildcard_position::in_between // covers wildcard_position::multiple and wildcard_position::in_between
template<wildcard_position, class Pattern, class FilteredPattern> template<wildcard_position, class Pattern, class FilteredPattern>
struct invoke_policy_impl : invoke_policy_base<FilteredPattern> { struct invoke_util_impl : invoke_util_base<FilteredPattern> {
typedef invoke_policy_base<FilteredPattern> super; typedef invoke_util_base<FilteredPattern> super;
template<class Tuple> template<class Tuple>
static bool can_invoke(const std::type_info& type_token, static bool can_invoke(const std::type_info& type_token,
...@@ -113,12 +113,12 @@ struct invoke_policy_impl : invoke_policy_base<FilteredPattern> { ...@@ -113,12 +113,12 @@ struct invoke_policy_impl : invoke_policy_base<FilteredPattern> {
}; };
template<> template<>
struct invoke_policy_impl<wildcard_position::nil, struct invoke_util_impl<wildcard_position::nil,
util::empty_type_list, util::empty_type_list,
util::empty_type_list > util::empty_type_list >
: invoke_policy_base<util::empty_type_list> { : invoke_util_base<util::empty_type_list> {
typedef invoke_policy_base<util::empty_type_list> super; typedef invoke_util_base<util::empty_type_list> super;
template<typename PtrType, class Tuple> template<typename PtrType, class Tuple>
static bool prepare_invoke(typename super::tuple_type&, static bool prepare_invoke(typename super::tuple_type&,
...@@ -137,12 +137,12 @@ struct invoke_policy_impl<wildcard_position::nil, ...@@ -137,12 +137,12 @@ struct invoke_policy_impl<wildcard_position::nil,
}; };
template<class Pattern, typename... Ts> template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::nil, struct invoke_util_impl<wildcard_position::nil,
Pattern, Pattern,
util::type_list<Ts...>> util::type_list<Ts...>>
: invoke_policy_base<util::type_list<Ts...>> { : invoke_util_base<util::type_list<Ts...>> {
typedef invoke_policy_base<util::type_list<Ts...>> super; typedef invoke_util_base<util::type_list<Ts...>> super;
typedef typename super::tuple_type tuple_type; typedef typename super::tuple_type tuple_type;
...@@ -242,12 +242,12 @@ struct invoke_policy_impl<wildcard_position::nil, ...@@ -242,12 +242,12 @@ struct invoke_policy_impl<wildcard_position::nil,
}; };
template<> template<>
struct invoke_policy_impl<wildcard_position::leading, struct invoke_util_impl<wildcard_position::leading,
util::type_list<anything>, util::type_list<anything>,
util::empty_type_list> util::empty_type_list>
: invoke_policy_base<util::empty_type_list> { : invoke_util_base<util::empty_type_list> {
typedef invoke_policy_base<util::empty_type_list> super; typedef invoke_util_base<util::empty_type_list> super;
template<class Tuple> template<class Tuple>
static inline bool can_invoke(const std::type_info&, const Tuple&) { static inline bool can_invoke(const std::type_info&, const Tuple&) {
...@@ -266,12 +266,12 @@ struct invoke_policy_impl<wildcard_position::leading, ...@@ -266,12 +266,12 @@ struct invoke_policy_impl<wildcard_position::leading,
}; };
template<class Pattern, typename... Ts> template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::trailing, struct invoke_util_impl<wildcard_position::trailing,
Pattern, Pattern,
util::type_list<Ts...>> util::type_list<Ts...>>
: invoke_policy_base<util::type_list<Ts...>> { : invoke_util_base<util::type_list<Ts...>> {
typedef invoke_policy_base<util::type_list<Ts...>> super; typedef invoke_util_base<util::type_list<Ts...>> super;
template<class Tuple> template<class Tuple>
static bool can_invoke(const std::type_info& arg_types, static bool can_invoke(const std::type_info& arg_types,
...@@ -308,12 +308,12 @@ struct invoke_policy_impl<wildcard_position::trailing, ...@@ -308,12 +308,12 @@ struct invoke_policy_impl<wildcard_position::trailing,
}; };
template<class Pattern, typename... Ts> template<class Pattern, typename... Ts>
struct invoke_policy_impl<wildcard_position::leading, struct invoke_util_impl<wildcard_position::leading,
Pattern, Pattern,
util::type_list<Ts...>> util::type_list<Ts...>>
: invoke_policy_base<util::type_list<Ts...>> { : invoke_util_base<util::type_list<Ts...>> {
typedef invoke_policy_base<util::type_list<Ts...>> super; typedef invoke_util_base<util::type_list<Ts...>> super;
template<class Tuple> template<class Tuple>
static bool can_invoke(const std::type_info& arg_types, static bool can_invoke(const std::type_info& arg_types,
...@@ -352,8 +352,8 @@ struct invoke_policy_impl<wildcard_position::leading, ...@@ -352,8 +352,8 @@ struct invoke_policy_impl<wildcard_position::leading,
}; };
template<class Pattern> template<class Pattern>
struct invoke_policy struct invoke_util
: invoke_policy_impl< : invoke_util_impl<
get_wildcard_position<Pattern>(), get_wildcard_position<Pattern>(),
Pattern, Pattern,
typename util::tl_filter_not_type<Pattern, anything>::type> { typename util::tl_filter_not_type<Pattern, anything>::type> {
...@@ -507,7 +507,7 @@ Result unroll_expr(PPFPs& fs, ...@@ -507,7 +507,7 @@ Result unroll_expr(PPFPs& fs,
auto& f = get<N>(fs); auto& f = get<N>(fs);
typedef typename util::rm_const_and_ref<decltype(f)>::type Fun; typedef typename util::rm_const_and_ref<decltype(f)>::type Fun;
typedef typename Fun::pattern_type pattern_type; typedef typename Fun::pattern_type pattern_type;
typedef detail::invoke_policy<pattern_type> policy; typedef detail::invoke_util<pattern_type> policy;
typename policy::tuple_type targs; typename policy::tuple_type targs;
if (policy::prepare_invoke(targs, type_token, is_dynamic, ptr, tup)) { if (policy::prepare_invoke(targs, type_token, is_dynamic, ptr, tup)) {
auto is = util::get_indices(targs); auto is = util::get_indices(targs);
...@@ -536,7 +536,7 @@ inline bool can_unroll_expr(PPFPs& fs, ...@@ -536,7 +536,7 @@ inline bool can_unroll_expr(PPFPs& fs,
auto& f = get<N>(fs); auto& f = get<N>(fs);
typedef typename util::rm_const_and_ref<decltype(f)>::type Fun; typedef typename util::rm_const_and_ref<decltype(f)>::type Fun;
typedef typename Fun::pattern_type pattern_type; typedef typename Fun::pattern_type pattern_type;
typedef detail::invoke_policy<pattern_type> policy; typedef detail::invoke_util<pattern_type> policy;
return policy::can_invoke(arg_types, tup); return policy::can_invoke(arg_types, tup);
} }
...@@ -556,7 +556,7 @@ inline std::uint64_t calc_bitmask(PPFPs& fs, ...@@ -556,7 +556,7 @@ inline std::uint64_t calc_bitmask(PPFPs& fs,
auto& f = get<N>(fs); auto& f = get<N>(fs);
typedef typename util::rm_const_and_ref<decltype(f)>::type Fun; typedef typename util::rm_const_and_ref<decltype(f)>::type Fun;
typedef typename Fun::pattern_type pattern_type; typedef typename Fun::pattern_type pattern_type;
typedef detail::invoke_policy<pattern_type> policy; typedef detail::invoke_util<pattern_type> policy;
std::uint64_t result = policy::can_invoke(tinf, tup) ? (0x01 << N) : 0x00; std::uint64_t result = policy::can_invoke(tinf, tup) ? (0x01 << N) : 0x00;
return result | calc_bitmask(fs, long_constant<N-1l>(), tinf, tup); return result | calc_bitmask(fs, long_constant<N-1l>(), tinf, tup);
} }
......
...@@ -34,7 +34,9 @@ ...@@ -34,7 +34,9 @@
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#include "cppa/on.hpp"
#include "cppa/match_expr.hpp" #include "cppa/match_expr.hpp"
#include "cppa/message_id.hpp"
#include "cppa/partial_function.hpp" #include "cppa/partial_function.hpp"
namespace cppa { namespace cppa {
...@@ -56,7 +58,9 @@ class continue_helper { ...@@ -56,7 +58,9 @@ 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) {
}
inline message_id get_message_id() const { inline message_id get_message_id() const {
return m_mid; return m_mid;
...@@ -78,12 +82,14 @@ class message_future { ...@@ -78,12 +82,14 @@ class message_future {
message_future() = delete; message_future() = delete;
inline continue_helper then(const partial_function& pfun) { inline continue_helper then(const behavior&) {
//FIXME
return message_id{};
} }
inline continue_helper await(const partial_function& pfun) { inline continue_helper await(const behavior&) {
//FIXME
return message_id{};
} }
/** /**
...@@ -113,7 +119,7 @@ class message_future { ...@@ -113,7 +119,7 @@ class message_future {
continue_helper continue_helper
>::type >::type
then(Fs... fs) { then(Fs... fs) {
return then(fs2bhvr(std::move(fs)...)); return then(partial_function{(on_arg_match >> std::move(fs))...});
} }
/** /**
...@@ -124,7 +130,7 @@ class message_future { ...@@ -124,7 +130,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) {
await(fs2bhvr({std::move(fs)...})); await(partial_function{(on_arg_match >> std::move(fs))...});
} }
/** /**
...@@ -142,8 +148,6 @@ class message_future { ...@@ -142,8 +148,6 @@ class message_future {
message_id m_mid; message_id m_mid;
local_actor* self; local_actor* self;
partial_function fs2bhvr(partial_function pf);
inline void check_consistency() { } inline void check_consistency() { }
}; };
...@@ -193,17 +197,6 @@ inline sync_handle_helper handle_response(const message_future& f) { ...@@ -193,17 +197,6 @@ inline sync_handle_helper handle_response(const message_future& f) {
return {f}; return {f};
} }
/**
* @brief Handles a synchronous response message in an event-based way.
* @param handle A future for a synchronous response.
* @throws std::logic_error if @p handle is not valid or if the actor
* already received the response for @p handle
* @relates message_future
*/
inline sync_receive_helper receive_response(const message_future& f) {
return {f};
}
} // namespace cppa } // namespace cppa
#endif // CPPA_MESSAGE_FUTURE_HPP #endif // CPPA_MESSAGE_FUTURE_HPP
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_OPENCL_ACTOR_FACADE_HPP #ifndef CPPA_OPENCL_ACTOR_FACADE_HPP
#define CPPA_OPENCL_ACTOR_FACADE_HPP #define CPPA_OPENCL_ACTOR_FACADE_HPP
...@@ -55,34 +54,35 @@ ...@@ -55,34 +54,35 @@
#include "cppa/detail/scheduled_actor_dummy.hpp" #include "cppa/detail/scheduled_actor_dummy.hpp"
namespace cppa { namespace opencl { namespace cppa {
namespace opencl {
class opencl_metainfo; class opencl_metainfo;
template<typename Signature> template <typename Signature>
class actor_facade; class actor_facade;
template<typename Ret, typename... Args> template <typename Ret, typename... Args>
class actor_facade<Ret(Args...)> : public actor { class actor_facade<Ret(Args...)> : public abstract_actor {
friend class command<actor_facade, Ret>; friend class command<actor_facade, Ret>;
public: public:
typedef cow_tuple<typename util::rm_const_and_ref<Args>::type...> args_tuple; typedef cow_tuple<typename util::rm_const_and_ref<Args>::type...>
args_tuple;
typedef std::function<optional<args_tuple>(any_tuple)> arg_mapping; typedef std::function<optional<args_tuple>(any_tuple)> arg_mapping;
typedef std::function<any_tuple(Ret&)> result_mapping; typedef std::function<any_tuple(Ret&)> result_mapping;
static intrusive_ptr<actor_facade> create(const program& prog, static intrusive_ptr<actor_facade>
const char* kernel_name, create(const program& prog, const char* kernel_name, arg_mapping map_args,
arg_mapping map_args, result_mapping map_result, const dim_vec& global_dims,
result_mapping map_result, const dim_vec& offsets, const dim_vec& local_dims) {
const dim_vec& global_dims,
const dim_vec& offsets,
const dim_vec& local_dims) {
if (global_dims.empty()) { if (global_dims.empty()) {
auto str = "OpenCL kernel needs at least 1 global dimension."; auto str = "OpenCL kernel needs at least 1 global dimension.";
CPPA_LOGM_ERROR(detail::demangle(typeid(actor_facade)).c_str(), str); CPPA_LOGM_ERROR(detail::demangle(typeid(actor_facade)).c_str(),
str);
throw std::runtime_error(str); throw std::runtime_error(str);
} }
auto check_vec = [&](const dim_vec& vec, const char* name) { auto check_vec = [&](const dim_vec& vec, const char* name) {
...@@ -90,30 +90,27 @@ class actor_facade<Ret(Args...)> : public actor { ...@@ -90,30 +90,27 @@ class actor_facade<Ret(Args...)> : public actor {
std::ostringstream oss; std::ostringstream oss;
oss << name << " vector is not empty, but " oss << name << " vector is not empty, but "
<< "its size differs from global dimensions vector's size"; << "its size differs from global dimensions vector's size";
CPPA_LOGM_ERROR(detail::demangle<actor_facade>().c_str(), oss.str()); CPPA_LOGM_ERROR(detail::demangle<actor_facade>().c_str(),
oss.str());
throw std::runtime_error(oss.str()); throw std::runtime_error(oss.str());
} }
}; };
check_vec(offsets, "offsets"); check_vec(offsets, "offsets");
check_vec(local_dims, "local dimensions"); check_vec(local_dims, "local dimensions");
cl_int err{0}; cl_int err{ 0 };
kernel_ptr kernel; kernel_ptr kernel;
kernel.adopt(clCreateKernel(prog.m_program.get(), kernel.adopt(clCreateKernel(prog.m_program.get(), kernel_name, &err));
kernel_name,
&err));
if (err != CL_SUCCESS) { if (err != CL_SUCCESS) {
std::ostringstream oss; std::ostringstream oss;
oss << "clCreateKernel: " << get_opencl_error(err); oss << "clCreateKernel: " << get_opencl_error(err);
CPPA_LOGM_ERROR(detail::demangle<actor_facade>().c_str(), oss.str()); CPPA_LOGM_ERROR(detail::demangle<actor_facade>().c_str(),
oss.str());
throw std::runtime_error(oss.str()); throw std::runtime_error(oss.str());
} }
return new actor_facade<Ret (Args...)>{prog, return new actor_facade<Ret(Args...)>{
kernel, prog, kernel, global_dims, offsets,
global_dims, local_dims, std::move(map_args), std::move(map_result)
offsets, };
local_dims,
std::move(map_args),
std::move(map_result)};
} }
void enqueue(const message_header& hdr, any_tuple msg) override { void enqueue(const message_header& hdr, any_tuple msg) override {
...@@ -124,47 +121,38 @@ class actor_facade<Ret(Args...)> : public actor { ...@@ -124,47 +121,38 @@ class actor_facade<Ret(Args...)> : public actor {
private: private:
actor_facade(const program& prog, actor_facade(const program& prog, kernel_ptr kernel,
kernel_ptr kernel,
const dim_vec& global_dimensions, const dim_vec& global_dimensions,
const dim_vec& global_offsets, const dim_vec& global_offsets, const dim_vec& local_dimensions,
const dim_vec& local_dimensions, arg_mapping map_args, result_mapping map_result)
arg_mapping map_args, : m_kernel(kernel), m_program(prog.m_program),
result_mapping map_result) m_context(prog.m_context), m_queue(prog.m_queue),
: m_kernel(kernel) m_global_dimensions(global_dimensions),
, m_program(prog.m_program) m_global_offsets(global_offsets),
, m_context(prog.m_context) m_local_dimensions(local_dimensions), m_map_args(std::move(map_args)),
, m_queue(prog.m_queue) m_map_result(std::move(map_result)) {
, m_global_dimensions(global_dimensions)
, m_global_offsets(global_offsets)
, m_local_dimensions(local_dimensions)
, m_map_args(std::move(map_args))
, m_map_result(std::move(map_result))
{
CPPA_LOG_TRACE("id: " << this->id()); CPPA_LOG_TRACE("id: " << this->id());
} }
template<long... Is> template <long... Is>
void enqueue_impl(const actor_ptr& sender, void enqueue_impl(const actor_ptr& sender, any_tuple msg, message_id id,
any_tuple msg,
message_id id,
util::int_list<Is...>) { util::int_list<Is...>) {
auto opt = m_map_args(std::move(msg)); auto opt = m_map_args(std::move(msg));
if (opt) { if (opt) {
response_handle handle{this, sender, id.response_id()}; response_handle handle{ this, sender, id.response_id() };
size_t ret_size = std::accumulate(m_global_dimensions.begin(), size_t ret_size = std::accumulate(m_global_dimensions.begin(),
m_global_dimensions.end(), m_global_dimensions.end(), 1,
1, std::multiplies<size_t>{}); std::multiplies<size_t>{});
std::vector<mem_ptr> arguments; std::vector<mem_ptr> arguments;
add_arguments_to_kernel<Ret>(arguments, add_arguments_to_kernel<Ret>(arguments, ret_size,
ret_size,
get_ref<Is>(*opt)...); get_ref<Is>(*opt)...);
auto cmd = make_counted<command<actor_facade, Ret>>(handle, auto cmd = make_counted<command<actor_facade, Ret>>(
this, handle, this, std::move(arguments));
std::move(arguments));
cmd->enqueue(); cmd->enqueue();
} else {
CPPA_LOGMF(CPPA_ERROR, this,
"actor_facade::enqueue() tuple_cast failed.");
} }
else { CPPA_LOGMF(CPPA_ERROR, this, "actor_facade::enqueue() tuple_cast failed."); }
} }
typedef std::vector<mem_ptr> args_vec; typedef std::vector<mem_ptr> args_vec;
...@@ -180,36 +168,30 @@ class actor_facade<Ret(Args...)> : public actor { ...@@ -180,36 +168,30 @@ class actor_facade<Ret(Args...)> : public actor {
result_mapping m_map_result; result_mapping m_map_result;
void add_arguments_to_kernel_rec(args_vec& arguments) { void add_arguments_to_kernel_rec(args_vec& arguments) {
cl_int err{0}; cl_int err{ 0 };
for(size_t i = 1; i < arguments.size(); ++i) { for (size_t i = 1; i < arguments.size(); ++i) {
err = clSetKernelArg(m_kernel.get(), err = clSetKernelArg(m_kernel.get(), (i - 1), sizeof(cl_mem),
(i-1),
sizeof(cl_mem),
static_cast<void*>(&arguments[i])); static_cast<void*>(&arguments[i]));
CPPA_LOG_ERROR_IF(err != CL_SUCCESS, CPPA_LOG_ERROR_IF(err != CL_SUCCESS,
"clSetKernelArg: " << get_opencl_error(err)); "clSetKernelArg: " << get_opencl_error(err));
} }
err = clSetKernelArg(m_kernel.get(), err = clSetKernelArg(m_kernel.get(), arguments.size() - 1,
arguments.size()-1, sizeof(cl_mem), static_cast<void*>(&arguments[0]));
sizeof(cl_mem),
static_cast<void*>(&arguments[0]));
CPPA_LOG_ERROR_IF(err != CL_SUCCESS, CPPA_LOG_ERROR_IF(err != CL_SUCCESS,
"clSetKernelArg: " << get_opencl_error(err)); "clSetKernelArg: " << get_opencl_error(err));
} }
template<typename T0, typename... Ts> template <typename T0, typename... Ts>
void add_arguments_to_kernel_rec(args_vec& arguments, void add_arguments_to_kernel_rec(args_vec& arguments, T0& arg0,
T0& arg0, Ts&... args) { Ts&... args) {
cl_int err{0}; cl_int err{ 0 };
auto buf = clCreateBuffer(m_context.get(), auto buf = clCreateBuffer(
CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, m_context.get(), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
sizeof(typename T0::value_type) * arg0.size(), sizeof(typename T0::value_type) * arg0.size(), arg0.data(), &err);
arg0.data(),
&err);
if (err != CL_SUCCESS) { if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, this, "clCreateBuffer: " << get_opencl_error(err)); CPPA_LOGMF(CPPA_ERROR, this,
} "clCreateBuffer: " << get_opencl_error(err));
else { } else {
mem_ptr tmp; mem_ptr tmp;
tmp.adopt(std::move(buf)); tmp.adopt(std::move(buf));
arguments.push_back(tmp); arguments.push_back(tmp);
...@@ -217,21 +199,18 @@ class actor_facade<Ret(Args...)> : public actor { ...@@ -217,21 +199,18 @@ class actor_facade<Ret(Args...)> : public actor {
} }
} }
template<typename R, typename... Ts> template <typename R, typename... Ts>
void add_arguments_to_kernel(args_vec& arguments, void add_arguments_to_kernel(args_vec& arguments, size_t ret_size,
size_t ret_size,
Ts&&... args) { Ts&&... args) {
arguments.clear(); arguments.clear();
cl_int err{0}; cl_int err{ 0 };
auto buf = clCreateBuffer(m_context.get(), auto buf = clCreateBuffer(m_context.get(), CL_MEM_WRITE_ONLY,
CL_MEM_WRITE_ONLY,
sizeof(typename R::value_type) * ret_size, sizeof(typename R::value_type) * ret_size,
nullptr, nullptr, &err);
&err);
if (err != CL_SUCCESS) { if (err != CL_SUCCESS) {
CPPA_LOGMF(CPPA_ERROR, this, "clCreateBuffer: " << get_opencl_error(err)); CPPA_LOGMF(CPPA_ERROR, this,
} "clCreateBuffer: " << get_opencl_error(err));
else { } else {
mem_ptr tmp; mem_ptr tmp;
tmp.adopt(std::move(buf)); tmp.adopt(std::move(buf));
arguments.push_back(tmp); arguments.push_back(tmp);
...@@ -241,6 +220,7 @@ class actor_facade<Ret(Args...)> : public actor { ...@@ -241,6 +220,7 @@ class actor_facade<Ret(Args...)> : public actor {
}; };
} } // namespace cppa::opencl } // namespace opencl
} // namespace cppa
#endif // CPPA_OPENCL_ACTOR_FACADE_HPP #endif // CPPA_OPENCL_ACTOR_FACADE_HPP
...@@ -33,10 +33,14 @@ ...@@ -33,10 +33,14 @@
#include "cppa/policy/no_resume.hpp" #include "cppa/policy/no_resume.hpp"
#include "cppa/policy/prioritizing.hpp" #include "cppa/policy/prioritizing.hpp"
#include "cppa/policy/no_scheduling.hpp"
#include "cppa/policy/invoke_policy.hpp"
#include "cppa/policy/nestable_invoke.hpp" #include "cppa/policy/nestable_invoke.hpp"
#include "cppa/policy/not_prioritizing.hpp"
#include "cppa/policy/sequential_invoke.hpp" #include "cppa/policy/sequential_invoke.hpp"
#include "cppa/policy/event_based_resume.hpp" #include "cppa/policy/event_based_resume.hpp"
#include "cppa/policy/invoke_policy_base.hpp" #include "cppa/policy/middleman_scheduling.hpp"
#include "cppa/policy/cooperative_scheduling.hpp"
#include "cppa/policy/context_switching_resume.hpp" #include "cppa/policy/context_switching_resume.hpp"
#endif // CPPA_POLICY_HPP #endif // CPPA_POLICY_HPP
...@@ -27,19 +27,26 @@ ...@@ -27,19 +27,26 @@
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. * * along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_CONTEXT_SWITCHING_ACTOR_HPP #ifndef CPPA_CONTEXT_SWITCHING_ACTOR_HPP
#define CPPA_CONTEXT_SWITCHING_ACTOR_HPP #define CPPA_CONTEXT_SWITCHING_ACTOR_HPP
#include "cppa/config.hpp" #include "cppa/config.hpp"
#include "cppa/resumable.hpp"
#include "cppa/actor_state.hpp"
#include "cppa/mailbox_element.hpp" #include "cppa/mailbox_element.hpp"
#include "cppa/util/fiber.hpp" #include "cppa/util/fiber.hpp"
#include "cppa/policy/resume_policy.hpp"
#include "cppa/detail/yield_interface.hpp" #include "cppa/detail/yield_interface.hpp"
namespace cppa { class local_actor; } namespace cppa {
class local_actor;
}
namespace cppa { namespace policy { namespace cppa {
namespace policy {
/** /**
* @brief Context-switching actor implementation. * @brief Context-switching actor implementation.
...@@ -49,9 +56,57 @@ class context_switching_resume { ...@@ -49,9 +56,57 @@ class context_switching_resume {
public: public:
// required by util::fiber
static void trampoline(void* _this);
// Base must be a mailbox-based actor
template<class Base>
struct mixin : Base, resumable {
template<typename... Ts>
mixin(Ts&&... args)
: Base(std::forward<Ts>(args)...)
, m_fiber(context_switching_resume::trampoline,
static_cast<blocking_untyped_actor*>(this)) { }
template<class Actor, typename F> resumable::resume_result resume(util::fiber* from) override {
CPPA_REQUIRE(from != nullptr);
using namespace detail;
for (;;) {
switch (call(&m_fiber, from)) {
case yield_state::done: {
CPPA_REQUIRE(next_job == nullptr);
return resumable::done;
}
case yield_state::ready: { break; }
case yield_state::blocked: {
CPPA_REQUIRE(next_job == nullptr);
CPPA_REQUIRE(m_chained_actor == nullptr);
switch (this->cas_state(actor_state::about_to_block,
actor_state::blocked)) {
case actor_state::ready: {
// restore variables
CPPA_REQUIRE(next_job == nullptr);
break;
}
case actor_state::blocked: {
// wait until someone re-schedules that actor
return resumable::resume_later;
}
default: { CPPA_CRITICAL("illegal yield result"); }
}
break;
}
default: { CPPA_CRITICAL("illegal state"); }
}
}
}
util::fiber m_fiber;
};
template <class Actor, typename F>
void fetch_messages(Actor* self, F cb) { void fetch_messages(Actor* self, F cb) {
auto e = self->m_mailbox.try_pop(); auto e = self->m_mailbox.try_pop();
while (e == nullptr) { while (e == nullptr) {
...@@ -63,7 +118,8 @@ class context_switching_resume { ...@@ -63,7 +118,8 @@ class context_switching_resume {
self->set_state(actor_state::ready); self->set_state(actor_state::ready);
} }
// wait until actor becomes rescheduled // wait until actor becomes rescheduled
else detail::yield(detail::yield_state::blocked); else
detail::yield(detail::yield_state::blocked);
} }
} }
// ok, we have at least one message // ok, we have at least one message
...@@ -73,7 +129,7 @@ class context_switching_resume { ...@@ -73,7 +129,7 @@ class context_switching_resume {
} }
} }
template<class Actor, typename F> template <class Actor, typename F>
void try_fetch_messages(Actor* self, F cb) { void try_fetch_messages(Actor* self, F cb) {
auto e = self->m_mailbox.try_pop(); auto e = self->m_mailbox.try_pop();
while (e) { while (e) {
...@@ -83,57 +139,33 @@ class context_switching_resume { ...@@ -83,57 +139,33 @@ class context_switching_resume {
} }
template<class Actor> template<class Actor>
resume_result resume(Actor* self, util::fiber* from) { void await_data(Actor* self) {
CPPA_LOG_TRACE("state = " << static_cast<int>(self->state())); while (self->m_mailbox.can_fetch_more() == false) {
CPPA_REQUIRE(from != nullptr); self->set_state(actor_state::about_to_block);
CPPA_REQUIRE(next_job == nullptr); // make sure mailbox is empty
using namespace detail; if (self->m_mailbox.can_fetch_more()) {
for (;;) { // someone preempt us => continue
switch (call(&m_fiber, from)) { self->set_state(actor_state::ready);
case yield_state::done: {
CPPA_REQUIRE(next_job == nullptr);
return resume_result::actor_done;
}
case yield_state::ready: {
break;
}
case yield_state::blocked: {
CPPA_REQUIRE(next_job == nullptr);
CPPA_REQUIRE(m_chained_actor == nullptr);
switch (compare_exchange_state(actor_state::about_to_block,
actor_state::blocked)) {
case actor_state::ready: {
// restore variables
CPPA_REQUIRE(next_job == nullptr);
break;
}
case actor_state::blocked: {
// wait until someone re-schedules that actor
return resume_result::actor_blocked;
}
default: {
CPPA_CRITICAL("illegal yield result");
}
}
break;
}
default: {
CPPA_CRITICAL("illegal state");
} }
// wait until actor becomes rescheduled
else detail::yield(detail::yield_state::blocked);
} }
} }
template<class Actor, typename AbsTimeout>
bool await_data(Actor* self, const AbsTimeout&) {
await_data(self);
return true;
} }
private: private:
// required by util::fiber
static void trampoline(void* _this);
// members // members
util::fiber m_fiber; util::fiber m_fiber;
}; };
} } // namespace cppa::policy } // namespace policy
} // namespace cppa
#endif // CPPA_CONTEXT_SWITCHING_ACTOR_HPP #endif // CPPA_CONTEXT_SWITCHING_ACTOR_HPP
...@@ -31,6 +31,17 @@ ...@@ -31,6 +31,17 @@
#ifndef CPPA_COOPERATIVE_SCHEDULING_HPP #ifndef CPPA_COOPERATIVE_SCHEDULING_HPP
#define CPPA_COOPERATIVE_SCHEDULING_HPP #define CPPA_COOPERATIVE_SCHEDULING_HPP
#include <atomic>
#include "cppa/any_tuple.hpp"
#include "cppa/resumable.hpp"
#include "cppa/actor_state.hpp"
#include "cppa/message_header.hpp"
#include "cppa/detail/yield_interface.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace cppa { namespace policy { namespace cppa { namespace policy {
class cooperative_scheduling { class cooperative_scheduling {
...@@ -49,12 +60,12 @@ class cooperative_scheduling { ...@@ -49,12 +60,12 @@ class cooperative_scheduling {
// this does return nullptr // this does return nullptr
template<class Actor, typename F> template<class Actor, typename F>
void fetch_messages(Actor* self, F cb) { void fetch_messages(Actor* self, F cb) {
auto e = self->m_mailbox.try_pop(); auto e = self->mailbox().try_pop();
while (e == nullptr) { while (e == nullptr) {
if (self->m_mailbox.can_fetch_more() == false) { if (self->mailbox().can_fetch_more() == false) {
self->set_state(actor_state::about_to_block); self->set_state(actor_state::about_to_block);
// make sure mailbox is empty // make sure mailbox is empty
if (self->m_mailbox.can_fetch_more()) { if (self->mailbox().can_fetch_more()) {
// someone preempt us => continue // someone preempt us => continue
self->set_state(actor_state::ready); self->set_state(actor_state::ready);
} }
...@@ -65,7 +76,7 @@ class cooperative_scheduling { ...@@ -65,7 +76,7 @@ class cooperative_scheduling {
// ok, we have at least one message // ok, we have at least one message
while (e) { while (e) {
cb(e); cb(e);
e = self->m_mailbox.try_pop(); e = self->mailbox().try_pop();
} }
} }
...@@ -76,6 +87,59 @@ class cooperative_scheduling { ...@@ -76,6 +87,59 @@ class cooperative_scheduling {
fetch_messages(self, cb); fetch_messages(self, cb);
} }
template<class Actor>
inline void launch(Actor*) {
static_cast<void>(m_hidden);
}
template<class Actor>
void enqueue(Actor* self, const message_header& hdr, any_tuple& msg) {
auto e = self->new_mailbox_element(hdr, std::move(msg));
switch (self->mailbox().enqueue(e)) {
case intrusive::first_enqueued: {
auto state = self->state();
auto set_ready = [&]() -> bool {
auto s = self->cas_state(state, actor_state::ready);
return s == actor_state::ready;
};
for (;;) {
switch (state) {
case actor_state::blocked: {
if (set_ready()) {
CPPA_REQUIRE(m_scheduler != nullptr);
//m_scheduler->enqueue(this);
return;
}
break;
}
case actor_state::about_to_block: {
if (set_ready()) {
return;
}
break;
}
default: return;
}
}
break;
}
case intrusive::queue_closed: {
if (hdr.id.is_request()) {
//FIXME
//detail::sync_request_bouncer f{exit_reason()};
//f(hdr.sender, hdr.id);
}
break;
}
default: break;
}
}
private:
// denotes whether this actor is ignored by await_all_actors_done()
bool m_hidden;
}; };
} } // namespace cppa::policy } } // namespace cppa::policy
......
...@@ -40,100 +40,59 @@ ...@@ -40,100 +40,59 @@
#include "cppa/config.hpp" #include "cppa/config.hpp"
#include "cppa/extend.hpp" #include "cppa/extend.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/scheduled_actor.hpp" #include "cppa/actor_state.hpp"
#include "cppa/policy/resume_policy.hpp"
namespace cppa { namespace policy { namespace cppa { namespace policy {
/**
* @brief Base class for all event-based actor implementations.
* @extends scheduled_actor
*/
class event_based_resume { class event_based_resume {
public: public:
template<class Actor> // Base must be a mailbox-based actor
void await_data(Actor*) { template<class Base>
static_assert(std::is_same<Actor, Actor>::value == false, struct mixin : Base, resumable {
"The event_based_resume policy cannot be used "
"to implement blocking actors");
}
template<class Actor>
bool await_data(Actor*, const util::duration&) {
static_assert(std::is_same<Actor, Actor>::value == false,
"The event_based_resume policy cannot be used "
"to implement blocking actors");
}
template<class Actor>
timeout_type init_timeout(Actor* self, const util::duration& rel_time) {
// request explicit timeout message
self->request_timeout(rel_time);
return 0; // return some dummy value
}
template<class Actor, typename F>
void fetch_messages(Actor* self, F cb) {
auto e = self->m_mailbox.try_pop();
while (e) {
cb(e);
e = self->m_mailbox.try_pop();
}
}
template<class Actor, typename F>
inline void fetch_messages(Actor* self, F cb, timeout_type) {
// a call to this call is always preceded by init_timeout,
// which will trigger a timeout message
fetch_messages(self, cb);
}
template<class Actor, typename F> template<typename... Ts>
void try_fetch_messages(Actor* self, F cb) { mixin(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
// try_fetch and fetch have the same semantics for event-based actors
fetch_messages(self, cb);
}
template<class Actor> resumable::resume_result resume(util::fiber*) override {
resume_result resume(Actor* self, util::fiber*) { CPPA_LOG_TRACE("id = " << this->id()
CPPA_LOG_TRACE("id = " << self->id() << ", state = " << static_cast<int>(this->state()));
<< ", state = " << static_cast<int>(self->state())); CPPA_REQUIRE( this->state() == actor_state::ready
CPPA_REQUIRE( self->state() == actor_state::ready || this->state() == actor_state::pending);
|| self->state() == actor_state::pending);
auto done_cb = [&]() -> bool { auto done_cb = [&]() -> bool {
CPPA_LOG_TRACE(""); CPPA_LOG_TRACE("");
if (self->exit_reason() == self->exit_reason::not_exited) { if (this->exit_reason() == exit_reason::not_exited) {
if (self->planned_exit_reason() == self->exit_reason::not_exited) { if (this->planned_exit_reason() == exit_reason::not_exited) {
self->planned_exit_reason(exit_reason::normal); this->planned_exit_reason(exit_reason::normal);
} }
self->on_exit(); this->on_exit();
if (!m_bhvr_stack.empty()) { if (!this->bhvr_stack().empty()) {
planned_exit_reason(exit_reason::not_exited); this->planned_exit_reason(exit_reason::not_exited);
return false; // on_exit did set a new behavior return false; // on_exit did set a new behavior
} }
cleanup(planned_exit_reason()); this->cleanup(this->planned_exit_reason());
} }
set_state(actor_state::done); this->set_state(actor_state::done);
m_bhvr_stack.clear(); this->bhvr_stack().clear();
m_bhvr_stack.cleanup(); this->bhvr_stack().cleanup();
on_exit(); this->on_exit();
CPPA_REQUIRE(next_job == nullptr);
return true; return true;
}; };
CPPA_REQUIRE(next_job == nullptr); CPPA_REQUIRE(next_job == nullptr);
try { try {
//auto e = m_mailbox.try_pop(); //auto e = m_mailbox.try_pop();
for (auto e = m_mailbox.try_pop(); ; e = m_mailbox.try_pop()) { for (auto e = this->m_mailbox.try_pop(); ; e = this->m_mailbox.try_pop()) {
//e = m_mailbox.try_pop(); //e = m_mailbox.try_pop();
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");
set_state(actor_state::about_to_block); this->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) {
switch (compare_exchange_state(actor_state::about_to_block, switch (this->cas_state(actor_state::about_to_block,
actor_state::blocked)) { actor_state::blocked)) {
case actor_state::ready: case actor_state::ready:
// interrupted by arriving message // interrupted by arriving message
...@@ -145,7 +104,7 @@ class event_based_resume { ...@@ -145,7 +104,7 @@ class event_based_resume {
case actor_state::blocked: case actor_state::blocked:
CPPA_LOGMF(CPPA_DEBUG, self, "set state successfully to blocked"); CPPA_LOGMF(CPPA_DEBUG, self, "set state successfully to blocked");
// done setting actor to blocked // done setting actor to blocked
return resume_result::actor_blocked; return resumable::resume_later;
default: default:
CPPA_LOGMF(CPPA_ERROR, self, "invalid state"); CPPA_LOGMF(CPPA_ERROR, self, "invalid state");
CPPA_CRITICAL("invalid state"); CPPA_CRITICAL("invalid state");
...@@ -154,49 +113,65 @@ class event_based_resume { ...@@ -154,49 +113,65 @@ class event_based_resume {
else { else {
CPPA_LOGMF(CPPA_DEBUG, self, "switched back to ready: " CPPA_LOGMF(CPPA_DEBUG, self, "switched back to ready: "
"mailbox can fetch more"); "mailbox can fetch more");
set_state(actor_state::ready); this->set_state(actor_state::ready);
CPPA_REQUIRE(m_chained_actor == nullptr);
} }
} }
/*
else { else {
CPPA_LOGMF(CPPA_DEBUG, self, "try to invoke message: " << to_string(e->msg)); if (this->bhvr_stack().invoke(m_recv_policy, this, e)) {
if (m_bhvr_stack.invoke(m_recv_policy, this, e)) {
CPPA_LOG_DEBUG_IF(m_chained_actor, CPPA_LOG_DEBUG_IF(m_chained_actor,
"set actor with ID " "set actor with ID "
<< m_chained_actor->id() << m_chained_actor->id()
<< " as successor"); << " as successor");
if (m_bhvr_stack.empty() && done_cb()) { if (this->bhvr_stack().empty() && done_cb()) {
CPPA_LOGMF(CPPA_DEBUG, self, "behavior stack empty"); CPPA_LOGMF(CPPA_DEBUG, self, "behavior stack empty");
return resume_result::actor_done; return resume_result::actor_done;
} }
m_bhvr_stack.cleanup(); this->bhvr_stack().cleanup();
} }
} }
*/
} }
} }
catch (actor_exited& what) { catch (actor_exited& what) {
CPPA_LOG_INFO("actor died because of exception: actor_exited, " CPPA_LOG_INFO("actor died because of exception: actor_exited, "
"reason = " << what.reason()); "reason = " << what.reason());
if (exit_reason() == exit_reason::not_exited) { if (this->exit_reason() == exit_reason::not_exited) {
quit(what.reason()); this->quit(what.reason());
} }
} }
catch (std::exception& e) { catch (std::exception& e) {
CPPA_LOG_WARNING("actor died because of exception: " CPPA_LOG_WARNING("actor died because of exception: "
<< detail::demangle(typeid(e)) << detail::demangle(typeid(e))
<< ", what() = " << e.what()); << ", what() = " << e.what());
if (exit_reason() == exit_reason::not_exited) { if (this->exit_reason() == exit_reason::not_exited) {
quit(exit_reason::unhandled_exception); this->quit(exit_reason::unhandled_exception);
} }
} }
catch (...) { catch (...) {
CPPA_LOG_WARNING("actor died because of an unknown exception"); CPPA_LOG_WARNING("actor died because of an unknown exception");
if (exit_reason() == exit_reason::not_exited) { if (this->exit_reason() == exit_reason::not_exited) {
quit(exit_reason::unhandled_exception); this->quit(exit_reason::unhandled_exception);
} }
} }
done_cb(); done_cb();
return resume_result::actor_done; return resumable::done;
}
};
template<class Actor>
void await_data(Actor*) {
static_assert(std::is_same<Actor, Actor>::value == false,
"The event-based resume policy cannot be used "
"to implement blocking actors");
}
template<class Actor>
bool await_data(Actor*, const util::duration&) {
static_assert(std::is_same<Actor, Actor>::value == false,
"The event-based resume policy cannot be used "
"to implement blocking actors");
} }
}; };
......
...@@ -28,8 +28,8 @@ ...@@ -28,8 +28,8 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_NESTABLE_RECEIVE_POLICY_HPP #ifndef CPPA_INVOKE_POLICY_HPP
#define CPPA_NESTABLE_RECEIVE_POLICY_HPP #define CPPA_INVOKE_POLICY_HPP
#include <list> #include <list>
#include <memory> #include <memory>
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
#include "cppa/mailbox_element.hpp" #include "cppa/mailbox_element.hpp"
#include "cppa/partial_function.hpp" #include "cppa/partial_function.hpp"
#include "cppa/util/dptr.hpp"
#include "cppa/detail/memory.hpp" #include "cppa/detail/memory.hpp"
#include "cppa/detail/matches.hpp" #include "cppa/detail/matches.hpp"
...@@ -59,35 +60,38 @@ enum receive_policy_flag { ...@@ -59,35 +60,38 @@ enum receive_policy_flag {
rp_sequential rp_sequential
}; };
enum handle_message_result {
hm_timeout_msg,
hm_skip_msg,
hm_drop_msg,
hm_cache_msg,
hm_msg_handled
};
template<receive_policy_flag X> template<receive_policy_flag X>
struct rp_flag { typedef std::integral_constant<receive_policy_flag, X> type; }; struct rp_flag { typedef std::integral_constant<receive_policy_flag, X> type; };
/**
* @brief The invoke_policy <b>concept</b> class. Please note that this
* class is <b>not</b> implemented. It only explains the all
* required member function and their behavior for any resume policy.
*/
template<class Derived> template<class Derived>
class invoke_policy_base { class invoke_policy {
public: public:
typedef mailbox_element* pointer; typedef mailbox_element* pointer;
typedef std::unique_ptr<mailbox_element, detail::disposer> smart_pointer; typedef std::unique_ptr<mailbox_element, detail::disposer> smart_pointer;
enum handle_message_result { template<class Actor, class Fun>
hm_timeout_msg, bool invoke_from_cache(Actor* self,
hm_skip_msg,
hm_drop_msg,
hm_cache_msg,
hm_msg_handled
};
template<class Client, class Fun>
bool invoke_from_cache(Client* client,
Fun& fun, Fun& fun,
message_id awaited_response = message_id{}) { message_id awaited_response = message_id{}) {
std::integral_constant<receive_policy_flag, Client::receive_flag> policy;
auto i = m_cache.begin(); auto i = m_cache.begin();
auto e = m_cache.end(); auto e = m_cache.end();
while (i != e) { while (i != e) {
switch (this->handle_message(client, i->get(), fun, switch (this->handle_message(self, i->get(), fun, awaited_response)) {
awaited_response, policy)) {
case hm_msg_handled: { case hm_msg_handled: {
m_cache.erase(i); m_cache.erase(i);
return true; return true;
...@@ -113,15 +117,14 @@ class invoke_policy_base { ...@@ -113,15 +117,14 @@ class invoke_policy_base {
m_cache.emplace_back(std::move(node_ptr)); m_cache.emplace_back(std::move(node_ptr));
} }
template<class Client, class Fun> template<class Actor, class Fun>
bool invoke(Client* client, bool invoke(Actor* self,
pointer node_ptr, pointer node_ptr,
Fun& fun, Fun& fun,
message_id awaited_response = message_id()) { message_id awaited_response = message_id()) {
smart_pointer node(node_ptr); smart_pointer node(node_ptr);
std::integral_constant<receive_policy_flag, Client::receive_flag> policy; switch (this->handle_message(self, node.get(), fun,
switch (this->handle_message(client, node.get(), fun, awaited_response)) {
awaited_response, policy)) {
case hm_msg_handled: { case hm_msg_handled: {
return true; return true;
} }
...@@ -142,71 +145,71 @@ class invoke_policy_base { ...@@ -142,71 +145,71 @@ class invoke_policy_base {
return false; return false;
} }
template<class Client, class FunOrBehavior> template<class Actor, class FunOrBehavior>
inline void receive_wo_timeout(Client *client, FunOrBehavior& fun) { inline void receive_wo_timeout(Actor* self, FunOrBehavior& fun) {
if (!invoke_from_cache(client, fun)) { if (!invoke_from_cache(self, fun)) {
while (!invoke(client, client->await_message(), fun)) { } while (!invoke(self, self->await_message(), fun)) { }
} }
} }
template<class Client> template<class Actor>
void receive(Client* client, partial_function& fun) { void receive(Actor* self, partial_function& fun) {
receive_wo_timeout(client, fun); receive_wo_timeout(self, fun);
} }
template<class Client> template<class Actor>
void receive(Client* client, behavior& bhvr) { void receive(Actor* self, behavior& bhvr) {
if (!bhvr.timeout().valid()) { if (!bhvr.timeout().valid()) {
receive_wo_timeout(client, bhvr); receive_wo_timeout(self, bhvr);
} }
else if (!invoke_from_cache(client, bhvr)) { else if (!invoke_from_cache(self, bhvr)) {
if (bhvr.timeout().is_zero()) { if (bhvr.timeout().is_zero()) {
pointer e = nullptr; pointer e = nullptr;
while ((e = client->try_pop()) != nullptr) { while ((e = self->try_pop()) != nullptr) {
CPPA_REQUIRE(e->marked == false); CPPA_REQUIRE(e->marked == false);
if (invoke(client, e, bhvr)) { if (invoke(self, e, bhvr)) {
return; // done return; // done
} }
} }
handle_timeout(client, bhvr); dptr()->handle_timeout(self, bhvr);
} }
else { else {
auto timeout = client->init_timeout(bhvr.timeout()); auto timeout = self->init_timeout(bhvr.timeout());
pointer e = nullptr; pointer e = nullptr;
while ((e = client->await_message(timeout)) != nullptr) { while ((e = self->await_message(timeout)) != nullptr) {
CPPA_REQUIRE(e->marked == false); CPPA_REQUIRE(e->marked == false);
if (invoke(client, e, bhvr)) { if (invoke(self, e, bhvr)) {
return; // done return; // done
} }
} }
handle_timeout(client, bhvr); dptr()->handle_timeout(self, bhvr);
} }
} }
} }
template<class Client> template<class Actor>
void receive(Client* client, behavior& bhvr, message_id mid) { void receive(Actor* self, behavior& bhvr, message_id mid) {
CPPA_REQUIRE(mid.is_response()); CPPA_REQUIRE(mid.is_response());
if (!invoke_from_cache(client, bhvr, mid)) { if (!invoke_from_cache(self, bhvr, mid)) {
if (bhvr.timeout().valid()) { if (bhvr.timeout().valid()) {
CPPA_REQUIRE(bhvr.timeout().is_zero() == false); CPPA_REQUIRE(bhvr.timeout().is_zero() == false);
auto timeout = client->init_timeout(bhvr.timeout()); auto timeout = self->init_timeout(bhvr.timeout());
pointer e = nullptr; pointer e = nullptr;
while ((e = client->await_message(timeout)) != nullptr) { while ((e = self->await_message(timeout)) != nullptr) {
CPPA_REQUIRE(e->marked == false); CPPA_REQUIRE(e->marked == false);
if (invoke(client, e, bhvr, mid)) { if (invoke(self, e, bhvr, mid)) {
return; // done return; // done
} }
} }
handle_timeout(client, bhvr); dptr()->handle_timeout(self, bhvr);
} }
else while (!invoke(client, client->await_message(), bhvr, mid)) { } else while (!invoke(self, self->await_message(), bhvr, mid)) { }
} }
} }
template<class Client> template<class Actor>
mailbox_element* fetch_message(Client* client) { mailbox_element* fetch_message(Actor* self) {
return client->await_message(); return self->await_message();
} }
typedef typename rp_flag<rp_nestable>::type nestable; typedef typename rp_flag<rp_nestable>::type nestable;
...@@ -216,13 +219,8 @@ class invoke_policy_base { ...@@ -216,13 +219,8 @@ class invoke_policy_base {
std::list<std::unique_ptr<mailbox_element, detail::disposer> > m_cache; std::list<std::unique_ptr<mailbox_element, detail::disposer> > m_cache;
template<class Client> template<class Actor>
inline void handle_timeout(Client* client, behavior& bhvr) { inline void handle_timeout(Actor*, partial_function&) {
client->handle_timeout(bhvr);
}
template<class Client>
inline void handle_timeout(Client*, partial_function&) {
CPPA_CRITICAL("handle_timeout(partial_function&)"); CPPA_CRITICAL("handle_timeout(partial_function&)");
} }
...@@ -239,11 +237,11 @@ class invoke_policy_base { ...@@ -239,11 +237,11 @@ class invoke_policy_base {
// identifies 'special' messages that should not be processed normally: // identifies 'special' messages that should not be processed normally:
// - system messages such as EXIT (if client doesn't trap exits) and TIMEOUT // - system messages such as EXIT (if self doesn't trap exits) and TIMEOUT
// - expired synchronous response messages // - expired synchronous response messages
template<class Client> template<class Actor>
filter_result filter_msg(Client* client, pointer node) { filter_result filter_msg(Actor* self, pointer node) {
const any_tuple& msg = node->msg; const any_tuple& msg = node->msg;
auto mid = node->mid; auto mid = node->mid;
auto& arr = detail::static_types_array<atom_value, std::uint32_t>::arr; auto& arr = detail::static_types_array<atom_value, std::uint32_t>::arr;
...@@ -254,9 +252,9 @@ class invoke_policy_base { ...@@ -254,9 +252,9 @@ class invoke_policy_base {
auto v1 = msg.get_as<std::uint32_t>(1); auto v1 = msg.get_as<std::uint32_t>(1);
if (v0 == atom("EXIT")) { if (v0 == atom("EXIT")) {
CPPA_REQUIRE(!mid.valid()); CPPA_REQUIRE(!mid.valid());
if (client->m_trap_exit == false) { if (self->trap_exit() == false) {
if (v1 != exit_reason::normal) { if (v1 != exit_reason::normal) {
client->quit(v1); self->quit(v1);
return non_normal_exit_signal; return non_normal_exit_signal;
} }
return normal_exit_signal; return normal_exit_signal;
...@@ -264,8 +262,9 @@ class invoke_policy_base { ...@@ -264,8 +262,9 @@ class invoke_policy_base {
} }
else if (v0 == atom("SYNC_TOUT")) { else if (v0 == atom("SYNC_TOUT")) {
CPPA_REQUIRE(!mid.valid()); CPPA_REQUIRE(!mid.valid());
return client->waits_for_timeout(v1) ? timeout_message //FIXME
: expired_timeout_message; //return self->waits_for_timeout(v1) ? timeout_message
// : expired_timeout_message;
} }
} }
else if ( msg.size() == 1 else if ( msg.size() == 1
...@@ -275,7 +274,7 @@ class invoke_policy_base { ...@@ -275,7 +274,7 @@ class invoke_policy_base {
return timeout_response_message; return timeout_response_message;
} }
if (mid.is_response()) { if (mid.is_response()) {
return (client->awaits(mid)) ? sync_response return (self->awaits(mid)) ? sync_response
: expired_sync_response; : expired_sync_response;
} }
return ordinary_message; return ordinary_message;
...@@ -283,37 +282,37 @@ class invoke_policy_base { ...@@ -283,37 +282,37 @@ class invoke_policy_base {
public: public:
template<class Client> template<class Actor>
inline response_handle fetch_response_handle(Client* cl, int) { inline response_handle fetch_response_handle(Actor* cl, int) {
return cl->make_response_handle(); return cl->make_response_handle();
} }
template<class Client> template<class Actor>
inline response_handle fetch_response_handle(Client*, response_handle& hdl) { inline response_handle fetch_response_handle(Actor*, response_handle& hdl) {
return std::move(hdl); return std::move(hdl);
} }
// - extracts response message from handler // - extracts response message from handler
// - returns true if fun was successfully invoked // - returns true if fun was successfully invoked
template<class Client, class Fun, class MaybeResponseHandle = int> template<class Actor, class Fun, class MaybeResponseHandle = int>
optional<any_tuple> invoke_fun(Client* client, optional<any_tuple> invoke_fun(Actor* self,
any_tuple& msg, any_tuple& msg,
message_id& mid, message_id& mid,
Fun& fun, Fun& fun,
MaybeResponseHandle hdl = MaybeResponseHandle{}) { MaybeResponseHandle hdl = MaybeResponseHandle{}) {
auto res = fun(msg); // might change mid auto res = fun(msg); // might change mid
if (res) { if (res) {
//message_header hdr{client, sender, mid.is_request() ? mid.response_id() //message_header hdr{self, sender, mid.is_request() ? mid.response_id()
// : message_id{}}; // : message_id{}};
if (res->empty()) { if (res->empty()) {
// make sure synchronous requests // make sure synchronous requests
// always receive a response // always receive a response
if (mid.is_request() && !mid.is_answered()) { if (mid.is_request() && !mid.is_answered()) {
CPPA_LOGMF(CPPA_WARNING, client, CPPA_LOGMF(CPPA_WARNING, self,
"actor with ID " << client->id() "actor with ID " << self->id()
<< " 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(self, hdl);
if (fhdl.valid()) fhdl.apply(make_any_tuple(atom("VOID"))); if (fhdl.valid()) fhdl.apply(make_any_tuple(atom("VOID")));
} }
} else { } else {
...@@ -321,11 +320,11 @@ class invoke_policy_base { ...@@ -321,11 +320,11 @@ class invoke_policy_base {
&& res->template get_as<atom_value>(0) == atom("MESSAGE_ID")) { && res->template get_as<atom_value>(0) == atom("MESSAGE_ID")) {
auto id = res->template get_as<std::uint64_t>(1); auto id = res->template get_as<std::uint64_t>(1);
auto msg_id = message_id::from_integer_value(id); auto msg_id = message_id::from_integer_value(id);
auto ref_opt = client->sync_handler(msg_id); auto ref_opt = self->sync_handler(msg_id);
// calls client->response_handle() if hdl is a dummy // calls self->response_handle() if hdl is a dummy
// argument, forwards hdl otherwise to reply to the // argument, forwards hdl otherwise to reply to the
// original request message // original request message
auto fhdl = fetch_response_handle(client, hdl); auto fhdl = fetch_response_handle(self, hdl);
if (ref_opt) { if (ref_opt) {
auto& ref = *ref_opt; auto& ref = *ref_opt;
// copy original behavior // copy original behavior
...@@ -342,7 +341,7 @@ class invoke_policy_base { ...@@ -342,7 +341,7 @@ class invoke_policy_base {
// recursively call invoke_fun on the // recursively call invoke_fun on the
// result to correctly handle stuff like // result to correctly handle stuff like
// sync_send(...).then(...).then(...)... // sync_send(...).then(...).then(...)...
return invoke_fun(client, return invoke_fun(self,
intermediate, intermediate,
mutable_mid, mutable_mid,
f2, f2,
...@@ -357,7 +356,7 @@ class invoke_policy_base { ...@@ -357,7 +356,7 @@ class invoke_policy_base {
res->reset(); res->reset();
} else { } else {
// respond by using the result of 'fun' // respond by using the result of 'fun'
auto fhdl = fetch_response_handle(client, hdl); auto fhdl = fetch_response_handle(self, hdl);
if (fhdl.valid()) fhdl.apply(std::move(*res)); if (fhdl.valid()) fhdl.apply(std::move(*res));
} }
} }
...@@ -370,47 +369,45 @@ class invoke_policy_base { ...@@ -370,47 +369,45 @@ class invoke_policy_base {
// the workflow of handle_message (hm) is as follows: // the workflow of handle_message (hm) is as follows:
// - should_skip? if yes: return hm_skip_msg // - should_skip? if yes: return hm_skip_msg
// - msg is ordinary message? if yes: // - msg is ordinary message? if yes:
// - begin(...) -> prepares a client for message handling // - begin(...) -> prepares a self for message handling
// - client could process message? // - self could process message?
// - yes: cleanup() // - yes: cleanup()
// - no: revert(...) -> set client back to state it had before begin() // - no: revert(...) -> set self back to state it had before begin()
template<class Client, class Fun, class Policy> template<class Actor, class Fun>
handle_message_result handle_message(Client* client, handle_message_result handle_message(Actor* self,
pointer node, pointer node,
Fun& fun, Fun& fun,
message_id awaited_response, message_id awaited_response) {
Policy policy ) {
bool handle_sync_failure_on_mismatch = true; bool handle_sync_failure_on_mismatch = true;
if (Derived::hm_should_skip(node, policy)) { if (dptr()->hm_should_skip(node)) { return hm_skip_msg;
return hm_skip_msg;
} }
switch (this->filter_msg(client, node)) { switch (this->filter_msg(self, node)) {
default: { default: {
CPPA_CRITICAL("illegal filter result"); CPPA_CRITICAL("illegal filter result");
} }
case normal_exit_signal: { case normal_exit_signal: {
CPPA_LOGMF(CPPA_DEBUG, client, "dropped normal exit signal"); CPPA_LOGMF(CPPA_DEBUG, self, "dropped normal exit signal");
return hm_drop_msg; return hm_drop_msg;
} }
case expired_sync_response: { case expired_sync_response: {
CPPA_LOGMF(CPPA_DEBUG, client, "dropped expired sync response"); CPPA_LOGMF(CPPA_DEBUG, self, "dropped expired sync response");
return hm_drop_msg; return hm_drop_msg;
} }
case expired_timeout_message: { case expired_timeout_message: {
CPPA_LOGMF(CPPA_DEBUG, client, "dropped expired timeout message"); CPPA_LOGMF(CPPA_DEBUG, self, "dropped expired timeout message");
return hm_drop_msg; return hm_drop_msg;
} }
case non_normal_exit_signal: { case non_normal_exit_signal: {
// this message was handled // this message was handled
// by calling client->quit(...) // by calling self->quit(...)
return hm_msg_handled; return hm_msg_handled;
} }
case timeout_message: { case timeout_message: {
handle_timeout(client, fun); dptr()->handle_timeout(self, fun);
if (awaited_response.valid()) { if (awaited_response.valid()) {
client->mark_arrived(awaited_response); self->mark_arrived(awaited_response);
client->remove_handler(awaited_response); //FIXME: self->remove_handler(awaited_response);
} }
return hm_msg_handled; return hm_msg_handled;
} }
...@@ -420,46 +417,50 @@ class invoke_policy_base { ...@@ -420,46 +417,50 @@ class invoke_policy_base {
} }
case sync_response: { case sync_response: {
if (awaited_response.valid() && node->mid == awaited_response) { if (awaited_response.valid() && node->mid == awaited_response) {
auto previous_node = Derived::hm_begin(client, node, policy); auto previous_node = dptr()->hm_begin(self, node);
auto res = invoke_fun(client, auto res = invoke_fun(self,
node->msg, node->msg,
node->mid, node->mid,
fun); fun);
if (!res && handle_sync_failure_on_mismatch) { if (!res && handle_sync_failure_on_mismatch) {
CPPA_LOGMF(CPPA_WARNING, CPPA_LOGMF(CPPA_WARNING,
client, self,
"sync failure occured in actor with ID " "sync failure occured in actor with ID "
<< client->id()); << self->id());
client->handle_sync_failure(); self->handle_sync_failure();
} }
client->mark_arrived(awaited_response); self->mark_arrived(awaited_response);
client->remove_handler(awaited_response); //FIXME: self->remove_handler(awaited_response);
Derived::hm_cleanup(client, previous_node, policy); dptr()->hm_cleanup(self, previous_node);
return hm_msg_handled; return hm_msg_handled;
} }
return hm_cache_msg; return hm_cache_msg;
} }
case ordinary_message: { case ordinary_message: {
if (!awaited_response.valid()) { if (!awaited_response.valid()) {
auto previous_node = Derived::hm_begin(client, node, policy); auto previous_node = dptr()->hm_begin(self, node);
auto res = invoke_fun(client, auto res = invoke_fun(self,
node->msg, node->msg,
node->mid, node->mid,
fun); fun);
if (res) { if (res) {
Derived::hm_cleanup(client, previous_node, policy); dptr()->hm_cleanup(self, previous_node);
return hm_msg_handled; return hm_msg_handled;
} }
// no match (restore client members) // no match (restore self members)
Derived::hm_revert(client, previous_node, policy); dptr()->hm_revert(self, previous_node);
} }
return hm_cache_msg; return hm_cache_msg;
} }
} }
} }
Derived* dptr() {
return static_cast<Derived*>(this);
}
}; };
} } // namespace cppa::policy } } // namespace cppa::policy
#endif // CPPA_NESTABLE_RECEIVE_POLICY_HPP #endif // CPPA_INVOKE_POLICY_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_POLICY_MIDDLEMAN_SCHEDULING_HPP
#define CPPA_POLICY_MIDDLEMAN_SCHEDULING_HPP
#include "cppa/singletons.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/io/middleman.hpp"
#include "cppa/policy/cooperative_scheduling.hpp"
namespace cppa {
namespace policy {
// Actor must implement invoke_message
class middleman_scheduling {
public:
template<class Actor>
class continuation {
public:
typedef intrusive_ptr<Actor> pointer;
continuation(pointer ptr, const message_header& hdr, any_tuple&& msg)
: m_self(std::move(ptr)), m_hdr(hdr), m_data(std::move(msg)) { }
inline void operator()() const {
m_self->invoke_message(m_hdr, move(m_data));
}
private:
pointer m_self;
message_header m_hdr;
any_tuple m_data;
};
using timeout_type = int;
template<class Actor>
timeout_type init_timeout(Actor* self, const util::duration& rel_time) {
// request explicit timeout message
self->request_timeout(rel_time);
return 0; // return some dummy value
}
// this does return nullptr
template<class Actor, typename F>
inline void fetch_messages(Actor*, F) {
// clients cannot fetch messages
}
template<class Actor, typename F>
inline void fetch_messages(Actor* self, F cb, timeout_type) {
// a call to this call is always preceded by init_timeout,
// which will trigger a timeout message
fetch_messages(self, cb);
}
template<class Actor>
inline void launch(Actor*) {
// nothing to do
}
template<class Actor>
void enqueue(Actor* self, const message_header& hdr, any_tuple& msg) {
get_middleman()->run_later(continuation<Actor>{self, hdr, std::move(msg)});
}
};
} // namespace policy
} // namespace cppa
#endif // CPPA_POLICY_MIDDLEMAN_SCHEDULING_HPP
...@@ -44,13 +44,13 @@ ...@@ -44,13 +44,13 @@
#include "cppa/intrusive/single_reader_queue.hpp" #include "cppa/intrusive/single_reader_queue.hpp"
#include "cppa/policy/invoke_policy_base.hpp" #include "cppa/policy/invoke_policy.hpp"
namespace cppa { namespace detail { class receive_policy; } } namespace cppa { namespace detail { class receive_policy; } }
namespace cppa { namespace policy { namespace cppa { namespace policy {
class nestable_invoke : public invoke_policy_base<nestable_invoke> { class nestable_invoke : public invoke_policy<nestable_invoke> {
typedef std::unique_lock<std::mutex> lock_type; typedef std::unique_lock<std::mutex> lock_type;
...@@ -62,34 +62,32 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> { ...@@ -62,34 +62,32 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> {
template<class Client> template<class Client>
static inline pointer hm_begin(Client* client, pointer node) { static inline pointer hm_begin(Client* client, pointer node) {
auto previous = client->m_current_node; auto previous = client->current_node();
client->m_current_node = node; client->current_node(node);
return previous; return previous;
} }
template<class Client> template<class Client>
static inline void hm_cleanup(Client* client, pointer /*previous*/) { static inline void hm_cleanup(Client* client, pointer /*previous*/) {
client->m_current_node = &(client->m_dummy_node); client->current_node(&(client->m_dummy_node));
if (client->has_behavior()) {
client->request_timeout(client->get_behavior().timeout());
}
else client->reset_timeout();
} }
template<class Client> template<class Client>
static inline void hm_revert(Client* client, pointer previous) { static inline void hm_revert(Client* client, pointer previous) {
client->m_current_node = previous; client->current_node(previous);
} }
typedef std::chrono::high_resolution_clock::time_point timeout_type; typedef std::chrono::high_resolution_clock::time_point timeout_type;
nestable_invoke() : m_initialized(false) { }
inline void reset_timeout() { } inline void reset_timeout() { }
inline void request_timeout(const util::duration&) { } template<class Actor>
inline void request_timeout(Actor*, const util::duration&) { }
inline void handle_timeout(behavior& bhvr) { bhvr.handle_timeout(); } template<class Actor>
inline void handle_timeout(Actor*, behavior& bhvr) {
bhvr.handle_timeout();
}
inline void pop_timeout() { } inline void pop_timeout() { }
...@@ -97,19 +95,7 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> { ...@@ -97,19 +95,7 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> {
inline bool waits_for_timeout(std::uint32_t) { return false; } inline bool waits_for_timeout(std::uint32_t) { return false; }
virtual mailbox_element* try_pop() { /*
return this->m_mailbox.try_pop();
}
mailbox_element* pop() {
wait_for_data();
return try_pop();
}
inline mailbox_element* try_pop(const timeout_type& abs_time) {
return (timed_wait_for_data(abs_time)) ? try_pop() : nullptr;
}
void run_detached() { void run_detached() {
auto dthis = util::dptr<Subtype>(this); auto dthis = util::dptr<Subtype>(this);
dthis->init(); dthis->init();
...@@ -120,87 +106,7 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> { ...@@ -120,87 +106,7 @@ class nestable_invoke : public invoke_policy_base<nestable_invoke> {
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);
} }
*/
inline void initialized(bool value) {
m_initialized = value;
}
bool initialized() const override {
return m_initialized;
}
protected:
typedef threaded combined_type;
void enqueue_impl(typename Base::mailbox_type& mbox,
const message_header& hdr,
any_tuple&& msg) {
auto ptr = this->new_mailbox_element(hdr, std::move(msg));
switch (mbox.enqueue(ptr)) {
case intrusive::first_enqueued: {
lock_type guard(m_mtx);
m_cv.notify_one();
break;
}
default: break;
case intrusive::queue_closed:
if (hdr.id.valid()) {
detail::sync_request_bouncer f{this->exit_reason()};
f(hdr.sender, hdr.id);
}
break;
}
}
void enqueue(const message_header& hdr, any_tuple msg) override {
enqueue_impl(this->m_mailbox, hdr, std::move(msg));
}
timeout_type init_timeout(const util::duration& rel_time) {
auto result = std::chrono::high_resolution_clock::now();
result += rel_time;
return result;
}
mailbox_element* await_message() {
return pop();
}
mailbox_element* await_message(const timeout_type& abs_time) {
return try_pop(abs_time);
}
virtual bool mailbox_empty() {
return this->m_mailbox.empty();
}
bool timed_wait_for_data(const timeout_type& abs_time) {
CPPA_REQUIRE(not this->m_mailbox.closed());
if (mailbox_empty()) {
lock_type guard(m_mtx);
while (mailbox_empty()) {
if (m_cv.wait_until(guard, abs_time) == std::cv_status::timeout) {
return false;
}
}
}
return true;
}
void wait_for_data() {
if (mailbox_empty()) {
lock_type guard(m_mtx);
while (mailbox_empty()) m_cv.wait(guard);
}
}
std::mutex m_mtx;
std::condition_variable m_cv;
private:
bool m_initialized;
}; };
......
...@@ -5,144 +5,41 @@ ...@@ -5,144 +5,41 @@
#include "cppa/policy/resume_policy.hpp" #include "cppa/policy/resume_policy.hpp"
namespace cppa {
namespace util {
struct fiber;
} // namespace util
} // namespace cppa
namespace cppa { namespace policy { namespace cppa { namespace policy {
// this policy simply forwards calls to @p await_data to the scheduling
// policy and throws an exception whenever @p resume is called;
// it intentionally works only with the no_scheduling policy
class no_resume { class no_resume {
public: public:
using timeout_type = std::chrono::high_resolution_clock::time_point; template<class Base>
struct mixin : Base {
template<class Actor>
timeout_type init_timeout(Actor* self, const util::duration& rel_time) {
// request explicit timeout message
self->request_timeout(rel_time);
return 0; // return some dummy value
}
template<class Actor, typename F>
void fetch_messages(Actor* self, F cb) {
auto e = self->m_mailbox.try_pop();
while (e) {
cb(e);
e = self->m_mailbox.try_pop();
}
}
template<class Actor, typename F> template<typename... Ts>
inline void fetch_messages(Actor* self, F cb, timeout_type) { mixin(Ts&&... args) : Base(std::forward<Ts>(args)...) { }
// a call to this call is always preceded by init_timeout,
// which will trigger a timeout message
fetch_messages(self, cb);
}
template<class Actor, typename F> inline resumable::resume_result resume(util::fiber*) {
void try_fetch_messages(Actor* self, F cb) { this->act();
// try_fetch and fetch have the same semantics for event-based actors return resumable::done;
fetch_messages(self, cb);
} }
};
template<class Actor> template<class Actor>
resume_result resume(Actor* self, util::fiber*) { void await_data(Actor* self) {
CPPA_LOG_TRACE("id = " << self->id() self->scheduling_policy().await_data(self);
<< ", state = " << static_cast<int>(self->state()));
CPPA_REQUIRE( self->state() == actor_state::ready
|| self->state() == actor_state::pending);
auto done_cb = [&]() -> bool {
CPPA_LOG_TRACE("");
if (self->exit_reason() == self->exit_reason::not_exited) {
if (self->planned_exit_reason() == self->exit_reason::not_exited) {
self->planned_exit_reason(exit_reason::normal);
}
self->on_exit();
if (!m_bhvr_stack.empty()) {
planned_exit_reason(exit_reason::not_exited);
return false; // on_exit did set a new behavior
}
cleanup(planned_exit_reason());
}
set_state(actor_state::done);
m_bhvr_stack.clear();
m_bhvr_stack.cleanup();
on_exit();
CPPA_REQUIRE(next_job == nullptr);
return true;
};
CPPA_REQUIRE(next_job == nullptr);
try {
//auto e = m_mailbox.try_pop();
for (auto e = m_mailbox.try_pop(); ; e = m_mailbox.try_pop()) {
//e = m_mailbox.try_pop();
if (e == nullptr) {
CPPA_REQUIRE(next_job == nullptr);
CPPA_LOGMF(CPPA_DEBUG, self, "no more element in mailbox; going to block");
set_state(actor_state::about_to_block);
std::atomic_thread_fence(std::memory_order_seq_cst);
if (this->m_mailbox.can_fetch_more() == false) {
switch (compare_exchange_state(actor_state::about_to_block,
actor_state::blocked)) {
case actor_state::ready:
// interrupted by arriving message
// restore members
CPPA_REQUIRE(m_chained_actor == nullptr);
CPPA_LOGMF(CPPA_DEBUG, self, "switched back to ready: "
"interrupted by arriving message");
break;
case actor_state::blocked:
CPPA_LOGMF(CPPA_DEBUG, self, "set state successfully to blocked");
// done setting actor to blocked
return resume_result::actor_blocked;
default:
CPPA_LOGMF(CPPA_ERROR, self, "invalid state");
CPPA_CRITICAL("invalid state");
};
} }
else {
CPPA_LOGMF(CPPA_DEBUG, self, "switched back to ready: " template<class Actor, typename AbsTimeout>
"mailbox can fetch more"); bool await_data(Actor* self, const AbsTimeout& abs_time) {
set_state(actor_state::ready); return self->scheduling_policy().await_data(self, abs_time);
CPPA_REQUIRE(m_chained_actor == nullptr);
}
}
else {
CPPA_LOGMF(CPPA_DEBUG, self, "try to invoke message: " << to_string(e->msg));
if (m_bhvr_stack.invoke(m_recv_policy, this, e)) {
CPPA_LOG_DEBUG_IF(m_chained_actor,
"set actor with ID "
<< m_chained_actor->id()
<< " as successor");
if (m_bhvr_stack.empty() && done_cb()) {
CPPA_LOGMF(CPPA_DEBUG, self, "behavior stack empty");
return resume_result::actor_done;
}
m_bhvr_stack.cleanup();
}
}
}
}
catch (actor_exited& what) {
CPPA_LOG_INFO("actor died because of exception: actor_exited, "
"reason = " << what.reason());
if (exit_reason() == exit_reason::not_exited) {
quit(what.reason());
}
}
catch (std::exception& e) {
CPPA_LOG_WARNING("actor died because of exception: "
<< detail::demangle(typeid(e))
<< ", what() = " << e.what());
if (exit_reason() == exit_reason::not_exited) {
quit(exit_reason::unhandled_exception);
}
}
catch (...) {
CPPA_LOG_WARNING("actor died because of an unknown exception");
if (exit_reason() == exit_reason::not_exited) {
quit(exit_reason::unhandled_exception);
}
}
done_cb();
return resume_result::actor_done;
} }
}; };
......
...@@ -33,8 +33,14 @@ ...@@ -33,8 +33,14 @@
#include <mutex> #include <mutex>
#include <thread> #include <thread>
#include <chrono>
#include <condition_variable> #include <condition_variable>
#include "cppa/util/fiber.hpp"
#include "cppa/util/duration.hpp"
#include "cppa/policy/scheduling_policy.hpp"
#include "cppa/detail/sync_request_bouncer.hpp" #include "cppa/detail/sync_request_bouncer.hpp"
#include "cppa/intrusive/single_reader_queue.hpp" #include "cppa/intrusive/single_reader_queue.hpp"
...@@ -47,6 +53,43 @@ class no_scheduling { ...@@ -47,6 +53,43 @@ class no_scheduling {
public: public:
typedef std::chrono::high_resolution_clock::time_point timeout_type;
template<class Actor>
inline timeout_type init_timeout(Actor*, const util::duration& rel_time) {
auto result = std::chrono::high_resolution_clock::now();
result += rel_time;
return result;
}
template<class Actor, typename F>
bool fetch_messages(Actor* self, F cb) {
await_data(self);
fetch_messages_impl(self, cb);
}
template<class Actor, typename F>
bool try_fetch_messages(Actor* self, F cb) {
auto next = [&] { return self->mailbox().try_pop(); };
auto e = next();
if (!e) return false;
do {
cb(e);
e = next();
}
while (e);
return true;
}
template<class Actor, typename F>
timed_fetch_result fetch_messages(Actor* self, F cb, timeout_type abs_time) {
if (!await_data(self, abs_time)) {
return timed_fetch_result::no_message;
}
fetch_messages_impl(self, cb);
return timed_fetch_result::success;
}
template<class Actor> template<class Actor>
void enqueue(Actor* self, const message_header& hdr, any_tuple& msg) { void enqueue(Actor* self, const message_header& hdr, any_tuple& msg) {
auto ptr = self->new_mailbox_element(hdr, std::move(msg)); auto ptr = self->new_mailbox_element(hdr, std::move(msg));
...@@ -69,22 +112,29 @@ class no_scheduling { ...@@ -69,22 +112,29 @@ class no_scheduling {
template<class Actor> template<class Actor>
void launch(Actor* self) { void launch(Actor* self) {
std::thread([=] { std::thread([=] {
auto rr = resume_result::actor_blocked; util::fiber fself;
while (rr != resume_result::actor_done) { auto rr = resumable::resume_later;
wait_for_data(); while (rr != resumable::done) {
self->resume(); await_data(self);
self->resume(&fself);
} }
}).detach(); }).detach();
} }
private: template<class Actor>
void await_data(Actor* self) {
if (self->mailbox().empty()) {
lock_type guard(m_mtx);
while (self->mailbox().empty()) m_cv.wait(guard);
}
}
bool timed_wait_for_data(const timeout_type& abs_time) { template<class Actor>
CPPA_REQUIRE(not this->m_mailbox.closed()); bool await_data(Actor* self, const timeout_type& abs_time) {
if (mailbox_empty()) { CPPA_REQUIRE(!self->mailbox().closed());
if (self->mailbox().empty()) {
lock_type guard(m_mtx); lock_type guard(m_mtx);
while (mailbox_empty()) { while (self->mailbox().empty()) {
if (m_cv.wait_until(guard, abs_time) == std::cv_status::timeout) { if (m_cv.wait_until(guard, abs_time) == std::cv_status::timeout) {
return false; return false;
} }
...@@ -93,11 +143,15 @@ class no_scheduling { ...@@ -93,11 +143,15 @@ class no_scheduling {
return true; return true;
} }
void wait_for_data() { private:
if (mailbox_empty()) {
lock_type guard(m_mtx); template<class Actor, typename F>
while (mailbox_empty()) m_cv.wait(guard); void fetch_messages_impl(Actor* self, F cb) {
auto next = [&] { return self->mailbox().try_pop(); };
for (auto e = next(); e != nullptr; e = next()) {
cb(e);
} }
} }
std::mutex m_mtx; std::mutex m_mtx;
......
...@@ -28,24 +28,31 @@ ...@@ -28,24 +28,31 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_SCHEDULED_ACTOR_DUMMY_HPP #ifndef NOT_PRIORITIZING_HPP
#define CPPA_SCHEDULED_ACTOR_DUMMY_HPP #define NOT_PRIORITIZING_HPP
#include "cppa/scheduled_actor.hpp" #include "cppa/mailbox_element.hpp"
namespace cppa { namespace detail { #include "cppa/policy/priority_policy.hpp"
struct scheduled_actor_dummy : scheduled_actor { namespace cppa {
scheduled_actor_dummy(); namespace policy {
void enqueue(const message_header&, any_tuple) override;
resume_result resume(util::fiber*) override; struct not_prioritizing {
void quit(std::uint32_t) override;
void dequeue(behavior&) override; template<class Actor>
void dequeue_response(behavior&, message_id) override; mailbox_element* next_message(Actor* self) {
bool has_behavior() override; return self->mailbox().try_pop();
scheduled_actor_type impl_type() override; }
template<class Actor, typename F>
bool fetch_messages(Actor*, F) {
//FIXME
}
}; };
} } // namespace cppa::detail } // namespace policy
} // namespace cppa
#endif // CPPA_SCHEDULED_ACTOR_DUMMY_HPP #endif // NOT_PRIORITIZING_HPP
...@@ -62,7 +62,7 @@ class priority_policy { ...@@ -62,7 +62,7 @@ class priority_policy {
* for re-scheduling. * for re-scheduling.
*/ */
template<class Actor, typename F> template<class Actor, typename F>
bool fetch_messages(Actor* self); bool fetch_messages(Actor* self, F cb);
}; };
......
...@@ -31,18 +31,15 @@ ...@@ -31,18 +31,15 @@
#ifndef CPPA_RESUME_POLICY_HPP #ifndef CPPA_RESUME_POLICY_HPP
#define CPPA_RESUME_POLICY_HPP #define CPPA_RESUME_POLICY_HPP
#include "cppa/resumable.hpp"
// this header consists all type definitions needed to // this header consists all type definitions needed to
// implement the resume_policy trait // implement the resume_policy trait
namespace cppa { namespace util { class duration; } } namespace cppa { namespace util { class duration; struct fiber; } }
namespace cppa { namespace policy { namespace cppa { namespace policy {
enum class resume_result {
actor_blocked,
actor_done
};
/** /**
* @brief The resume_policy <b>concept</b> class. Please note that this * @brief The resume_policy <b>concept</b> class. Please note that this
* class is <b>not</b> implemented. It only explains the all * class is <b>not</b> implemented. It only explains the all
...@@ -59,7 +56,7 @@ class resume_policy { ...@@ -59,7 +56,7 @@ class resume_policy {
* actor finishes execution. * actor finishes execution.
*/ */
template<class Actor> template<class Actor>
resume_result resume(Actor* self, util::fiber* from); resumable::resume_result resume(Actor* self, util::fiber* from);
/** /**
* @brief Waits unconditionally until a new message arrives. * @brief Waits unconditionally until a new message arrives.
......
...@@ -36,14 +36,14 @@ ...@@ -36,14 +36,14 @@
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
#include "cppa/policy/invoke_policy_base.hpp" #include "cppa/policy/invoke_policy.hpp"
namespace cppa { namespace policy { namespace cppa { namespace policy {
/** /**
* @brief An actor that is scheduled or otherwise managed. * @brief An actor that is scheduled or otherwise managed.
*/ */
class sequential_invoke : public invoke_policy_base<sequential_invoke> { class sequential_invoke : public invoke_policy<sequential_invoke> {
public: public:
...@@ -53,26 +53,26 @@ class sequential_invoke : public invoke_policy_base<sequential_invoke> { ...@@ -53,26 +53,26 @@ class sequential_invoke : public invoke_policy_base<sequential_invoke> {
return node->marked; return node->marked;
} }
template<class Client> template<class Actor>
static inline pointer hm_begin(Client* client, pointer node) { inline pointer hm_begin(Actor* self, pointer node) {
auto previous = client->m_current_node; auto previous = self->m_current_node;
client->m_current_node = node; self->m_current_node = node;
client->push_timeout(); push_timeout();
node->marked = true; node->marked = true;
return previous; return previous;
} }
template<class Client> template<class Actor>
static inline void hm_cleanup(Client* client, pointer previous) { inline void hm_cleanup(Actor* self, pointer previous) {
client->m_current_node->marked = false; self->m_current_node->marked = false;
client->m_current_node = previous; self->m_current_node = previous;
} }
template<class Client> template<class Actor>
static inline void hm_revert(Client* client, pointer previous) { inline void hm_revert(Actor* self, pointer previous) {
client->m_current_node->marked = false; self->m_current_node->marked = false;
client->m_current_node = previous; self->m_current_node = previous;
client->pop_timeout(); pop_timeout();
} }
inline void reset_timeout() { inline void reset_timeout() {
...@@ -82,22 +82,24 @@ class sequential_invoke : public invoke_policy_base<sequential_invoke> { ...@@ -82,22 +82,24 @@ class sequential_invoke : public invoke_policy_base<sequential_invoke> {
} }
} }
void request_timeout(const util::duration& d) { template<class Actor>
void request_timeout(Actor* self, const util::duration& d) {
if (!d.valid()) m_has_pending_tout = false; if (!d.valid()) m_has_pending_tout = false;
else { else {
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->address(), this}, std::move(msg)); self->enqueue({self->address(), self}, 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 this->delayed_send_tuple(this, d, std::move(msg)); else self->delayed_send_tuple(self, d, std::move(msg));
m_has_pending_tout = true; m_has_pending_tout = true;
} }
} }
inline void handle_timeout(behavior& bhvr) { template<class Actor>
inline void handle_timeout(Actor*, behavior& bhvr) {
bhvr.handle_timeout(); bhvr.handle_timeout();
reset_timeout(); reset_timeout();
} }
......
...@@ -28,64 +28,32 @@ ...@@ -28,64 +28,32 @@
\******************************************************************************/ \******************************************************************************/
#ifndef CPPA_THREAD_BASED_ACTOR_HPP #ifndef CPPA_RESUMABLE_HPP
#define CPPA_THREAD_BASED_ACTOR_HPP #define CPPA_RESUMABLE_HPP
#include "cppa/config.hpp"
#include <map>
#include <list>
#include <mutex>
#include <stack>
#include <atomic>
#include <vector>
#include <memory>
#include <cstdint>
#include "cppa/atom.hpp"
#include "cppa/extend.hpp"
#include "cppa/stacked.hpp"
#include "cppa/threaded.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/intrusive_ptr.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/detail/receive_policy.hpp"
namespace cppa { namespace cppa {
class self_type; namespace util {
class scheduler_helper; struct fiber;
} // namespace util
/**
* @brief An actor using the blocking API running in its own thread.
* @extends local_actor
*/
class thread_mapped_actor : public extend<local_actor, thread_mapped_actor>::
with<stacked, threaded> {
typedef combined_type super; struct resumable {
public: enum resume_result {
resume_later,
done
};
thread_mapped_actor(); // intrusive next pointer needed to use
// 'resumable' with 'single_reader_queue'
resumable* next;
thread_mapped_actor(std::function<void()> fun); virtual ~resumable();
inline void initialized(bool value) { m_initialized = value; } virtual resume_result resume(util::fiber*) = 0;
bool initialized() const override;
private:
bool m_initialized;
}; };
typedef intrusive_ptr<thread_mapped_actor> thread_mapped_actor_ptr;
} // namespace cppa } // namespace cppa
#endif // CPPA_THREAD_BASED_ACTOR_HPP #endif // CPPA_RESUMABLE_HPP
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
#include <type_traits> #include <type_traits>
#include "cppa/util/dptr.hpp" #include "cppa/util/dptr.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/untyped_actor.hpp"
namespace cppa { namespace cppa {
...@@ -45,11 +45,11 @@ namespace cppa { ...@@ -45,11 +45,11 @@ namespace cppa {
* to initialize the derived actor with its @p init_state member. * to initialize the derived actor with its @p init_state member.
* @tparam Derived Direct subclass of @p sb_actor. * @tparam Derived Direct subclass of @p sb_actor.
*/ */
template<class Derived, class Base = event_based_actor> template<class Derived, class Base = untyped_actor>
class sb_actor : public Base { class sb_actor : public Base {
static_assert(std::is_base_of<event_based_actor, Base>::value, static_assert(std::is_base_of<untyped_actor, Base>::value,
"Base must be either event_based_actor or a derived type"); "Base must be either untyped_actor or a derived type");
protected: protected:
...@@ -58,11 +58,11 @@ class sb_actor : public Base { ...@@ -58,11 +58,11 @@ class sb_actor : public Base {
public: public:
/** /**
* @brief Overrides {@link event_based_actor::init()} and sets * @brief Overrides {@link untyped_actor::init()} and sets
* the initial actor behavior to <tt>Derived::init_state</tt>. * the initial actor behavior to <tt>Derived::init_state</tt>.
*/ */
void init() override { behavior make_behavior() override {
become(util::dptr<Derived>(this)->init_state); return util::dptr<Derived>(this)->init_state;
} }
protected: protected:
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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_ACTOR_BEHAVIOR_HPP
#define CPPA_ACTOR_BEHAVIOR_HPP
#include <functional>
#include "cppa/config.hpp"
#include "cppa/extend.hpp"
#include "cppa/threadless.hpp"
#include "cppa/actor_state.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp"
#include "cppa/mailbox_element.hpp"
#include "cppa/message_priority.hpp"
#include "cppa/detail/memory.hpp"
#include "cppa/detail/receive_policy.hpp"
#include "cppa/intrusive/single_reader_queue.hpp"
namespace cppa {
class scheduler;
namespace util { struct fiber; }
enum scheduled_actor_type {
context_switching_impl, // enqueued to the job queue on startup
event_based_impl, // not enqueued to the job queue on startup
default_event_based_impl // scheduler enqueues a 'RUN' message on startup
};
class scheduled_actor;
/**
* @brief A base class for cooperatively scheduled actors.
* @extends local_actor
*/
class scheduled_actor : public extend<local_actor>::with<threadless> {
typedef combined_type super;
public:
~scheduled_actor();
/**
* @brief Intrusive next pointer needed by the scheduler's job queue.
*/
scheduled_actor* next;
/**
* @brief Continues execution of this actor.
* @param next_job Denotes the next actor to be resumed, should be
* set in case of chaining.
* @note This member function is called from the scheduler's worker threads.
*/
virtual resume_result resume(util::fiber* from) = 0;
/**
* @brief Called once by the scheduler after actor is initialized,
* but before @p resume is called.
*/
void attach_to_scheduler(scheduler* sched, bool hidden);
/**
* @brief Returns @p false if this actor can be disposed immediately
* after construction, @p true otherwise.
*/
virtual bool has_behavior() = 0;
/**
* @brief Denotes wheter this actor is enqueued to the scheduler's
* job queue on startup.
*/
virtual scheduled_actor_type impl_type() = 0;
/**
* @brief Returns @p true if this actor is ignored by
* {@link await_all_actors_done()}, false otherwise.
*/
inline bool is_hidden() const;
virtual void run_detached();
void enqueue(const message_header&, any_tuple) override;
protected:
scheduled_actor(actor_state init_state, bool enable_chained_send);
void cleanup(std::uint32_t reason) override;
typedef intrusive::single_reader_queue<mailbox_element, detail::disposer>
mailbox_type;
actor_state compare_exchange_state(actor_state expected, actor_state desired);
inline void set_state(actor_state new_value) {
m_state.store(new_value);
}
inline actor_state state() const {
return m_state;
}
bool initialized() const;
private:
bool enqueue_impl(actor_state, const message_header&, any_tuple&&);
std::atomic<actor_state> m_state;
protected:
scheduler* m_scheduler;
bool m_hidden;
};
typedef intrusive_ptr<scheduled_actor> scheduled_actor_ptr;
inline bool scheduled_actor::is_hidden() const {
return m_hidden;
}
} // namespace cppa
#endif // CPPA_ACTOR_BEHAVIOR_HPP
...@@ -41,8 +41,8 @@ ...@@ -41,8 +41,8 @@
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/cow_tuple.hpp" #include "cppa/cow_tuple.hpp"
#include "cppa/resumable.hpp"
#include "cppa/attachable.hpp" #include "cppa/attachable.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/spawn_options.hpp" #include "cppa/spawn_options.hpp"
#include "cppa/util/duration.hpp" #include "cppa/util/duration.hpp"
...@@ -52,7 +52,7 @@ namespace cppa { ...@@ -52,7 +52,7 @@ namespace cppa {
class untyped_actor; class untyped_actor;
class scheduled_actor; class scheduled_actor;
class scheduler_helper; class scheduler_helper;
class event_based_actor; class untyped_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
...@@ -83,12 +83,9 @@ class scheduler { ...@@ -83,12 +83,9 @@ class scheduler {
public: public:
typedef std::function<void(local_actor*)> init_callback; actor printer() const;
typedef std::function<behavior(untyped_actor*)> actor_fun;
const actor& printer() const;
virtual void enqueue(scheduled_actor*) = 0; virtual void enqueue(resumable*) = 0;
/** /**
* @brief Informs the scheduler about a converted context * @brief Informs the scheduler about a converted context
...@@ -128,33 +125,13 @@ class scheduler { ...@@ -128,33 +125,13 @@ class scheduler {
//TODO: delayed_send_helper()->enqueue(nullptr, std::move(tup)); //TODO: delayed_send_helper()->enqueue(nullptr, std::move(tup));
} }
/**
* @brief Executes @p ptr in this scheduler.
*/
virtual local_actor_ptr exec(spawn_options opts,
scheduled_actor_ptr ptr) = 0;
/**
* @brief Creates a new actor from @p actor_behavior and executes it
* in this scheduler.
*/
virtual local_actor_ptr exec(spawn_options opts,
init_callback init_cb,
actor_fun actor_behavior) = 0;
template<typename F, typename T, typename... Ts>
local_actor_ptr exec(spawn_options opts, init_callback cb,
F f, T&& a0, Ts&&... as) {
return this->exec(opts, cb, std::bind(f, std::forward<T>(a0), std::forward<Ts>(as)...));
}
private: private:
static scheduler* create_singleton(); static scheduler* create_singleton();
inline void dispose() { delete this; } inline void dispose() { delete this; }
actor& delayed_send_helper(); actor delayed_send_helper();
scheduler_helper* m_helper; scheduler_helper* m_helper;
......
...@@ -25,130 +25,54 @@ ...@@ -25,130 +25,54 @@
* * * *
* 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_SCOPED_ACTOR_HPP #ifndef CPPA_SCOPED_ACTOR_HPP
#define CPPA_SCOPED_ACTOR_HPP #define CPPA_SCOPED_ACTOR_HPP
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/thread_mapped_actor.hpp" #include "cppa/blocking_untyped_actor.hpp"
namespace cppa { namespace cppa {
class scoped_actor { class scoped_actor {
public: public:
/**
* @brief Dequeues the next message from the mailbox that
* is matched by given behavior.
*/
template<typename... Ts>
void receive(Ts&&... args);
/**
* @brief Receives messages in an endless loop.
* Semantically equal to: <tt>for (;;) { receive(...); }</tt>
*/
template<typename... Ts>
void receive_loop(Ts&&... args);
/**
* @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>
detail::receive_for_helper<T> receive_for(T& begin, const T& 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>
detail::receive_while_helper<Statement> receive_while(Statement&& 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>
detail::do_receive_helper do_receive(Ts&&... args);
private:
intrusive_ptr<thread_mapped_actor> m_self;
}; scoped_actor();
~scoped_actor();
inline blocking_untyped_actor* operator->() const {
return m_self.get();
}
inline blocking_untyped_actor& operator*() const {
return *m_self;
}
inline blocking_untyped_actor* get() const {
return m_self.get();
}
operator channel() const {
return get();
}
/****************************************************************************** operator actor() const {
* inline and template function implementations * return get();
******************************************************************************/ }
template<typename... Ts> operator actor_addr() const {
void scoped_actor::receive(Ts&&... args) { return get()->address();
m_self->receive(std::forward<Ts(args)...); }
}
private:
template<typename... Ts>
void scoped_actor::receive_loop(Ts&&... args) { intrusive_ptr<blocking_untyped_actor> m_self;
m_self->receive_loop(std::forward<Ts(args)...);
} };
template<typename T>
detail::receive_for_helper<T> scoped_actor::receive_for(T& begin, const T& end) {
m_self->receive_for(begin, end);
}
template<typename Statement>
detail::receive_while_helper<Statement> scoped_actor::receive_while(Statement&& stmt) {
m_self->receive_while(std::forward<Statement(stmt));
}
template<typename... Ts>
detail::do_receive_helper scoped_actor::do_receive(Ts&&... args) {
m_self->do_receive(std::forward<Ts(args)...);
}
} // namespace cppa } // namespace cppa
......
...@@ -39,17 +39,11 @@ ...@@ -39,17 +39,11 @@
#include "cppa/spawn_options.hpp" #include "cppa/spawn_options.hpp"
#include "cppa/detail/proper_actor.hpp" #include "cppa/detail/proper_actor.hpp"
#include "cppa/detail/functor_based_actor.hpp"
#include "cppa/detail/functor_based_blocking_actor.hpp"
namespace cppa { namespace cppa {
/** @cond PRIVATE */
constexpr bool unbound_spawn_options(spawn_options opts) {
return !has_monitor_flag(opts) && !has_link_flag(opts);
}
/** @endcond */
/** /**
* @ingroup ActorCreation * @ingroup ActorCreation
* @{ * @{
...@@ -58,17 +52,21 @@ constexpr bool unbound_spawn_options(spawn_options opts) { ...@@ -58,17 +52,21 @@ constexpr bool unbound_spawn_options(spawn_options opts) {
/** /**
* @brief Spawns an actor of type @p Impl. * @brief Spawns an actor of type @p Impl.
* @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 untyped_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} 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, typename... Ts>
actor spawn(Ts&&... args) { actor spawn(Ts&&... args) {
static_assert(std::is_base_of<event_based_actor, Impl>::value, static_assert(std::is_base_of<untyped_actor, Impl>::value ||
"Impl is not a derived type of event_based_actor"); (std::is_base_of<blocking_untyped_actor, Impl>::value &&
static_assert(unbound_spawn_options(Options), has_blocking_api_flag(Options)),
"Impl is not a derived type of untyped_actor or "
"is a derived type of blocking_untyped_actor but "
"blocking_api_flag is missing");
static_assert(is_unbound(Options),
"top-level spawns cannot have monitor or link flag"); "top-level spawns cannot have monitor or link flag");
static_assert(unbound_spawn_options(Options), static_assert(is_unbound(Options),
"top-level spawns cannot have monitor or link flag"); "top-level spawns cannot have monitor or link flag");
using scheduling_policy = typename std::conditional< using scheduling_policy = typename std::conditional<
has_detach_flag(Options), has_detach_flag(Options),
...@@ -100,6 +98,8 @@ actor spawn(Ts&&... args) { ...@@ -100,6 +98,8 @@ actor spawn(Ts&&... args) {
resume_policy, resume_policy,
invoke_policy>; invoke_policy>;
auto ptr = make_counted<proper_impl>(std::forward<Ts>(args)...); auto ptr = make_counted<proper_impl>(std::forward<Ts>(args)...);
ptr->launch();
return ptr;
/* /*
scheduled_actor_ptr ptr; scheduled_actor_ptr ptr;
if (has_priority_aware_flag(Options)) { if (has_priority_aware_flag(Options)) {
...@@ -121,7 +121,8 @@ actor spawn(Ts&&... args) { ...@@ -121,7 +121,8 @@ actor spawn(Ts&&... args) {
* @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} 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>
template<spawn_options Options, typename... Ts>
actor 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");
using base_class = typename std::conditional< using base_class = typename std::conditional<
...@@ -129,13 +130,7 @@ actor spawn(Ts&&... args) { ...@@ -129,13 +130,7 @@ actor spawn(Ts&&... args) {
detail::functor_based_blocking_actor, detail::functor_based_blocking_actor,
detail::functor_based_actor detail::functor_based_actor
>::type; >::type;
return spawn<base_class>(std::forward<Ts>(args)...); return spawn<base_class, Options>(std::forward<Ts>(args)...);
using impl = detail::proper_actor<untyped_actor,
scheduling_policy,
priority_policy,
resume_policy,
invoke_policy>;
return make_counted<impl>();
} }
/** /**
...@@ -163,7 +158,7 @@ actor spawn_in_group(const group_ptr& grp, Ts&&... args) { ...@@ -163,7 +158,7 @@ actor spawn_in_group(const group_ptr& grp, Ts&&... args) {
/** /**
* @brief Spawns an actor of type @p Impl that immediately joins @p grp. * @brief Spawns an actor of type @p Impl that immediately joins @p grp.
* @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 untyped_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} 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.
......
...@@ -173,6 +173,21 @@ constexpr bool has_blocking_api_flag(spawn_options opts) { ...@@ -173,6 +173,21 @@ constexpr bool has_blocking_api_flag(spawn_options opts) {
/** @} */ /** @} */
/** @cond PRIVATE */
constexpr bool is_unbound(spawn_options opts) {
return !has_monitor_flag(opts) && !has_link_flag(opts);
}
constexpr spawn_options make_unbound(spawn_options opts) {
return static_cast<spawn_options>(
(static_cast<int>(opts)
& ~static_cast<int>(spawn_options::link_flag))
& ~static_cast<int>(spawn_options::monitor_flag));
}
/** @endcond */
} // namespace cppa } // namespace cppa
#endif // CPPA_SPAWN_OPTIONS_HPP #endif // CPPA_SPAWN_OPTIONS_HPP
...@@ -72,6 +72,10 @@ inline std::string to_string(const actor& what) { ...@@ -72,6 +72,10 @@ inline std::string to_string(const actor& what) {
return detail::to_string_impl(what); return detail::to_string_impl(what);
} }
inline std::string to_string(const actor_addr& what) {
return detail::to_string_impl(what);
}
inline std::string to_string(const group_ptr& what) { inline std::string to_string(const group_ptr& what) {
return detail::to_string_impl(what); return detail::to_string_impl(what);
} }
......
...@@ -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_TYPED_ACTOR_HPP #ifndef CPPA_TYPED_ACTOR_HPP
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "cppa/replies_to.hpp" #include "cppa/replies_to.hpp"
#include "cppa/typed_behavior.hpp" #include "cppa/typed_behavior.hpp"
#include "cppa/message_future.hpp" #include "cppa/message_future.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/untyped_actor.hpp"
#include "cppa/detail/typed_actor_util.hpp" #include "cppa/detail/typed_actor_util.hpp"
...@@ -44,7 +44,7 @@ template<typename... Signatures> ...@@ -44,7 +44,7 @@ template<typename... Signatures>
class typed_actor_ptr; class typed_actor_ptr;
template<typename... Signatures> template<typename... Signatures>
class typed_actor : public event_based_actor { class typed_actor : public untyped_actor {
public: public:
......
...@@ -25,103 +25,30 @@ ...@@ -25,103 +25,30 @@
* * * *
* 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_UNTYPED_ACTOR_HPP #ifndef CPPA_UNTYPED_ACTOR_HPP
#define CPPA_UNTYPED_ACTOR_HPP #define CPPA_UNTYPED_ACTOR_HPP
#include "cppa/extend.hpp" #include "cppa/extend.hpp"
#include "cppa/stackless.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/mailbox_based.hpp" #include "cppa/mailbox_based.hpp"
#include "cppa/behavior_stack_based.hpp"
namespace cppa { namespace cppa {
/** /**
* @extends local_actor * @extends local_actor
*/ */
class untyped_actor : public local_actor { class untyped_actor : public extend<local_actor>::with<mailbox_based,
behavior_stack_based> {
bool has_behavior() {
return this->m_bhvr_stack.empty() == false;
}
void unbecome() {
this->m_bhvr_stack.pop_async_back();
}
/**
* @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) {
if (bhvr.timeout().valid()) {
this->reset_timeout();
this->request_timeout(bhvr.timeout());
}
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 {
return this->m_bhvr_stack.empty() == false;
}
inline behavior& get_behavior() {
CPPA_REQUIRE(this->m_bhvr_stack.empty() == false);
return this->m_bhvr_stack.back();
}
inline void handle_timeout(behavior& bhvr) {
CPPA_REQUIRE(bhvr.timeout().valid());
this->reset_timeout();
bhvr.handle_timeout();
if (this->m_bhvr_stack.empty() == false) {
this->request_timeout(get_behavior().timeout());
}
}
void exec_bhvr_stack() {
while (!m_bhvr_stack.empty()) {
m_bhvr_stack.exec(m_recv_policy, util::dptr<Subtype>(this));
}
}
inline detail::behavior_stack& bhvr_stack() {
return m_bhvr_stack;
}
inline optional<behavior&> sync_handler(message_id msg_id) {
return m_bhvr_stack.sync_handler(msg_id);
}
protected: protected:
// allows actors to keep previous behaviors and enables unbecome() virtual behavior make_behavior() = 0;
detail::behavior_stack m_bhvr_stack;
void forward_to(const actor& other);
}; };
......
...@@ -110,17 +110,17 @@ constexpr int min_req_interval = 10; ...@@ -110,17 +110,17 @@ constexpr int min_req_interval = 10;
constexpr int max_req_interval = 300; constexpr int max_req_interval = 300;
const actor_ostream& print(const char* color_code, const char* actor_name) { const actor_ostream& print(const char* color_code, const char* actor_name) {
return aout << color_code << actor_name << " (id = " << self->id() << "): "; return aout << color_code << actor_name;// << " (id = " << self->id() << "): ";
} }
} // namespace <anonymous> } // namespace <anonymous>
// provides print utility and each base_actor has a parent // provides print utility and each base_actor has a parent
class base_actor : public event_based_actor { class base_actor : public untyped_actor {
protected: protected:
base_actor(actor_ptr parent, std::string name, std::string color_code) base_actor(actor parent, std::string name, std::string color_code)
: m_parent(std::move(parent)) : m_parent(std::move(parent))
, m_name(std::move(name)) , m_name(std::move(name))
, m_color(std::move(color_code)) { } , m_color(std::move(color_code)) { }
...@@ -133,7 +133,7 @@ class base_actor : public event_based_actor { ...@@ -133,7 +133,7 @@ class base_actor : public event_based_actor {
print() << "on_exit" << color::reset_endl; print() << "on_exit" << color::reset_endl;
} }
actor_ptr m_parent; actor m_parent;
private: private:
...@@ -147,19 +147,19 @@ class client_job : public base_actor { ...@@ -147,19 +147,19 @@ class client_job : public base_actor {
public: public:
client_job(actor_ptr parent) client_job(actor parent)
: base_actor(std::move(parent), "client_job", color::blue) { } : base_actor(std::move(parent), "client_job", color::blue) { }
protected: protected:
void init() override { behavior make_behavior() override {
print() << "init" << color::reset_endl; print() << "init" << color::reset_endl;
send(m_parent, send(m_parent,
atom("read"), atom("read"),
"http://www.example.com/index.html", "http://www.example.com/index.html",
static_cast<uint64_t>(0), static_cast<uint64_t>(0),
static_cast<uint64_t>(4095)); static_cast<uint64_t>(4095));
become ( return (
on(atom("reply"), arg_match) >> [=](const util::buffer& buf) { on(atom("reply"), arg_match) >> [=](const util::buffer& buf) {
print() << "successfully received " print() << "successfully received "
<< buf.size() << buf.size()
...@@ -181,18 +181,18 @@ class client : public base_actor { ...@@ -181,18 +181,18 @@ class client : public base_actor {
public: public:
client(const actor_ptr& parent) client(const actor& parent)
: base_actor(parent, "client", color::green), m_count(0) { } : base_actor(parent, "client", color::green), m_count(0) { }
protected: protected:
void init() override { behavior make_behavior() override {
using std::chrono::milliseconds; using std::chrono::milliseconds;
link_to(m_parent); link_to(m_parent);
print() << "init" << color::reset_endl; print() << "init" << color::reset_endl;
// start 'loop' // start 'loop'
send(this, atom("next")); send(this, atom("next"));
become ( return (
on(atom("next")) >> [=] { on(atom("next")) >> [=] {
print() << "spawn new client_job (nr. " print() << "spawn new client_job (nr. "
<< ++m_count << ++m_count
...@@ -203,7 +203,7 @@ class client : public base_actor { ...@@ -203,7 +203,7 @@ class client : public base_actor {
spawn<client_job, detached+linked>(m_parent); spawn<client_job, detached+linked>(m_parent);
// compute random delay until next job is launched // compute random delay until next job is launched
auto delay = (rand() + min_req_interval) % max_req_interval; auto delay = (rand() + min_req_interval) % max_req_interval;
delayed_send(self, milliseconds(delay), atom("next")); delayed_send(this, milliseconds(delay), atom("next"));
} }
); );
} }
...@@ -219,17 +219,17 @@ class curl_worker : public base_actor { ...@@ -219,17 +219,17 @@ class curl_worker : public base_actor {
public: public:
curl_worker(const actor_ptr& parent) curl_worker(const actor& parent)
: base_actor(parent, "curl_worker", color::yellow) { } : base_actor(parent, "curl_worker", color::yellow) { }
protected: protected:
void init() override { behavior make_behavior() override {
print() << "init" << color::reset_endl; print() << "init" << color::reset_endl;
m_curl = curl_easy_init(); m_curl = curl_easy_init();
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, &curl_worker::cb); curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, &curl_worker::cb);
curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1);
become ( return (
on(atom("read"), arg_match) on(atom("read"), arg_match)
>> [=](const std::string& fname, uint64_t offset, uint64_t range) >> [=](const std::string& fname, uint64_t offset, uint64_t range)
-> cow_tuple<atom_value, util::buffer> { -> cow_tuple<atom_value, util::buffer> {
...@@ -314,31 +314,32 @@ class curl_master : public base_actor { ...@@ -314,31 +314,32 @@ class curl_master : public base_actor {
protected: protected:
void init() override { behavior make_behavior() override {
print() << "init" << color::reset_endl; print() << "init" << color::reset_endl;
// spawn workers // spawn workers
for(size_t i = 0; i < num_curl_workers; ++i) { for(size_t i = 0; i < num_curl_workers; ++i) {
m_idle_worker.push_back(spawn<curl_worker, detached+linked>(this)); m_idle_worker.push_back(spawn<curl_worker, detached+linked>(this));
} }
auto worker_finished = [=] { auto worker_finished = [=] {
actor_ptr sender = self->last_sender(); auto sender = last_sender();
m_busy_worker.erase(std::find(m_busy_worker.begin(), auto i = std::find(m_busy_worker.begin(),
m_busy_worker.end(), m_busy_worker.end(),
sender)); sender);
m_idle_worker.push_back(sender); m_idle_worker.push_back(*i);
m_busy_worker.erase(i);
print() << "worker is done" << color::reset_endl; print() << "worker is done" << color::reset_endl;
}; };
print() << "spawned " print() << "spawned "
<< m_idle_worker.size() << m_idle_worker.size()
<< " worker" << " worker"
<< color::reset_endl; << color::reset_endl;
become ( return (
on(atom("read"), arg_match) >> [=](const std::string&, on(atom("read"), arg_match) >> [=](const std::string&,
uint64_t, uint64_t,
uint64_t) { uint64_t) {
print() << "received {'read'}" << color::reset_endl; print() << "received {'read'}" << color::reset_endl;
// forward job to first idle worker // forward job to first idle worker
actor_ptr worker = m_idle_worker.front(); actor worker = m_idle_worker.front();
m_idle_worker.erase(m_idle_worker.begin()); m_idle_worker.erase(m_idle_worker.begin());
m_busy_worker.push_back(worker); m_busy_worker.push_back(worker);
forward_to(worker); forward_to(worker);
...@@ -364,8 +365,8 @@ class curl_master : public base_actor { ...@@ -364,8 +365,8 @@ class curl_master : public base_actor {
private: private:
std::vector<actor_ptr> m_idle_worker; std::vector<actor> m_idle_worker;
std::vector<actor_ptr> m_busy_worker; std::vector<actor> m_busy_worker;
}; };
...@@ -394,7 +395,7 @@ int main() { ...@@ -394,7 +395,7 @@ int main() {
while (!shutdown_flag) { sleep(1); } while (!shutdown_flag) { sleep(1); }
aout << color::cyan << "received CTRL+C" << color::reset_endl; aout << color::cyan << "received CTRL+C" << color::reset_endl;
// shutdown actors // shutdown actors
send_exit(master, exit_reason::user_shutdown); anon_send_exit(master, exit_reason::user_shutdown);
// await actors // await actors
act.sa_handler = [](int) { abort(); }; act.sa_handler = [](int) { abort(); };
set_sighandler(); set_sighandler();
......
...@@ -5,11 +5,11 @@ ...@@ -5,11 +5,11 @@
using namespace std; using namespace std;
using namespace cppa; using namespace cppa;
void mirror() { behavior mirror(untyped_actor* self) {
// wait for messages // wait for messages
become ( return (
// invoke this lambda expression if we receive a string // invoke this lambda expression if we receive a string
on_arg_match >> [](const string& what) -> string { on_arg_match >> [=](const string& what) -> string {
// prints "Hello World!" via aout (thread-safe cout wrapper) // prints "Hello World!" via aout (thread-safe cout wrapper)
aout << what << endl; aout << what << endl;
// terminates this actor ('become' otherwise loops forever) // terminates this actor ('become' otherwise loops forever)
...@@ -20,11 +20,11 @@ void mirror() { ...@@ -20,11 +20,11 @@ void mirror() {
); );
} }
void hello_world(const actor_ptr& buddy) { void hello_world(untyped_actor* self, const actor& buddy) {
// send "Hello World!" to our buddy ... // send "Hello World!" to our buddy ...
sync_send(buddy, "Hello World!").then( self->sync_send(buddy, "Hello World!").then(
// ... and wait for a response // ... and wait for a response
on_arg_match >> [](const string& what) { on_arg_match >> [=](const string& what) {
// prints "!dlroW olleH" // prints "!dlroW olleH"
aout << what << endl; aout << what << endl;
} }
......
...@@ -13,9 +13,9 @@ using std::endl; ...@@ -13,9 +13,9 @@ using std::endl;
using namespace cppa; using namespace cppa;
// implementation using the blocking API // implementation using the blocking API
void blocking_math_fun() { void blocking_math_fun(blocking_untyped_actor* self) {
bool done = false; bool done = false;
do_receive ( self->do_receive (
// "arg_match" matches the parameter types of given lambda expression // "arg_match" matches the parameter types of given lambda expression
// thus, it's equal to // thus, it's equal to
// - on<atom("plus"), int, int>() // - on<atom("plus"), int, int>()
...@@ -34,38 +34,38 @@ void blocking_math_fun() { ...@@ -34,38 +34,38 @@ void blocking_math_fun() {
).until(gref(done)); ).until(gref(done));
} }
void calculator() { void calculator(untyped_actor* self) {
// execute this behavior until actor terminates // execute this behavior until actor terminates
become ( self->become (
on(atom("plus"), arg_match) >> [](int a, int b) { on(atom("plus"), arg_match) >> [](int a, int b) {
return make_cow_tuple(atom("result"), a + b); return make_cow_tuple(atom("result"), a + b);
}, },
on(atom("minus"), arg_match) >> [](int a, int b) { on(atom("minus"), arg_match) >> [](int a, int b) {
return make_cow_tuple(atom("result"), a - b); return make_cow_tuple(atom("result"), a - b);
}, },
on(atom("quit")) >> [] { on(atom("quit")) >> [=] {
// terminate actor with normal exit reason // terminate actor with normal exit reason
self->quit(); self->quit();
} }
); );
} }
void tester(const actor_ptr& testee) { void tester(untyped_actor* self, const actor& testee) {
self->link_to(testee); self->link_to(testee);
// will be invoked if we receive an unexpected response message // will be invoked if we receive an unexpected response message
self->on_sync_failure([] { self->on_sync_failure([=] {
aout << "AUT (actor under test) failed" << endl; aout << "AUT (actor under test) failed" << endl;
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
}); });
// first test: 2 + 1 = 3 // first test: 2 + 1 = 3
sync_send(testee, atom("plus"), 2, 1).then( self->sync_send(testee, atom("plus"), 2, 1).then(
on(atom("result"), 3) >> [=] { on(atom("result"), 3) >> [=] {
// second test: 2 - 1 = 1 // second test: 2 - 1 = 1
sync_send(testee, atom("minus"), 2, 1).then( self->sync_send(testee, atom("minus"), 2, 1).then(
on(atom("result"), 1) >> [=] { on(atom("result"), 1) >> [=] {
// both tests succeeded // both tests succeeded
aout << "AUT (actor under test) seems to be ok" << endl; aout << "AUT (actor under test) seems to be ok" << endl;
send(testee, atom("quit")); self->send(testee, atom("quit"));
} }
); );
} }
...@@ -78,4 +78,3 @@ int main() { ...@@ -78,4 +78,3 @@ int main() {
shutdown(); shutdown();
return 0; return 0;
} }
...@@ -53,20 +53,20 @@ void draw_kirby(const animation_step& animation) { ...@@ -53,20 +53,20 @@ void draw_kirby(const animation_step& animation) {
} }
// uses a message-based loop to iterate over all animation steps // uses a message-based loop to iterate over all animation steps
void dancing_kirby() { void dancing_kirby(untyped_actor* self) {
// let's get it started // let's get it started
send(self, atom("Step"), size_t{0}); self->send(self, atom("Step"), size_t{0});
become ( self->become (
on(atom("Step"), array_size(animation_steps)) >> [] { on(atom("Step"), array_size(animation_steps)) >> [=] {
// we've printed all animation steps (done) // we've printed all animation steps (done)
cout << endl; cout << endl;
self->quit(); self->quit();
}, },
on(atom("Step"), arg_match) >> [](size_t step) { on(atom("Step"), arg_match) >> [=](size_t step) {
// print given step // print given step
draw_kirby(animation_steps[step]); draw_kirby(animation_steps[step]);
// animate next step in 150ms // animate next step in 150ms
delayed_send(self, std::chrono::milliseconds(150), atom("Step"), step + 1); self->delayed_send(self, std::chrono::milliseconds(150), atom("Step"), step + 1);
} }
); );
} }
......
...@@ -17,21 +17,21 @@ using namespace std; ...@@ -17,21 +17,21 @@ using namespace std;
using namespace cppa; using namespace cppa;
// either taken by a philosopher or available // either taken by a philosopher or available
void chopstick() { void chopstick(untyped_actor* self) {
become( self->become(
on(atom("take"), arg_match) >> [=](const actor_ptr& philos) { on(atom("take"), arg_match) >> [=](const actor& philos) {
// tell philosopher it took this chopstick // tell philosopher it took this chopstick
send(philos, atom("taken"), self); self->send(philos, atom("taken"), self);
// await 'put' message and reject other 'take' messages // await 'put' message and reject other 'take' messages
become( self->become(
// allows us to return to the previous behavior // allows us to return to the previous behavior
keep_behavior, keep_behavior,
on(atom("take"), arg_match) >> [=](const actor_ptr& other) { on(atom("take"), arg_match) >> [=](const actor& other) {
send(other, atom("busy"), self); self->send(other, atom("busy"), self);
}, },
on(atom("put"), philos) >> [=] { on(atom("put"), philos) >> [=] {
// return to previous behaivor, i.e., await next 'take' // return to previous behaivor, i.e., await next 'take'
unbecome(); self->unbecome();
} }
); );
} }
...@@ -71,11 +71,11 @@ void chopstick() { ...@@ -71,11 +71,11 @@ void chopstick() {
* [ X = right => Y = left ] * [ X = right => Y = left ]
*/ */
struct philosopher : event_based_actor { struct philosopher : untyped_actor {
std::string name; // the name of this philosopher std::string name; // the name of this philosopher
actor_ptr left; // left chopstick actor left; // left chopstick
actor_ptr right; // right chopstick actor right; // right chopstick
// note: we have to define all behaviors in the constructor because // note: we have to define all behaviors in the constructor because
// non-static member initialization are not (yet) implemented in GCC // non-static member initialization are not (yet) implemented in GCC
...@@ -85,7 +85,7 @@ struct philosopher : event_based_actor { ...@@ -85,7 +85,7 @@ struct philosopher : event_based_actor {
behavior eating; behavior eating;
// wait for second chopstick // wait for second chopstick
behavior waiting_for(const actor_ptr& what) { behavior waiting_for(const actor& what) {
return ( return (
on(atom("taken"), what) >> [=] { on(atom("taken"), what) >> [=] {
aout << name aout << name
...@@ -106,7 +106,7 @@ struct philosopher : event_based_actor { ...@@ -106,7 +106,7 @@ struct philosopher : event_based_actor {
); );
} }
philosopher(const std::string& n, const actor_ptr& l, const actor_ptr& r) philosopher(const std::string& n, const actor& l, const actor& r)
: name(n), left(l), right(r) { : name(n), left(l), right(r) {
// a philosopher that receives {eat} stops thinking and becomes hungry // a philosopher that receives {eat} stops thinking and becomes hungry
thinking = ( thinking = (
...@@ -124,18 +124,18 @@ struct philosopher : event_based_actor { ...@@ -124,18 +124,18 @@ struct philosopher : event_based_actor {
on(atom("taken"), right) >> [=] { on(atom("taken"), right) >> [=] {
become(waiting_for(left)); become(waiting_for(left));
}, },
on<atom("busy"), actor_ptr>() >> [=] { on<atom("busy"), actor>() >> [=] {
become(denied); become(denied);
} }
); );
// philosopher was not able to obtain the first chopstick // philosopher was not able to obtain the first chopstick
denied = ( denied = (
on(atom("taken"), arg_match) >> [=](const actor_ptr& ptr) { on(atom("taken"), arg_match) >> [=](const actor& ptr) {
send(ptr, atom("put"), this); send(ptr, atom("put"), this);
send(this, atom("eat")); send(this, atom("eat"));
become(thinking); become(thinking);
}, },
on<atom("busy"), actor_ptr>() >> [=] { on<atom("busy"), actor>() >> [=] {
send(this, atom("eat")); send(this, atom("eat"));
become(thinking); become(thinking);
} }
...@@ -153,17 +153,17 @@ struct philosopher : event_based_actor { ...@@ -153,17 +153,17 @@ struct philosopher : event_based_actor {
); );
} }
void init() { behavior make_behavior() override {
// start thinking
send(this, atom("think"));
// philosophers start to think after receiving {think} // philosophers start to think after receiving {think}
become ( return (
on(atom("think")) >> [=] { on(atom("think")) >> [=] {
aout << name << " starts to think\n"; aout << name << " starts to think\n";
delayed_send(this, seconds(5), atom("eat")); delayed_send(this, seconds(5), atom("eat"));
become(thinking); become(thinking);
} }
); );
// start thinking
send(this, atom("think"));
} }
}; };
...@@ -171,7 +171,7 @@ struct philosopher : event_based_actor { ...@@ -171,7 +171,7 @@ struct philosopher : event_based_actor {
int main(int, char**) { int main(int, char**) {
// create five chopsticks // create five chopsticks
aout << "chopstick ids are:"; aout << "chopstick ids are:";
std::vector<actor_ptr> chopsticks; std::vector<actor> chopsticks;
for (size_t i = 0; i < 5; ++i) { for (size_t i = 0; i < 5; ++i) {
chopsticks.push_back(spawn(chopstick)); chopsticks.push_back(spawn(chopstick));
aout << " " << chopsticks.back()->id(); aout << " " << chopsticks.back()->id();
......
...@@ -26,15 +26,15 @@ using namespace cppa; ...@@ -26,15 +26,15 @@ using namespace cppa;
using namespace cppa::placeholders; using namespace cppa::placeholders;
// our "service" // our "service"
void calculator() { void calculator(untyped_actor* self) {
become ( self->become (
on(atom("plus"), arg_match) >> [](int a, int b) -> any_tuple { on(atom("plus"), arg_match) >> [](int a, int b) -> any_tuple {
return {atom("result"), a + b}; return make_any_tuple(atom("result"), a + b);
}, },
on(atom("minus"), arg_match) >> [](int a, int b) -> any_tuple { on(atom("minus"), arg_match) >> [](int a, int b) -> any_tuple {
return {atom("result"), a - b}; return make_any_tuple(atom("result"), a - b);
}, },
on(atom("quit")) >> [=]() { on(atom("quit")) >> [=] {
self->quit(); self->quit();
} }
); );
...@@ -49,12 +49,12 @@ inline string trim(std::string s) { ...@@ -49,12 +49,12 @@ inline string trim(std::string s) {
return s; return s;
} }
void client_bhvr(const string& host, uint16_t port, const actor_ptr& server) { void client_bhvr(untyped_actor* self, const string& host, uint16_t port, const actor& server) {
// recover from sync failures by trying to reconnect to server // recover from sync failures by trying to reconnect to server
if (!self->has_sync_failure_handler()) { if (!self->has_sync_failure_handler()) {
self->on_sync_failure([=] { self->on_sync_failure([=] {
aout << "*** lost connection to " << host << ":" << port << endl; aout << "*** lost connection to " << host << ":" << port << endl;
client_bhvr(host, port, nullptr); client_bhvr(self, host, port, nullptr);
}); });
} }
// connect to server if needed // connect to server if needed
...@@ -64,17 +64,17 @@ void client_bhvr(const string& host, uint16_t port, const actor_ptr& server) { ...@@ -64,17 +64,17 @@ void client_bhvr(const string& host, uint16_t port, const actor_ptr& server) {
auto new_serv = remote_actor(host, port); auto new_serv = remote_actor(host, port);
self->monitor(new_serv); self->monitor(new_serv);
aout << "reconnection succeeded" << endl; aout << "reconnection succeeded" << endl;
client_bhvr(host, port, new_serv); client_bhvr(self, host, port, new_serv);
return; return;
} }
catch (exception&) { catch (exception&) {
aout << "connection failed, try again in 3s" << endl; aout << "connection failed, try again in 3s" << endl;
delayed_send(self, chrono::seconds(3), atom("reconnect")); self->delayed_send(self, chrono::seconds(3), atom("reconnect"));
} }
} }
become ( self->become (
on_arg_match.when(_x1.in({atom("plus"), atom("minus")}) && gval(server) != nullptr) >> [=](atom_value op, int lhs, int rhs) { on_arg_match.when(_x1.in({atom("plus"), atom("minus")}) && gval(server) != nullptr) >> [=](atom_value op, int lhs, int rhs) {
sync_send_tuple(server, self->last_dequeued()).then( self->sync_send_tuple(server, self->last_dequeued()).then(
on(atom("result"), arg_match) >> [=](int result) { on(atom("result"), arg_match) >> [=](int result) {
aout << lhs << " " aout << lhs << " "
<< to_string(op) << " " << to_string(op) << " "
...@@ -85,14 +85,14 @@ void client_bhvr(const string& host, uint16_t port, const actor_ptr& server) { ...@@ -85,14 +85,14 @@ void client_bhvr(const string& host, uint16_t port, const actor_ptr& server) {
}, },
on(atom("DOWN"), arg_match) >> [=](uint32_t) { on(atom("DOWN"), arg_match) >> [=](uint32_t) {
aout << "*** server down, try to reconnect ..." << endl; aout << "*** server down, try to reconnect ..." << endl;
client_bhvr(host, port, nullptr); client_bhvr(self, host, port, nullptr);
}, },
on(atom("rebind"), arg_match) >> [=](const string& host, uint16_t port) { on(atom("rebind"), arg_match) >> [=](const string& host, uint16_t port) {
aout << "*** rebind to new server: " << host << ":" << port << endl; aout << "*** rebind to new server: " << host << ":" << port << endl;
client_bhvr(host, port, nullptr); client_bhvr(self, host, port, nullptr);
}, },
on(atom("reconnect")) >> [=] { on(atom("reconnect")) >> [=] {
client_bhvr(host, port, nullptr); client_bhvr(self, host, port, nullptr);
} }
); );
} }
...@@ -112,7 +112,7 @@ void client_repl(const string& host, uint16_t port) { ...@@ -112,7 +112,7 @@ void client_repl(const string& host, uint16_t port) {
line = trim(std::move(line)); // ignore leading and trailing whitespaces line = trim(std::move(line)); // ignore leading and trailing whitespaces
if (line == "quit") { if (line == "quit") {
// force client to quit // force client to quit
send_exit(client, exit_reason::user_shutdown); anon_send_exit(client, exit_reason::user_shutdown);
return; return;
} }
// the STL way of line.starts_with("connect") // the STL way of line.starts_with("connect")
...@@ -123,7 +123,7 @@ void client_repl(const string& host, uint16_t port) { ...@@ -123,7 +123,7 @@ void client_repl(const string& host, uint16_t port) {
auto lport = std::stoul(sport); auto lport = std::stoul(sport);
if (lport < std::numeric_limits<uint16_t>::max()) { if (lport < std::numeric_limits<uint16_t>::max()) {
auto port = static_cast<uint16_t>(lport); auto port = static_cast<uint16_t>(lport);
send(client, atom("rebind"), move(host), port); anon_send(client, atom("rebind"), move(host), port);
} }
else { else {
aout << lport << " is not a valid port" << endl; aout << lport << " is not a valid port" << endl;
...@@ -159,7 +159,7 @@ void client_repl(const string& host, uint16_t port) { ...@@ -159,7 +159,7 @@ void client_repl(const string& host, uint16_t port) {
auto rhs = toint(rsub); auto rhs = toint(rsub);
if (lhs && rhs) { if (lhs && rhs) {
auto op = (*pos == '+') ? atom("plus") : atom("minus"); auto op = (*pos == '+') ? atom("plus") : atom("minus");
send(client, op, *lhs, *rhs); anon_send(client, op, *lhs, *rhs);
} }
} }
else if (!success) { else if (!success) {
......
...@@ -42,22 +42,22 @@ any_tuple split_line(const line& l) { ...@@ -42,22 +42,22 @@ any_tuple split_line(const line& l) {
return any_tuple::view(std::move(result)); return any_tuple::view(std::move(result));
} }
void client(const string& name) { void client(untyped_actor* self, const string& name) {
become ( self->become (
on(atom("broadcast"), arg_match) >> [=](const string& message) { on(atom("broadcast"), arg_match) >> [=](const string& message) {
for(auto& dest : self->joined_groups()) { for(auto& dest : self->joined_groups()) {
send(dest, name + ": " + message); self->send(dest, name + ": " + message);
} }
}, },
on(atom("join"), arg_match) >> [=](const group_ptr& what) { on(atom("join"), arg_match) >> [=](const group_ptr& what) {
for (auto g : self->joined_groups()) { for (auto g : self->joined_groups()) {
cout << "*** leave " << to_string(g) << endl; cout << "*** leave " << to_string(g) << endl;
send(g, name + " has left the chatroom"); self->send(self, g, name + " has left the chatroom");
self->leave(g); self->leave(g);
} }
cout << "*** join " << to_string(what) << endl; cout << "*** join " << to_string(what) << endl;
self->join(what); self->join(what);
send(what, name + " has entered the chatroom"); self->send(self, what, name + " has entered the chatroom");
}, },
on<string>() >> [=](const string& txt) { on<string>() >> [=](const string& txt) {
// don't print own messages // don't print own messages
...@@ -104,7 +104,7 @@ int main(int argc, char** argv) { ...@@ -104,7 +104,7 @@ int main(int argc, char** argv) {
try { try {
auto g = group::get(group_id.substr(0, p), auto g = group::get(group_id.substr(0, p),
group_id.substr(p + 1)); group_id.substr(p + 1));
send(client_actor, atom("join"), g); anon_send(client_actor, atom("join"), g);
} }
catch (exception& e) { catch (exception& e) {
ostringstream err; ostringstream err;
...@@ -120,7 +120,7 @@ int main(int argc, char** argv) { ...@@ -120,7 +120,7 @@ int main(int argc, char** argv) {
match_each (lines, eof, split_line) ( match_each (lines, eof, split_line) (
on("/join", arg_match) >> [&](const string& mod, const string& id) { on("/join", arg_match) >> [&](const string& mod, const string& id) {
try { try {
send(client_actor, atom("join"), group::get(mod, id)); anon_send(client_actor, atom("join"), group::get(mod, id));
} }
catch (exception& e) { catch (exception& e) {
cerr << "*** exception: " << to_verbose_string(e) << endl; cerr << "*** exception: " << to_verbose_string(e) << endl;
...@@ -137,12 +137,12 @@ int main(int argc, char** argv) { ...@@ -137,12 +137,12 @@ int main(int argc, char** argv) {
}, },
others() >> [&] { others() >> [&] {
if (!s_last_line.empty()) { if (!s_last_line.empty()) {
send(client_actor, atom("broadcast"), s_last_line); anon_send(client_actor, atom("broadcast"), s_last_line);
} }
} }
); );
// force actor to quit // force actor to quit
send_exit(client_actor, exit_reason::user_shutdown); anon_send_exit(client_actor, exit_reason::user_shutdown);
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
......
...@@ -42,12 +42,12 @@ bool operator==( const foo2& lhs, const foo2& rhs ) { ...@@ -42,12 +42,12 @@ bool operator==( const foo2& lhs, const foo2& rhs ) {
} }
// receives `remaining` messages // receives `remaining` messages
void testee(size_t remaining) { void testee(untyped_actor* self, size_t remaining) {
auto set_next_behavior = [=] { auto set_next_behavior = [=] {
if (remaining > 1) testee(remaining - 1); if (remaining > 1) testee(self, remaining - 1);
else self->quit(); else self->quit();
}; };
become ( self->become (
// note: we sent a foo_pair2, but match on foo_pair // note: we sent a foo_pair2, but match on foo_pair
// that's safe because both are aliases for std::pair<int, int> // that's safe because both are aliases for std::pair<int, int>
on<foo_pair>() >> [=](const foo_pair& val) { on<foo_pair>() >> [=](const foo_pair& val) {
...@@ -113,11 +113,13 @@ int main(int, char**) { ...@@ -113,11 +113,13 @@ int main(int, char**) {
// spawn a testee that receives two messages // spawn a testee that receives two messages
auto t = spawn(testee, 2); auto t = spawn(testee, 2);
{
scoped_actor self;
// send t a foo // send t a foo
send(t, foo{std::vector<int>{1, 2, 3, 4}, 5}); self->send(t, foo{std::vector<int>{1, 2, 3, 4}, 5});
// send t a foo_pair2 // send t a foo_pair2
send(t, foo_pair2{3, 4}); self->send(t, foo_pair2{3, 4});
}
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
......
...@@ -39,9 +39,9 @@ bool operator==(const foo& lhs, const foo& rhs) { ...@@ -39,9 +39,9 @@ bool operator==(const foo& lhs, const foo& rhs) {
&& lhs.b() == rhs.b(); && lhs.b() == rhs.b();
} }
void testee() { void testee(untyped_actor* self) {
become ( self->become (
on<foo>() >> [](const foo& val) { on<foo>() >> [=](const foo& val) {
aout << "foo(" aout << "foo("
<< val.a() << ", " << val.a() << ", "
<< val.b() << ")" << val.b() << ")"
...@@ -56,8 +56,11 @@ int main(int, char**) { ...@@ -56,8 +56,11 @@ int main(int, char**) {
// we pass those to the announce function as { getter, setter } pairs. // we pass those to the announce function as { getter, setter } pairs.
announce<foo>(make_pair(&foo::a, &foo::set_a), announce<foo>(make_pair(&foo::a, &foo::set_a),
make_pair(&foo::b, &foo::set_b)); make_pair(&foo::b, &foo::set_b));
{
scoped_actor self;
auto t = spawn(testee); auto t = spawn(testee);
send(t, foo{1, 2}); self->send(t, foo{1, 2});
}
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
......
...@@ -46,9 +46,9 @@ typedef int (foo::*foo_getter)() const; ...@@ -46,9 +46,9 @@ typedef int (foo::*foo_getter)() const;
// a member function pointer to set an attribute of foo // a member function pointer to set an attribute of foo
typedef void (foo::*foo_setter)(int); typedef void (foo::*foo_setter)(int);
void testee() { void testee(untyped_actor* self) {
become ( self->become (
on<foo>() >> [](const foo& val) { on<foo>() >> [=](const foo& val) {
aout << "foo(" aout << "foo("
<< val.a() << ", " << val.a() << ", "
<< val.b() << ")" << val.b() << ")"
...@@ -78,7 +78,10 @@ int main(int, char**) { ...@@ -78,7 +78,10 @@ int main(int, char**) {
static_cast<foo_setter>(&foo::b))); static_cast<foo_setter>(&foo::b)));
// spawn a new testee and send it a foo // spawn a new testee and send it a foo
send(spawn(testee), foo{1, 2}); {
scoped_actor self;
self->send(spawn(testee), foo{1, 2});
}
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
......
...@@ -79,12 +79,12 @@ bool operator==(const baz& lhs, const baz& rhs) { ...@@ -79,12 +79,12 @@ bool operator==(const baz& lhs, const baz& rhs) {
} }
// receives `remaining` messages // receives `remaining` messages
void testee(size_t remaining) { void testee(untyped_actor* self, size_t remaining) {
auto set_next_behavior = [=] { auto set_next_behavior = [=] {
if (remaining > 1) testee(remaining - 1); if (remaining > 1) testee(self, remaining - 1);
else self->quit(); else self->quit();
}; };
become ( self->become (
on<bar>() >> [=](const bar& val) { on<bar>() >> [=](const bar& val) {
aout << "bar(foo(" aout << "bar(foo("
<< val.f.a() << ", " << val.f.a() << ", "
...@@ -127,8 +127,11 @@ int main(int, char**) { ...@@ -127,8 +127,11 @@ int main(int, char**) {
// spawn a testee that receives two messages // spawn a testee that receives two messages
auto t = spawn(testee, 2); auto t = spawn(testee, 2);
send(t, bar{foo{1, 2}, 3}); {
send(t, baz{foo{1, 2}, bar{foo{3, 4}, 5}}); scoped_actor self;
self->send(t, bar{foo{1, 2}, 3});
self->send(t, baz{foo{1, 2}, bar{foo{3, 4}, 5}});
}
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
return 0; return 0;
......
...@@ -131,12 +131,12 @@ class tree_type_info : public util::abstract_uniform_type_info<tree> { ...@@ -131,12 +131,12 @@ class tree_type_info : public util::abstract_uniform_type_info<tree> {
typedef std::vector<tree> tree_vector; typedef std::vector<tree> tree_vector;
// receives `remaining` messages // receives `remaining` messages
void testee(size_t remaining) { void testee(untyped_actor* self, size_t remaining) {
auto set_next_behavior = [=] { auto set_next_behavior = [=] {
if (remaining > 1) testee(remaining - 1); if (remaining > 1) testee(self, remaining - 1);
else self->quit(); else self->quit();
}; };
become ( self->become (
on_arg_match >> [=](const tree& tmsg) { on_arg_match >> [=](const tree& tmsg) {
// prints the tree in its serialized format: // prints the tree in its serialized format:
// @<> ( { tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ) } ) // @<> ( { tree ( 0, { 10, { 11, { }, 12, { }, 13, { } }, 20, { 21, { }, 22, { } } } ) } )
...@@ -188,18 +188,22 @@ int main() { ...@@ -188,18 +188,22 @@ int main() {
11 12 13 21 22 11 12 13 21 22
*/ */
{ // lifetime scope of self
scoped_actor self;
// spawn a testee that receives two messages // spawn a testee that receives two messages
auto t = spawn(testee, 2); auto t = spawn(testee, 2);
// send a tree // send a tree
send(t, t0); self->send(t, t0);
// send a vector of trees // send a vector of trees
announce<tree_vector>(); announce<tree_vector>();
tree_vector tvec; tree_vector tvec;
tvec.push_back(t0); tvec.push_back(t0);
tvec.push_back(t0); tvec.push_back(t0);
send(t, tvec); self->send(t, tvec);
}
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
......
...@@ -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/>. *
\******************************************************************************/ \******************************************************************************/
#include <utility> #include <utility>
...@@ -39,6 +39,8 @@ namespace cppa { ...@@ -39,6 +39,8 @@ namespace cppa {
actor::actor(abstract_actor* ptr) : m_ops(ptr) { } actor::actor(abstract_actor* ptr) : m_ops(ptr) { }
actor::actor(const invalid_actor_t&) : m_ops(nullptr) { }
void actor::enqueue(const message_header& hdr, any_tuple msg) const { void actor::enqueue(const message_header& hdr, any_tuple msg) const {
if (m_ops.m_ptr) m_ops.m_ptr->enqueue(hdr, std::move(msg)); if (m_ops.m_ptr) m_ops.m_ptr->enqueue(hdr, std::move(msg));
} }
......
...@@ -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/>. *
\******************************************************************************/ \******************************************************************************/
#include "cppa/actor.hpp" #include "cppa/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/>. *
\******************************************************************************/ \******************************************************************************/
#include <utility> #include <utility>
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/singletons.hpp"
#include "cppa/blocking_untyped_actor.hpp"
#include "cppa/detail/actor_registry.hpp"
namespace cppa {
void blocking_untyped_actor::await_all_other_actors_done() {
get_actor_registry()->await_running_count_equal(1);
}
} // namespace cppa
...@@ -49,7 +49,8 @@ using std::cout; ...@@ -49,7 +49,8 @@ using std::cout;
using std::endl; using std::endl;
using std::move; using std::move;
namespace cppa { namespace io { namespace cppa {
namespace io {
namespace { namespace {
...@@ -57,31 +58,20 @@ constexpr size_t default_max_buffer_size = 65535; ...@@ -57,31 +58,20 @@ constexpr size_t default_max_buffer_size = 65535;
} // namespace <anonymous> } // namespace <anonymous>
class default_broker : public broker { default_broker::default_broker(input_stream_ptr in,
output_stream_ptr out,
function_type f)
: broker(std::move(in), std::move(out)), m_fun(std::move(f)) { }
public: behavior default_broker::make_behavior() {
typedef std::function<void (broker*)> function_type;
template<typename... Ts>
default_broker(function_type&& fun, Ts&&... args)
: broker{std::forward<Ts>(args)...}, m_fun{move(fun)} { }
void init() override {
enqueue({invalid_actor_addr, channel{this}}, make_any_tuple(atom("INITMSG"))); enqueue({invalid_actor_addr, channel{this}}, make_any_tuple(atom("INITMSG")));
become( return (
on(atom("INITMSG")) >> [=] { on(atom("INITMSG")) >> [=] {
unbecome(); unbecome();
m_fun(this); m_fun(this);
} }
); );
} }
private:
function_type m_fun;
};
class broker::continuation { class broker::continuation {
...@@ -299,24 +289,23 @@ void broker::invoke_message(const message_header& hdr, any_tuple msg) { ...@@ -299,24 +289,23 @@ void broker::invoke_message(const message_header& hdr, any_tuple msg) {
try { try {
using detail::receive_policy; using detail::receive_policy;
auto bhvr = m_bhvr_stack.back(); auto bhvr = m_bhvr_stack.back();
switch (m_recv_policy.handle_message(this, switch (m_invoke.handle_message(this,
&m_dummy_node, &m_dummy_node,
bhvr, bhvr,
m_bhvr_stack.back_id(), m_bhvr_stack.back_id())) {
receive_policy::sequential{})) { case policy::hm_msg_handled: {
case receive_policy::hm_msg_handled: {
if ( not m_bhvr_stack.empty() if ( not m_bhvr_stack.empty()
&& bhvr.as_behavior_impl() == m_bhvr_stack.back().as_behavior_impl()) { && bhvr.as_behavior_impl() == m_bhvr_stack.back().as_behavior_impl()) {
m_recv_policy.invoke_from_cache(this, bhvr, m_bhvr_stack.back_id()); m_invoke.invoke_from_cache(this, bhvr, m_bhvr_stack.back_id());
} }
break; break;
} }
case receive_policy::hm_drop_msg: case policy::hm_drop_msg:
break; break;
case receive_policy::hm_skip_msg: case policy::hm_skip_msg:
case receive_policy::hm_cache_msg: { case policy::hm_cache_msg: {
auto e = mailbox_element::create(hdr, move(m_dummy_node.msg)); auto e = mailbox_element::create(hdr, move(m_dummy_node.msg));
m_recv_policy.add_to_cache(e); m_invoke.add_to_cache(e);
break; break;
} }
default: CPPA_CRITICAL("illegal result of handle_message"); default: CPPA_CRITICAL("illegal result of handle_message");
...@@ -398,7 +387,7 @@ void broker::write(const connection_handle& hdl, util::buffer&& buf) { ...@@ -398,7 +387,7 @@ 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) {
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");
auto mm = get_middleman(); auto mm = get_middleman();
...@@ -421,6 +410,7 @@ local_actor_ptr init_and_launch(broker_ptr ptr) { ...@@ -421,6 +410,7 @@ local_actor_ptr init_and_launch(broker_ptr ptr) {
return ptr; return ptr;
} }
/*
broker_ptr broker::from_impl(std::function<void (broker*)> fun, broker_ptr broker::from_impl(std::function<void (broker*)> fun,
input_stream_ptr in, input_stream_ptr in,
output_stream_ptr out) { output_stream_ptr out) {
...@@ -430,6 +420,7 @@ broker_ptr broker::from_impl(std::function<void (broker*)> fun, ...@@ -430,6 +420,7 @@ broker_ptr broker::from_impl(std::function<void (broker*)> fun,
broker_ptr broker::from(std::function<void (broker*)> fun, acceptor_uptr in) { broker_ptr broker::from(std::function<void (broker*)> fun, acceptor_uptr in) {
return make_counted<default_broker>(move(fun), move(in)); return make_counted<default_broker>(move(fun), move(in));
} }
*/
void broker::erase_io(int id) { void broker::erase_io(int id) {
...@@ -454,16 +445,19 @@ accept_handle broker::add_doorman(acceptor_uptr ptr) { ...@@ -454,16 +445,19 @@ accept_handle broker::add_doorman(acceptor_uptr ptr) {
return id; return id;
} }
actor_addr broker::fork_impl(std::function<void (broker*)> fun, actor 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");
/*FIXME
scribe* sptr = i->second.get(); // non-owning pointer scribe* sptr = i->second.get(); // non-owning pointer
auto result = make_counted<default_broker>(move(fun), move(i->second)); auto result = make_counted<default_broker>(move(fun), move(i->second));
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};
*/
return nullptr;
} }
void broker::receive_policy(const connection_handle& hdl, void broker::receive_policy(const connection_handle& hdl,
...@@ -473,4 +467,5 @@ void broker::receive_policy(const connection_handle& hdl, ...@@ -473,4 +467,5 @@ void broker::receive_policy(const connection_handle& hdl,
if (i != m_io.end()) i->second->receive_policy(policy, buffer_size); if (i != m_io.end()) i->second->receive_policy(policy, buffer_size);
} }
} } // namespace cppa::network } // namespace io
} // namespace cppa
...@@ -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/>. *
\******************************************************************************/ \******************************************************************************/
#include "cppa/actor_addr.hpp" #include "cppa/actor_addr.hpp"
......
...@@ -36,12 +36,13 @@ ...@@ -36,12 +36,13 @@
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/self.hpp" #include "cppa/self.hpp"
namespace cppa { namespace policy { namespace cppa {
namespace policy {
void context_switching_resume::trampoline(void* this_ptr) { void context_switching_resume::trampoline(void* this_ptr) {
auto _this = reinterpret_cast<context_switching_resume*>(this_ptr); auto _this = reinterpret_cast<blocking_untyped_actor*>(this_ptr);
bool cleanup_called = false; bool cleanup_called = false;
try { _this->run(); } try { _this->act(); }
catch (actor_exited&) { catch (actor_exited&) {
// cleanup already called by scheduled_actor::quit // cleanup already called by scheduled_actor::quit
cleanup_called = true; cleanup_called = true;
...@@ -56,10 +57,21 @@ void context_switching_resume::trampoline(void* this_ptr) { ...@@ -56,10 +57,21 @@ void context_switching_resume::trampoline(void* this_ptr) {
detail::yield(detail::yield_state::done); detail::yield(detail::yield_state::done);
} }
} } // namespace cppa::policy } // namespace policy
} // namespace cppa
#else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING #else // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
namespace cppa {
namespace policy {
void context_switching_resume::trampoline(void*) {
throw std::logic_error("context_switching_resume::trampoline called");
}
} // namespace policy
} // namespace cppa
namespace cppa { int keep_compiler_happy_function() { return 42; } } namespace cppa { int keep_compiler_happy_function() { return 42; } }
#endif // ifdef CPPA_DISABLE_CONTEXT_SWITCHING #endif // ifdef CPPA_DISABLE_CONTEXT_SWITCHING
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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 <iostream>
#include "cppa/to_string.hpp"
#include "cppa/cppa.hpp"
#include "cppa/logging.hpp"
#include "cppa/event_based_actor.hpp"
using namespace std;
namespace cppa {
class default_scheduled_actor : public event_based_actor {
typedef event_based_actor super;
public:
typedef std::function<behavior(event_based_actor*)> fun_type;
default_scheduled_actor(fun_type&& fun)
: super(actor_state::ready), m_fun(std::move(fun)) { }
behavior make_behavior() override {
return m_fun(this);
}
scheduled_actor_type impl_type() {
return default_event_based_impl;
}
private:
fun_type m_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));
}
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) { }
resume_result event_based_resume::resume(untyped_actor* self, util::fiber*) {
CPPA_LOG_TRACE("id = " << self->id() << ", state = " << static_cast<int>(state()));
CPPA_REQUIRE( self->state() == actor_state::ready
|| self->state() == actor_state::pending);
auto done_cb = [&]() -> bool {
CPPA_LOG_TRACE("");
if (self->exit_reason() == self->exit_reason::not_exited) {
if (self->planned_exit_reason() == self->exit_reason::not_exited) {
self->planned_exit_reason(exit_reason::normal);
}
self->on_exit();
if (!m_bhvr_stack.empty()) {
planned_exit_reason(exit_reason::not_exited);
return false; // on_exit did set a new behavior
}
cleanup(planned_exit_reason());
}
set_state(actor_state::done);
m_bhvr_stack.clear();
m_bhvr_stack.cleanup();
on_exit();
CPPA_REQUIRE(next_job == nullptr);
return true;
};
CPPA_REQUIRE(next_job == nullptr);
try {
//auto e = m_mailbox.try_pop();
for (auto e = m_mailbox.try_pop(); ; e = m_mailbox.try_pop()) {
//e = m_mailbox.try_pop();
if (e == nullptr) {
CPPA_REQUIRE(next_job == nullptr);
CPPA_LOGMF(CPPA_DEBUG, self, "no more element in mailbox; going to block");
set_state(actor_state::about_to_block);
std::atomic_thread_fence(std::memory_order_seq_cst);
if (this->m_mailbox.can_fetch_more() == false) {
switch (compare_exchange_state(actor_state::about_to_block,
actor_state::blocked)) {
case actor_state::ready:
// interrupted by arriving message
// restore members
CPPA_REQUIRE(m_chained_actor == nullptr);
CPPA_LOGMF(CPPA_DEBUG, self, "switched back to ready: "
"interrupted by arriving message");
break;
case actor_state::blocked:
CPPA_LOGMF(CPPA_DEBUG, self, "set state successfully to blocked");
// done setting actor to blocked
return resume_result::actor_blocked;
default:
CPPA_LOGMF(CPPA_ERROR, self, "invalid state");
CPPA_CRITICAL("invalid state");
};
}
else {
CPPA_LOGMF(CPPA_DEBUG, self, "switched back to ready: "
"mailbox can fetch more");
set_state(actor_state::ready);
CPPA_REQUIRE(m_chained_actor == nullptr);
}
}
else {
CPPA_LOGMF(CPPA_DEBUG, self, "try to invoke message: " << to_string(e->msg));
if (m_bhvr_stack.invoke(m_recv_policy, this, e)) {
CPPA_LOG_DEBUG_IF(m_chained_actor,
"set actor with ID "
<< m_chained_actor->id()
<< " as successor");
if (m_bhvr_stack.empty() && done_cb()) {
CPPA_LOGMF(CPPA_DEBUG, self, "behavior stack empty");
return resume_result::actor_done;
}
m_bhvr_stack.cleanup();
}
}
}
}
catch (actor_exited& what) {
CPPA_LOG_INFO("actor died because of exception: actor_exited, "
"reason = " << what.reason());
if (exit_reason() == exit_reason::not_exited) {
quit(what.reason());
}
}
catch (std::exception& e) {
CPPA_LOG_WARNING("actor died because of exception: "
<< detail::demangle(typeid(e))
<< ", what() = " << e.what());
if (exit_reason() == exit_reason::not_exited) {
quit(exit_reason::unhandled_exception);
}
}
catch (...) {
CPPA_LOG_WARNING("actor died because of an unknown exception");
if (exit_reason() == exit_reason::not_exited) {
quit(exit_reason::unhandled_exception);
}
}
done_cb();
return resume_result::actor_done;
}
scheduled_actor_type event_based_actor::impl_type() {
return event_based_impl;
}
} // namespace cppa
...@@ -28,29 +28,21 @@ ...@@ -28,29 +28,21 @@
\******************************************************************************/ \******************************************************************************/
#include <chrono> #include "cppa/detail/functor_based_actor.hpp"
#include <memory>
#include <iostream>
#include <algorithm>
#include "cppa/to_string.hpp"
#include "cppa/exception.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/detail/matches.hpp"
namespace cppa { namespace cppa {
namespace detail {
thread_mapped_actor::thread_mapped_actor() : m_initialized(true) { } void functor_based_actor::create(untyped_actor*, void_fun fun) {
m_make_behavior = [=](untyped_actor* self) -> behavior {
thread_mapped_actor::thread_mapped_actor(std::function<void()> fun) fun(self);
: m_initialized(false) { return behavior{};
set_behavior(std::move(fun)); };
} }
bool thread_mapped_actor::initialized() const { behavior functor_based_actor::make_behavior() {
return m_initialized; return m_make_behavior(this);
} }
} // namespace cppa::detail } // namespace detail
} // namespace cppa
...@@ -28,25 +28,18 @@ ...@@ -28,25 +28,18 @@
\******************************************************************************/ \******************************************************************************/
#include "cppa/detail/scheduled_actor_dummy.hpp" #include "cppa/detail/functor_based_blocking_actor.hpp"
namespace cppa { namespace detail { namespace cppa {
namespace detail {
scheduled_actor_dummy::scheduled_actor_dummy() void functor_based_blocking_actor::create(blocking_untyped_actor*, act_fun fun) {
: scheduled_actor(actor_state::blocked, false) { } m_act = fun;
void scheduled_actor_dummy::enqueue(const message_header&, any_tuple) { }
void scheduled_actor_dummy::quit(std::uint32_t) { }
void scheduled_actor_dummy::dequeue(behavior&) { }
void scheduled_actor_dummy::dequeue_response(behavior&, message_id) { }
bool scheduled_actor_dummy::has_behavior() { return false; }
resume_result scheduled_actor_dummy::resume(util::fiber*) {
return resume_result::actor_blocked;
} }
scheduled_actor_type scheduled_actor_dummy::impl_type() { void functor_based_blocking_actor::act() {
return event_based_impl; m_act(this);
} }
} } // namespace cppa::detail } // namespace detail
} // namespace cppa
...@@ -87,7 +87,7 @@ const std::string& group::module_name() const { ...@@ -87,7 +87,7 @@ const std::string& group::module_name() const {
return get_module()->name(); return get_module()->name();
} }
struct group_nameserver : event_based_actor { struct group_nameserver : untyped_actor {
behavior make_behavior() override { behavior make_behavior() override {
return ( return (
on(atom("GET_GROUP"), arg_match) >> [](const std::string& name) { on(atom("GET_GROUP"), arg_match) >> [](const std::string& name) {
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include "cppa/deserializer.hpp" #include "cppa/deserializer.hpp"
#include "cppa/untyped_actor.hpp" #include "cppa/untyped_actor.hpp"
#include "cppa/message_header.hpp" #include "cppa/message_header.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/io/middleman.hpp" #include "cppa/io/middleman.hpp"
...@@ -133,13 +132,13 @@ class local_group : public group { ...@@ -133,13 +132,13 @@ class local_group : public group {
typedef intrusive_ptr<local_group> local_group_ptr; typedef intrusive_ptr<local_group> local_group_ptr;
class local_broker : public event_based_actor { class local_broker : public untyped_actor {
public: public:
local_broker(local_group_ptr g) : m_group(move(g)) { } local_broker(local_group_ptr g) : m_group(move(g)) { }
behavior make_behavior() { behavior make_behavior() override {
return ( return (
on(atom("JOIN"), arg_match) >> [=](const actor_addr& 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",
...@@ -256,7 +255,7 @@ class local_group_proxy : public local_group { ...@@ -256,7 +255,7 @@ class local_group_proxy : public local_group {
typedef intrusive_ptr<local_group_proxy> local_group_proxy_ptr; typedef intrusive_ptr<local_group_proxy> local_group_proxy_ptr;
class proxy_broker : public event_based_actor { class proxy_broker : public untyped_actor {
public: public:
...@@ -496,7 +495,7 @@ class remote_group_module : public group::module { ...@@ -496,7 +495,7 @@ class remote_group_module : public group::module {
} }
} }
} }
self->timed_sync_send(chrono::seconds(10), nameserver, atom("GET_GROUP"), name).then ( self->timed_sync_send(nameserver, chrono::seconds(10), 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) {
......
...@@ -77,38 +77,12 @@ constexpr const char* s_default_debug_name = "actor"; ...@@ -77,38 +77,12 @@ constexpr const char* s_default_debug_name = "actor";
} // namespace <anonymous> } // namespace <anonymous>
local_actor::local_actor(bool sflag) local_actor::local_actor()
: m_trap_exit(false) : m_trap_exit(false)
, m_is_scheduled(sflag), m_dummy_node(), m_current_node(&m_dummy_node) , 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
new (&m_debug_name) std::string (std::to_string(m_id) + "@local");
# endif // CPPA_DEBUG_MODE
}
local_actor::~local_actor() {
using std::string;
# ifdef CPPA_DEBUG_MODE
m_debug_name.~string();
# endif // CPPA_DEBUG_MODE
}
const char* local_actor::debug_name() const {
# ifdef CPPA_DEBUG_MODE
return m_debug_name.c_str();
# else // CPPA_DEBUG_MODE
return s_default_debug_name;
# endif // CPPA_DEBUG_MODE
}
void local_actor::debug_name(std::string str) { local_actor::~local_actor() { }
# ifdef CPPA_DEBUG_MODE
m_debug_name = std::move(str);
# else // CPPA_DEBUG_MODE
CPPA_LOG_WARNING("unable to set debug name to " << str
<< " (compiled without debug mode enabled)");
# endif // CPPA_DEBUG_MODE
}
void local_actor::monitor(const actor_addr& whom) { void local_actor::monitor(const actor_addr& whom) {
if (!whom) return; if (!whom) return;
...@@ -125,8 +99,6 @@ void local_actor::demonitor(const actor_addr& whom) { ...@@ -125,8 +99,6 @@ void local_actor::demonitor(const actor_addr& whom) {
void local_actor::on_exit() { } void local_actor::on_exit() { }
void local_actor::init() { }
void local_actor::join(const group_ptr& what) { void local_actor::join(const group_ptr& what) {
if (what && m_subscriptions.count(what) == 0) { if (what && m_subscriptions.count(what) == 0) {
m_subscriptions.insert(std::make_pair(what, what->subscribe(this))); m_subscriptions.insert(std::make_pair(what, what->subscribe(this)));
...@@ -180,6 +152,10 @@ void local_actor::send_tuple(const channel& dest, any_tuple what) { ...@@ -180,6 +152,10 @@ void local_actor::send_tuple(const channel& dest, any_tuple what) {
//TODO: //TODO:
} }
void local_actor::send_exit(const actor_addr& whom, std::uint32_t reason) {
}
void local_actor::remove_handler(message_id) { void local_actor::remove_handler(message_id) {
} }
...@@ -194,6 +170,14 @@ message_future local_actor::timed_sync_send_tuple(const util::duration& rtime, ...@@ -194,6 +170,14 @@ message_future local_actor::timed_sync_send_tuple(const util::duration& rtime,
} }
void local_actor::send_tuple(message_priority prio, const channel& dest, any_tuple what) {
}
message_future local_actor::sync_send_tuple(const actor& dest, any_tuple what) {
}
response_handle local_actor::make_response_handle() { response_handle local_actor::make_response_handle() {
return {}; return {};
} }
......
...@@ -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,
actor_addr from, actor_addr,
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, "::", ".");
......
...@@ -46,7 +46,6 @@ ...@@ -46,7 +46,6 @@
#include "cppa/actor_proxy.hpp" #include "cppa/actor_proxy.hpp"
#include "cppa/binary_serializer.hpp" #include "cppa/binary_serializer.hpp"
#include "cppa/uniform_type_info.hpp" #include "cppa/uniform_type_info.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/binary_deserializer.hpp" #include "cppa/binary_deserializer.hpp"
#include "cppa/util/buffer.hpp" #include "cppa/util/buffer.hpp"
...@@ -347,9 +346,6 @@ class middleman_overseer : public continuable { ...@@ -347,9 +346,6 @@ class middleman_overseer : public continuable {
middleman::~middleman() { } middleman::~middleman() { }
void middleman_loop(middleman_impl* impl) { void middleman_loop(middleman_impl* impl) {
# ifdef CPPA_LOG_LEVEL
auto mself = make_counted<thread_mapped_actor>();
# endif
middleman_event_handler* handler = impl->m_handler.get(); middleman_event_handler* handler = impl->m_handler.get();
CPPA_LOGF_TRACE("run middleman loop"); CPPA_LOGF_TRACE("run middleman loop");
CPPA_LOGF_INFO("middleman runs at " CPPA_LOGF_INFO("middleman runs at "
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/resumable.hpp"
namespace cppa {
resumable::~resumable() { }
} // namespace cppa
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/on.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/scheduled_actor.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/detail/sync_request_bouncer.hpp"
namespace cppa {
scheduled_actor::scheduled_actor(actor_state init_state, bool chained_send)
: super(chained_send), next(nullptr), m_state(init_state)
, m_scheduler(nullptr), m_hidden(false) { }
void scheduled_actor::attach_to_scheduler(scheduler* sched, bool hidden) {
CPPA_REQUIRE(sched != nullptr);
m_scheduler = sched;
m_hidden = hidden;
// initialize this actor
try { init(); }
catch (...) { }
}
bool scheduled_actor::initialized() const {
return m_scheduler != nullptr;
}
scheduled_actor::~scheduled_actor() {
if (!m_mailbox.closed()) {
detail::sync_request_bouncer f{exit_reason()};
m_mailbox.close(f);
}
}
void scheduled_actor::run_detached() {
throw std::logic_error("scheduled_actor::run_detached called");
}
void scheduled_actor::cleanup(std::uint32_t reason) {
detail::sync_request_bouncer f{reason};
m_mailbox.close(f);
super::cleanup(reason);
}
bool scheduled_actor::enqueue_impl(actor_state next_state,
const message_header& hdr,
any_tuple&& msg) {
CPPA_REQUIRE( next_state == actor_state::ready
|| next_state == actor_state::pending);
auto e = new_mailbox_element(hdr, std::move(msg));
switch (m_mailbox.enqueue(e)) {
case intrusive::first_enqueued: {
auto state = m_state.load();
for (;;) {
switch (state) {
case actor_state::blocked: {
if (m_state.compare_exchange_weak(state, next_state)) {
CPPA_REQUIRE(m_scheduler != nullptr);
if (next_state == actor_state::ready) {
CPPA_LOGMF(CPPA_DEBUG, self, "enqueued actor with id " << id()
<< " to job queue");
m_scheduler->enqueue(this);
return false;
}
return true;
}
break;
}
case actor_state::about_to_block: {
if (m_state.compare_exchange_weak(state, actor_state::ready)) {
return false;
}
break;
}
default: return false;
}
}
break;
}
case intrusive::queue_closed: {
if (hdr.id.is_request()) {
detail::sync_request_bouncer f{exit_reason()};
f(hdr.sender, hdr.id);
}
break;
}
default: break;
}
return false;
}
actor_state scheduled_actor::compare_exchange_state(actor_state expected,
actor_state desired) {
auto e = expected;
do { if (m_state.compare_exchange_weak(e, desired)) return desired; }
while (e == expected);
return e;
}
void scheduled_actor::enqueue(const message_header& hdr, any_tuple msg) {
enqueue_impl(actor_state::ready, hdr, std::move(msg));
}
} // namespace cppa
...@@ -39,8 +39,7 @@ ...@@ -39,8 +39,7 @@
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
#include "cppa/scheduler.hpp" #include "cppa/scheduler.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/thread_mapped_actor.hpp" #include "cppa/scoped_actor.hpp"
#include "cppa/context_switching_actor.hpp"
#include "cppa/detail/actor_registry.hpp" #include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/singleton_manager.hpp" #include "cppa/detail/singleton_manager.hpp"
...@@ -90,38 +89,31 @@ class scheduler_helper { ...@@ -90,38 +89,31 @@ class scheduler_helper {
public: public:
typedef intrusive_ptr<thread_mapped_actor> ptr_type;
void start() { void start() {
auto mt = make_counted<thread_mapped_actor>();
auto mp = make_counted<thread_mapped_actor>();
// launch threads // launch threads
m_timer_thread = std::thread{&scheduler_helper::timer_loop, mt.get()}; m_timer_thread = std::thread{&scheduler_helper::timer_loop, m_timer.get()};
m_printer_thread = std::thread{&scheduler_helper::printer_loop, mp.get()}; m_printer_thread = std::thread{&scheduler_helper::printer_loop, m_printer.get()};
// set member variables
m_timer = std::move(mt);
m_printer = std::move(mp);
} }
void stop() { void stop() {
auto msg = make_any_tuple(atom("DIE")); auto msg = make_any_tuple(atom("DIE"));
m_timer.enqueue({invalid_actor_addr, nullptr}, msg); m_timer->enqueue({invalid_actor_addr, nullptr}, msg);
m_printer.enqueue({invalid_actor_addr, 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 m_timer; scoped_actor m_timer;
std::thread m_timer_thread; std::thread m_timer_thread;
actor m_printer; scoped_actor m_printer;
std::thread m_printer_thread; std::thread m_printer_thread;
private: private:
static void timer_loop(thread_mapped_actor* self); static void timer_loop(blocking_untyped_actor* self);
static void printer_loop(thread_mapped_actor* self); static void printer_loop(blocking_untyped_actor* self);
}; };
...@@ -136,7 +128,7 @@ inline void insert_dmsg(Map& storage, ...@@ -136,7 +128,7 @@ 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(thread_mapped_actor* self) { void scheduler_helper::timer_loop(blocking_untyped_actor* self) {
// setup & local variables // setup & local variables
bool done = false; bool done = false;
std::unique_ptr<mailbox_element, detail::disposer> msg_ptr; std::unique_ptr<mailbox_element, detail::disposer> msg_ptr;
...@@ -163,7 +155,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* self) { ...@@ -163,7 +155,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* self) {
// loop // loop
while (!done) { while (!done) {
while (!msg_ptr) { while (!msg_ptr) {
if (messages.empty()) msg_ptr.reset(self->pop()); if (messages.empty()) msg_ptr.reset(self->dequeue());
else { else {
tout = hrc::now(); tout = hrc::now();
// handle timeouts (send messages) // handle timeouts (send messages)
...@@ -175,7 +167,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* self) { ...@@ -175,7 +167,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* 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(self->try_pop(it->first)); msg_ptr.reset(self->try_dequeue(it->first));
} }
} }
} }
...@@ -184,7 +176,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* self) { ...@@ -184,7 +176,7 @@ void scheduler_helper::timer_loop(thread_mapped_actor* self) {
} }
} }
void scheduler_helper::printer_loop(thread_mapped_actor* self) { void scheduler_helper::printer_loop(blocking_untyped_actor* self) {
std::map<actor_addr, std::string> out; std::map<actor_addr, std::string> out;
auto flush_output = [&out](const actor_addr& s) { auto flush_output = [&out](const actor_addr& s) {
auto i = out.find(s); auto i = out.find(s);
...@@ -257,8 +249,8 @@ scheduler::~scheduler() { ...@@ -257,8 +249,8 @@ scheduler::~scheduler() {
delete m_helper; delete m_helper;
} }
actor& scheduler::delayed_send_helper() { actor scheduler::delayed_send_helper() {
return m_helper->m_timer; return m_helper->m_timer.get();
} }
void scheduler::register_converted_context(abstract_actor* what) { void scheduler::register_converted_context(abstract_actor* what) {
...@@ -287,8 +279,8 @@ scheduler* scheduler::create_singleton() { ...@@ -287,8 +279,8 @@ scheduler* scheduler::create_singleton() {
return new detail::thread_pool_scheduler; return new detail::thread_pool_scheduler;
} }
const actor& scheduler::printer() const { actor scheduler::printer() const {
return m_helper->m_printer; return m_helper->m_printer.get();
} }
} // namespace cppa } // namespace cppa
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/policy.hpp"
#include "cppa/scoped_actor.hpp"
#include "cppa/detail/proper_actor.hpp"
namespace cppa {
namespace {
struct impl : blocking_untyped_actor {
void act() override { }
};
blocking_untyped_actor* alloc() {
using namespace policy;
return new detail::proper_actor<impl,
no_scheduling,
not_prioritizing,
no_resume,
nestable_invoke>;
}
} // namespace <anonymous>
scoped_actor::scoped_actor() : m_self(alloc()) { }
scoped_actor::~scoped_actor() { }
} // namespace cppa
...@@ -36,7 +36,6 @@ ...@@ -36,7 +36,6 @@
#include "cppa/exception.hpp" #include "cppa/exception.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/local_actor.hpp" #include "cppa/local_actor.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/io/middleman.hpp" #include "cppa/io/middleman.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/>. *
\******************************************************************************/ \******************************************************************************/
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
......
...@@ -36,12 +36,8 @@ ...@@ -36,12 +36,8 @@
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/logging.hpp" #include "cppa/logging.hpp"
#include "cppa/prioritizing.hpp"
#include "cppa/untyped_actor.hpp" #include "cppa/util/fiber.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/thread_mapped_actor.hpp"
#include "cppa/blocking_untyped_actor.hpp"
#include "cppa/context_switching_actor.hpp"
#include "cppa/detail/actor_registry.hpp" #include "cppa/detail/actor_registry.hpp"
#include "cppa/detail/thread_pool_scheduler.hpp" #include "cppa/detail/thread_pool_scheduler.hpp"
...@@ -51,9 +47,13 @@ using std::endl; ...@@ -51,9 +47,13 @@ using std::endl;
namespace cppa { namespace detail { namespace cppa { namespace detail {
resumable::resume_result thread_pool_scheduler::dummy::resume(util::fiber*) {
throw std::logic_error("thread_pool_scheduler::dummy::resume");
}
struct thread_pool_scheduler::worker { struct thread_pool_scheduler::worker {
typedef scheduled_actor* job_ptr; typedef resumable* job_ptr;
job_queue* m_job_queue; job_queue* m_job_queue;
job_ptr m_dummy; job_ptr m_dummy;
...@@ -109,11 +109,11 @@ struct thread_pool_scheduler::worker { ...@@ -109,11 +109,11 @@ struct thread_pool_scheduler::worker {
return; // and say goodbye return; // and say goodbye
} }
CPPA_LOG_DEBUG("resume actor with ID " << job->id()); CPPA_LOG_DEBUG("resume actor with ID " << job->id());
if (job->resume(&fself) == resume_result::actor_done) { if (job->resume(&fself) == resumable::done) {
CPPA_LOGMF(CPPA_DEBUG, self, "actor is done"); CPPA_LOGMF(CPPA_DEBUG, self, "actor is done");
bool hidden = job->is_hidden(); /*FIXME bool hidden = job->is_hidden();
job->deref(); job->deref();
if (!hidden) get_actor_registry()->dec_running(); if (!hidden)*/ get_actor_registry()->dec_running();
} }
job = nullptr; job = nullptr;
} }
...@@ -134,7 +134,7 @@ thread_pool_scheduler::thread_pool_scheduler(size_t num_worker_threads) { ...@@ -134,7 +134,7 @@ thread_pool_scheduler::thread_pool_scheduler(size_t num_worker_threads) {
} }
void thread_pool_scheduler::supervisor_loop(job_queue* jqueue, void thread_pool_scheduler::supervisor_loop(job_queue* jqueue,
scheduled_actor* dummy, resumable* dummy,
size_t num_threads) { size_t num_threads) {
std::vector<std::unique_ptr<thread_pool_scheduler::worker> > workers; std::vector<std::unique_ptr<thread_pool_scheduler::worker> > workers;
for (size_t i = 0; i < num_threads; ++i) { for (size_t i = 0; i < num_threads; ++i) {
...@@ -164,116 +164,18 @@ void thread_pool_scheduler::destroy() { ...@@ -164,116 +164,18 @@ void thread_pool_scheduler::destroy() {
auto ptr = m_queue.try_pop(); auto ptr = m_queue.try_pop();
while (ptr != nullptr) { while (ptr != nullptr) {
if (ptr != &m_dummy) { if (ptr != &m_dummy) {
bool hidden = ptr->is_hidden(); /*FIXME bool hidden = ptr->is_hidden();
ptr->deref(); ptr->deref();
std::atomic_thread_fence(std::memory_order_seq_cst); std::atomic_thread_fence(std::memory_order_seq_cst);
if (!hidden) get_actor_registry()->dec_running(); if (!hidden)*/ get_actor_registry()->dec_running();
} }
ptr = m_queue.try_pop(); ptr = m_queue.try_pop();
} }
super::destroy(); super::destroy();
} }
void thread_pool_scheduler::enqueue(scheduled_actor* what) { void thread_pool_scheduler::enqueue(resumable* what) {
m_queue.push_back(what); m_queue.push_back(what);
} }
void exec_as_thread(bool is_hidden, intrusive_ptr<untyped_actor> ptr) {
/*TODO:
if (!is_hidden) get_actor_registry()->inc_running();
std::thread([=] {
try { ptr->exec_bhvr_stack(); }
catch (...) { }
if (!is_hidden) {
std::atomic_thread_fence(std::memory_order_seq_cst);
get_actor_registry()->dec_running();
}
}).detach();
*/
}
local_actor_ptr thread_pool_scheduler::exec(spawn_options os, scheduled_actor_ptr p) {
/*TODO:
CPPA_REQUIRE(p != nullptr);
bool is_hidden = has_hide_flag(os);
if (has_detach_flag(os)) {
exec_as_thread(is_hidden, p [p] {
p->run_detached();
});
return p;
}
p->attach_to_scheduler(this, is_hidden);
if (p->has_behavior() || p->impl_type() == default_event_based_impl) {
if (!is_hidden) get_actor_registry()->inc_running();
p->ref(); // implicit reference that's released if actor dies
if (p->impl_type() != event_based_impl) m_queue.push_back(p.get());
}
else p->on_exit();
return p;
*/
}
local_actor_ptr thread_pool_scheduler::exec(spawn_options os,
init_callback cb,
actor_fun f) {
local_actor_ptr result;
auto set_result = [&](local_actor_ptr value) {
CPPA_REQUIRE(result == nullptr && value != nullptr);
result = std::move(value);
if (cb) cb(result.get());
};
if (has_priority_aware_flag(os)) {
using impl = extend<local_actor>::with<stackless, threaded, prioritizing>;
set_result(make_counted<impl>());
/*TODO:
exec_as_thread(has_hide_flag(os), [result, f] {
try {
f();
}
catch (actor_exited& e) { }
catch (std::exception& e) {
CPPA_LOGF_ERROR("actor with ID " << result->id()
<< " terminated due to an unhandled exception; "
<< detail::demangle(typeid(e)) << ": "
<< e.what());
}
catch (...) {
CPPA_LOGF_ERROR("actor with ID " << result->id()
<< " terminated due to an unknown exception");
}
result->on_exit();
});
*/
}
else if (has_blocking_api_flag(os)) {
# ifndef CPPA_DISABLE_CONTEXT_SWITCHING
if (!has_detach_flag(os)) {
auto p = make_counted<context_switching_actor>(std::move(f));
set_result(p);
exec(os, std::move(p));
}
else
# endif
/* else tree */ {
//auto p = make_counted<thread_mapped_actor>(std::move(f));
//set_result(p);
/*TODO:
exec_as_thread(has_hide_flag(os), [p] {
p->run();
p->on_exit();
});
*/
}
}
else {
/*TODO:
auto p = event_based_actor::from(std::move(f));
set_result(p);
exec(os, p);
*/
}
CPPA_REQUIRE(result != nullptr);
return result;
}
} } // namespace cppa::detail } } // namespace cppa::detail
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \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/untyped_actor.hpp"
namespace cppa {
void untyped_actor::forward_to(const actor&) {
}
} // namespace cppa
...@@ -15,21 +15,21 @@ namespace { ...@@ -15,21 +15,21 @@ namespace {
size_t s_pongs = 0; size_t s_pongs = 0;
behavior ping_behavior(size_t num_pings) { behavior ping_behavior(local_actor* self, size_t num_pings) {
return ( return (
on(atom("pong"), arg_match) >> [num_pings](int value) -> any_tuple { on(atom("pong"), arg_match) >> [=](int value) -> any_tuple {
CPPA_LOGF_ERROR_IF(!self->last_sender(), "last_sender() == nullptr"); CPPA_LOGF_ERROR_IF(!self->last_sender(), "last_sender() == nullptr");
CPPA_LOGF_INFO("received {'pong', " << value << "}"); CPPA_LOGF_INFO("received {'pong', " << value << "}");
//cout << to_string(self->last_dequeued()) << endl; //cout << to_string(self->last_dequeued()) << endl;
if (++s_pongs >= num_pings) { if (++s_pongs >= num_pings) {
CPPA_LOGF_INFO("reached maximum, send {'EXIT', user_defined} " CPPA_LOGF_INFO("reached maximum, send {'EXIT', user_defined} "
<< "to last sender and quit with normal reason"); << "to last sender and quit with normal reason");
send_exit(self->last_sender(), exit_reason::user_shutdown); self->send_exit(self->last_sender(), exit_reason::user_shutdown);
self->quit(); self->quit();
} }
return {atom("ping"), value}; return make_any_tuple(atom("ping"), value);
}, },
others() >> [] { others() >> [=] {
CPPA_LOGF_ERROR("unexpected message; " CPPA_LOGF_ERROR("unexpected message; "
<< to_string(self->last_dequeued())); << to_string(self->last_dequeued()));
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
...@@ -37,13 +37,13 @@ behavior ping_behavior(size_t num_pings) { ...@@ -37,13 +37,13 @@ behavior ping_behavior(size_t num_pings) {
); );
} }
behavior pong_behavior() { behavior pong_behavior(local_actor* self) {
return ( return (
on(atom("ping"), arg_match) >> [](int value) -> any_tuple { on(atom("ping"), arg_match) >> [](int value) -> any_tuple {
CPPA_LOGF_INFO("received {'ping', " << value << "}"); CPPA_LOGF_INFO("received {'ping', " << value << "}");
return {atom("pong"), value + 1}; return make_any_tuple(atom("pong"), value + 1);
}, },
others() >> [] { others() >> [=] {
CPPA_LOGF_ERROR("unexpected message; " CPPA_LOGF_ERROR("unexpected message; "
<< to_string(self->last_dequeued())); << to_string(self->last_dequeued()));
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
...@@ -57,27 +57,27 @@ size_t pongs() { ...@@ -57,27 +57,27 @@ size_t pongs() {
return s_pongs; return s_pongs;
} }
void ping(size_t num_pings) { void ping(blocking_untyped_actor* self, size_t num_pings) {
CPPA_LOGF_TRACE("num_pings = " << num_pings); CPPA_LOGF_TRACE("num_pings = " << num_pings);
s_pongs = 0; s_pongs = 0;
receive_loop(ping_behavior(num_pings)); self->receive_loop(ping_behavior(self, num_pings));
} }
void event_based_ping(size_t num_pings) { void event_based_ping(untyped_actor* self, size_t num_pings) {
CPPA_LOGF_TRACE("num_pings = " << num_pings); CPPA_LOGF_TRACE("num_pings = " << num_pings);
s_pongs = 0; s_pongs = 0;
become(ping_behavior(num_pings)); self->become(ping_behavior(self, num_pings));
} }
void pong(actor_ptr ping_actor) { void pong(blocking_untyped_actor* self, actor ping_actor) {
CPPA_LOGF_TRACE("ping_actor = " << to_string(ping_actor)); CPPA_LOGF_TRACE("ping_actor = " << to_string(ping_actor));
send(ping_actor, atom("pong"), 0); // kickoff self->send(ping_actor, atom("pong"), 0); // kickoff
receive_loop(pong_behavior()); self->receive_loop(pong_behavior(self));
} }
void event_based_pong(actor_ptr ping_actor) { void event_based_pong(untyped_actor* self, actor ping_actor) {
CPPA_LOGF_TRACE("ping_actor = " << to_string(ping_actor)); CPPA_LOGF_TRACE("ping_actor = " << to_string(ping_actor));
CPPA_REQUIRE(ping_actor != nullptr); CPPA_REQUIRE(ping_actor != nullptr);
send(ping_actor, atom("pong"), 0); // kickoff self->send(ping_actor, atom("pong"), 0); // kickoff
become(pong_behavior()); self->become(pong_behavior(self));
} }
...@@ -10,9 +10,9 @@ void ping(cppa::blocking_untyped_actor*, size_t num_pings); ...@@ -10,9 +10,9 @@ void ping(cppa::blocking_untyped_actor*, size_t num_pings);
void event_based_ping(cppa::untyped_actor*, size_t num_pings); void event_based_ping(cppa::untyped_actor*, size_t num_pings);
void pong(cppa::blocking_untyped_actor*, cppa::actor_ptr ping_actor); void pong(cppa::blocking_untyped_actor*, cppa::actor ping_actor);
void event_based_pong(cppa::untyped_actor*, cppa::actor_ptr ping_actor); void event_based_pong(cppa::untyped_actor*, cppa::actor ping_actor);
// returns the number of messages ping received // returns the number of messages ping received
size_t pongs(); size_t pongs();
......
...@@ -60,6 +60,10 @@ inline std::string cppa_stream_arg(const cppa::actor& ptr) { ...@@ -60,6 +60,10 @@ inline std::string cppa_stream_arg(const cppa::actor& ptr) {
return cppa::to_string(ptr); return cppa::to_string(ptr);
} }
inline std::string cppa_stream_arg(const cppa::actor_addr& ptr) {
return cppa::to_string(ptr);
}
inline std::string cppa_stream_arg(const bool& value) { inline std::string cppa_stream_arg(const bool& value) {
return value ? "true" : "false"; return value ? "true" : "false";
} }
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "test.hpp" #include "test.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/scoped_actor.hpp"
namespace cppa { namespace cppa {
inline std::ostream& operator<<(std::ostream& out, const atom_value& a) { inline std::ostream& operator<<(std::ostream& out, const atom_value& a) {
...@@ -27,6 +28,15 @@ void foo() { ...@@ -27,6 +28,15 @@ void foo() {
<< " = " << to_string(AtomValue) << ")"); << " = " << to_string(AtomValue) << ")");
} }
struct mirror {
mirror(local_actor* self) : m_self(self) { }
template<typename... Ts>
void operator()(Ts&&... args) {
m_self->send(m_self, make_any_tuple(std::forward<Ts>(args)...));
}
local_actor* m_self;
};
int main() { int main() {
bool matched_pattern[3] = { false, false, false }; bool matched_pattern[3] = { false, false, false };
CPPA_TEST(test_atom); CPPA_TEST(test_atom);
...@@ -38,12 +48,14 @@ int main() { ...@@ -38,12 +48,14 @@ int main() {
CPPA_CHECK_EQUAL(atom(" "), atom("@!?")); CPPA_CHECK_EQUAL(atom(" "), atom("@!?"));
// check to_string impl. // check to_string impl.
CPPA_CHECK_EQUAL(to_string(s_foo), "FooBar"); CPPA_CHECK_EQUAL(to_string(s_foo), "FooBar");
self << make_cow_tuple(atom("foo"), static_cast<std::uint32_t>(42)) scoped_actor self;
<< make_cow_tuple(atom(":Attach"), atom(":Baz"), "cstring") mirror m(self.get());
<< make_cow_tuple(atom("b"), atom("a"), atom("c"), 23.f) m(atom("foo"), static_cast<std::uint32_t>(42));
<< make_cow_tuple(atom("a"), atom("b"), atom("c"), 23.f); m(atom(":Attach"), atom(":Baz"), "cstring");
m(atom("b"), atom("a"), atom("c"), 23.f);
m(atom("a"), atom("b"), atom("c"), 23.f);
int i = 0; int i = 0;
receive_for(i, 3) ( self->receive_for(i, 3) (
on<atom("foo"), std::uint32_t>() >> [&](std::uint32_t value) { on<atom("foo"), std::uint32_t>() >> [&](std::uint32_t value) {
matched_pattern[0] = true; matched_pattern[0] = true;
CPPA_CHECK_EQUAL(value, 42); CPPA_CHECK_EQUAL(value, 42);
...@@ -58,7 +70,7 @@ int main() { ...@@ -58,7 +70,7 @@ int main() {
} }
); );
CPPA_CHECK(matched_pattern[0] && matched_pattern[1] && matched_pattern[2]); CPPA_CHECK(matched_pattern[0] && matched_pattern[1] && matched_pattern[2]);
receive ( self->receive (
// "erase" message { atom("b"), atom("a"), atom("c"), 23.f } // "erase" message { atom("b"), atom("a"), atom("c"), 23.f }
others() >> CPPA_CHECKPOINT_CB(), others() >> CPPA_CHECKPOINT_CB(),
after(std::chrono::seconds(0)) >> CPPA_UNEXPECTED_TOUT_CB() after(std::chrono::seconds(0)) >> CPPA_UNEXPECTED_TOUT_CB()
......
...@@ -135,7 +135,8 @@ int main(int argc, char** argv) { ...@@ -135,7 +135,8 @@ int main(int argc, char** argv) {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto p = spawn(ping, 10); auto p = spawn(ping, 10);
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto cl = spawn_io(peer, "localhost", port, p); //FIXME auto cl = spawn_io(peer, "localhost", port, p);
actor cl;
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
send_as(nullptr, p, atom("kickoff"), cl); send_as(nullptr, p, atom("kickoff"), cl);
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
...@@ -154,7 +155,7 @@ int main(int argc, char** argv) { ...@@ -154,7 +155,7 @@ int main(int argc, char** argv) {
uint16_t port = 4242; uint16_t port = 4242;
for (;;) { for (;;) {
try { try {
spawn_io_server(peer_acceptor, port, p); //FIXME: spawn_io_server(peer_acceptor, port, p);
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
ostringstream oss; ostringstream oss;
oss << app_path << " mode=client port=" << port << " &>/dev/null"; oss << app_path << " mode=client port=" << port << " &>/dev/null";
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
#include "test.hpp" #include "test.hpp"
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/self.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/group.hpp" #include "cppa/group.hpp"
...@@ -22,14 +21,14 @@ using std::endl; ...@@ -22,14 +21,14 @@ using std::endl;
using std::string; using std::string;
using namespace cppa; using namespace cppa;
void testee(int current_value, int final_result) { void testee(untyped_actor* self, int current_value, int final_result) {
become( self->become(
on_arg_match >> [=](int result) { on_arg_match >> [=](int result) {
auto next = result + current_value; auto next = result + current_value;
if (next >= final_result) self->quit(); if (next >= final_result) self->quit();
else testee(next, final_result); else testee(self, next, final_result);
}, },
after(std::chrono::seconds(2)) >> [] { after(std::chrono::seconds(2)) >> [=] {
CPPA_UNEXPECTED_TOUT(); CPPA_UNEXPECTED_TOUT();
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
} }
...@@ -38,8 +37,9 @@ void testee(int current_value, int final_result) { ...@@ -38,8 +37,9 @@ void testee(int current_value, int final_result) {
int main() { int main() {
CPPA_TEST(test_local_group); CPPA_TEST(test_local_group);
/*
auto foo_group = group::get("local", "foo"); auto foo_group = group::get("local", "foo");
actor_ptr master = spawn_in_group(foo_group, testee, 0, 10); auto master = spawn_in_group(foo_group, testee, 0, 10);
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
// spawn five workers and let them join local/foo // spawn five workers and let them join local/foo
spawn_in_group(foo_group, [master] { spawn_in_group(foo_group, [master] {
...@@ -52,5 +52,6 @@ int main() { ...@@ -52,5 +52,6 @@ int main() {
send(foo_group, 2); send(foo_group, 2);
await_all_actors_done(); await_all_actors_done();
shutdown(); shutdown();
*/
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
...@@ -18,10 +18,10 @@ namespace { ...@@ -18,10 +18,10 @@ namespace {
typedef std::pair<std::string, std::string> string_pair; typedef std::pair<std::string, std::string> string_pair;
typedef vector<actor_ptr> actor_vector; typedef vector<actor> actor_vector;
void reflector() { void reflector(untyped_actor* self) {
become ( self->become (
others() >> [=] { others() >> [=] {
CPPA_LOGF_INFO("reflect and quit"); CPPA_LOGF_INFO("reflect and quit");
self->quit(); self->quit();
...@@ -30,26 +30,26 @@ void reflector() { ...@@ -30,26 +30,26 @@ void reflector() {
); );
} }
void spawn5_server_impl(actor_ptr client, group_ptr grp) { void spawn5_server_impl(untyped_actor* self, actor client, group_ptr grp) {
CPPA_LOGF_TRACE(CPPA_TARG(client, to_string) CPPA_LOGF_TRACE(CPPA_TARG(client, to_string)
<< ", " << CPPA_TARG(grp, to_string)); << ", " << CPPA_TARG(grp, to_string));
spawn_in_group(grp, reflector); //FIXME spawn_in_group(grp, reflector);
spawn_in_group(grp, reflector); //FIXME spawn_in_group(grp, reflector);
CPPA_LOGF_INFO("send {'Spawn5'} and await {'ok', actor_vector}"); CPPA_LOGF_INFO("send {'Spawn5'} and await {'ok', actor_vector}");
sync_send(client, atom("Spawn5"), grp).then( self->sync_send(client, atom("Spawn5"), grp).then(
on(atom("ok"), arg_match) >> [=](const actor_vector& vec) { on(atom("ok"), arg_match) >> [=](const actor_vector& vec) {
CPPA_LOGF_INFO("received vector with " << vec.size() << " elements"); CPPA_LOGF_INFO("received vector with " << vec.size() << " elements");
send(grp, "Hello reflectors!", 5.0); self->send(grp, "Hello reflectors!", 5.0);
if (vec.size() != 5) { if (vec.size() != 5) {
CPPA_PRINTERR("remote client did not spawn five reflectors!"); CPPA_PRINTERR("remote client did not spawn five reflectors!");
} }
for (auto& a : vec) self->monitor(a); for (auto& a : vec) self->monitor(a);
}, },
others() >> [] { others() >> [=] {
CPPA_UNEXPECTED_MSG(); CPPA_UNEXPECTED_MSG();
self->quit(exit_reason::unhandled_exception); self->quit(exit_reason::unhandled_exception);
}, },
after(chrono::seconds(10)) >> [] { after(chrono::seconds(10)) >> [=] {
CPPA_UNEXPECTED_TOUT(); CPPA_UNEXPECTED_TOUT();
self->quit(exit_reason::unhandled_exception); self->quit(exit_reason::unhandled_exception);
} }
...@@ -58,34 +58,34 @@ void spawn5_server_impl(actor_ptr client, group_ptr grp) { ...@@ -58,34 +58,34 @@ void spawn5_server_impl(actor_ptr client, group_ptr grp) {
CPPA_PRINT("wait for reflected messages"); CPPA_PRINT("wait for reflected messages");
// receive seven reply messages (2 local, 5 remote) // receive seven reply messages (2 local, 5 remote)
auto replies = std::make_shared<int>(0); auto replies = std::make_shared<int>(0);
become ( self->become (
on("Hello reflectors!", 5.0) >> [=] { on("Hello reflectors!", 5.0) >> [=] {
if (++*replies == 7) { if (++*replies == 7) {
CPPA_PRINT("wait for DOWN messages"); CPPA_PRINT("wait for DOWN messages");
auto downs = std::make_shared<int>(0); auto downs = std::make_shared<int>(0);
become ( self->become (
on(atom("DOWN"), arg_match) >> [=](std::uint32_t reason) { on(atom("DOWN"), arg_match) >> [=](std::uint32_t reason) {
if (reason != exit_reason::normal) { if (reason != exit_reason::normal) {
CPPA_PRINTERR("reflector exited for non-normal exit reason!"); CPPA_PRINTERR("reflector exited for non-normal exit reason!");
} }
if (++*downs == 5) { if (++*downs == 5) {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
send(client, atom("Spawn5Done")); self->send(client, atom("Spawn5Done"));
self->quit(); self->quit();
} }
}, },
others() >> [] { others() >> [=] {
CPPA_UNEXPECTED_MSG(); CPPA_UNEXPECTED_MSG();
self->quit(exit_reason::unhandled_exception); self->quit(exit_reason::unhandled_exception);
}, },
after(chrono::seconds(2)) >> [] { after(chrono::seconds(2)) >> [=] {
CPPA_UNEXPECTED_TOUT(); CPPA_UNEXPECTED_TOUT();
self->quit(exit_reason::unhandled_exception); self->quit(exit_reason::unhandled_exception);
} }
); );
} }
}, },
after(std::chrono::seconds(2)) >> [] { after(std::chrono::seconds(2)) >> [=] {
CPPA_UNEXPECTED_TOUT(); CPPA_UNEXPECTED_TOUT();
self->quit(exit_reason::unhandled_exception); self->quit(exit_reason::unhandled_exception);
} }
...@@ -94,33 +94,33 @@ void spawn5_server_impl(actor_ptr client, group_ptr grp) { ...@@ -94,33 +94,33 @@ void spawn5_server_impl(actor_ptr client, group_ptr grp) {
} }
// receive seven reply messages (2 local, 5 remote) // receive seven reply messages (2 local, 5 remote)
void spawn5_server(actor_ptr client, bool inverted) { void spawn5_server(untyped_actor* self, actor client, bool inverted) {
if (!inverted) spawn5_server_impl(client, group::get("local", "foobar")); if (!inverted) spawn5_server_impl(self, client, group::get("local", "foobar"));
else { else {
CPPA_LOGF_INFO("request group"); CPPA_LOGF_INFO("request group");
sync_send(client, atom("GetGroup")).then ( self->sync_send(client, atom("GetGroup")).then (
[=](const group_ptr& remote_group) { [=](const group_ptr& remote_group) {
spawn5_server_impl(client, remote_group); spawn5_server_impl(self, client, remote_group);
} }
); );
} }
} }
void spawn5_client() { void spawn5_client(untyped_actor* self) {
become ( self->become (
on(atom("GetGroup")) >> []() -> group_ptr { on(atom("GetGroup")) >> []() -> group_ptr {
CPPA_LOGF_INFO("received {'GetGroup'}"); CPPA_LOGF_INFO("received {'GetGroup'}");
return group::get("local", "foobar"); return group::get("local", "foobar");
}, },
on(atom("Spawn5"), arg_match) >> [=](const group_ptr& grp) -> any_tuple { on(atom("Spawn5"), arg_match) >> [=](const group_ptr&) -> any_tuple {
CPPA_LOGF_INFO("received {'Spawn5'}"); CPPA_LOGF_INFO("received {'Spawn5'}");
actor_vector vec; actor_vector vec;
for (int i = 0; i < 5; ++i) { for (int i = 0; i < 5; ++i) {
vec.push_back(spawn_in_group(grp, reflector)); //FIXME vec.push_back(spawn_in_group(grp, reflector));
} }
return {atom("ok"), std::move(vec)}; return make_any_tuple(atom("ok"), std::move(vec));
}, },
on(atom("Spawn5Done")) >> [] { on(atom("Spawn5Done")) >> [=] {
CPPA_LOGF_INFO("received {'Spawn5Done'}"); CPPA_LOGF_INFO("received {'Spawn5Done'}");
self->quit(); self->quit();
} }
...@@ -129,8 +129,9 @@ void spawn5_client() { ...@@ -129,8 +129,9 @@ void spawn5_client() {
} // namespace <anonymous> } // namespace <anonymous>
template<typename T> template<typename F>
void await_down(actor_ptr ptr, T continuation) { void await_down(actor, F) {
/*
become ( become (
on(atom("DOWN"), arg_match) >> [=](uint32_t) -> bool { on(atom("DOWN"), arg_match) >> [=](uint32_t) -> bool {
if (self->last_sender() == ptr) { if (self->last_sender() == ptr) {
...@@ -140,27 +141,28 @@ void await_down(actor_ptr ptr, T continuation) { ...@@ -140,27 +141,28 @@ void await_down(actor_ptr ptr, T continuation) {
return false; // not the 'DOWN' message we are waiting for return false; // not the 'DOWN' message we are waiting for
} }
); );
*/
} }
static constexpr size_t num_pings = 10; static constexpr size_t num_pings = 10;
class client : public event_based_actor { class client : public untyped_actor {
public: public:
client(actor_ptr server) : m_server(std::move(server)) { } client(actor server) : m_server(std::move(server)) { }
void init() { behavior make_behavior() override {
spawn_ping(); return spawn_ping();
} }
private: private:
void spawn_ping() { behavior spawn_ping() {
CPPA_PRINT("send {'SpawnPing'}"); CPPA_PRINT("send {'SpawnPing'}");
send(m_server, atom("SpawnPing")); send(m_server, atom("SpawnPing"));
become ( return (
on(atom("PingPtr"), arg_match) >> [=](const actor_ptr& ping) { on(atom("PingPtr"), arg_match) >> [=](const actor& ping) {
auto pptr = spawn<monitored+detached+blocking_api>(pong, ping); auto pptr = spawn<monitored+detached+blocking_api>(pong, ping);
await_down(pptr, [=] { await_down(pptr, [=] {
send_sync_msg(); send_sync_msg();
...@@ -195,7 +197,7 @@ class client : public event_based_actor { ...@@ -195,7 +197,7 @@ class client : public event_based_actor {
void test_group_comm() { void test_group_comm() {
CPPA_PRINT("test group communication via network"); CPPA_PRINT("test group communication via network");
sync_send(m_server, atom("GClient")).then( sync_send(m_server, atom("GClient")).then(
on(atom("GClient"), arg_match) >> [=](actor_ptr gclient) { on(atom("GClient"), arg_match) >> [=](actor gclient) {
auto s5a = spawn<monitored>(spawn5_server, gclient, false); auto s5a = spawn<monitored>(spawn5_server, gclient, false);
await_down(s5a, [=]{ await_down(s5a, [=]{
test_group_comm_inverted(); test_group_comm_inverted();
...@@ -208,38 +210,38 @@ class client : public event_based_actor { ...@@ -208,38 +210,38 @@ class client : public event_based_actor {
CPPA_PRINT("test group communication via network (inverted setup)"); CPPA_PRINT("test group communication via network (inverted setup)");
become ( become (
on(atom("GClient")) >> [=]() -> any_tuple { on(atom("GClient")) >> [=]() -> any_tuple {
auto cptr = self->last_sender(); auto cptr = last_sender();
auto s5c = spawn<monitored>(spawn5_client); auto s5c = spawn<monitored>(spawn5_client);
// set next behavior // set next behavior
await_down(s5c, [=] { await_down(s5c, [=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
self->quit(); quit();
}); });
return {atom("GClient"), s5c}; return make_any_tuple(atom("GClient"), s5c);
} }
); );
} }
actor_ptr m_server; actor m_server;
}; };
class server : public event_based_actor { class server : public untyped_actor {
public: public:
void init() { behavior make_behavior() override {
await_spawn_ping(); return await_spawn_ping();
} }
private: private:
void await_spawn_ping() { behavior await_spawn_ping() {
CPPA_PRINT("await {'SpawnPing'}"); CPPA_PRINT("await {'SpawnPing'}");
become ( return (
on(atom("SpawnPing")) >> [=]() -> any_tuple { on(atom("SpawnPing")) >> [=]() -> any_tuple {
CPPA_PRINT("received {'SpawnPing'}"); CPPA_PRINT("received {'SpawnPing'}");
auto client = self->last_sender(); auto client = last_sender();
CPPA_LOGF_ERROR_IF(!client, "last_sender() == nullptr"); CPPA_LOGF_ERROR_IF(!client, "last_sender() == nullptr");
CPPA_LOGF_INFO("spawn event-based ping actor"); CPPA_LOGF_INFO("spawn event-based ping actor");
auto pptr = spawn<monitored>(event_based_ping, num_pings); auto pptr = spawn<monitored>(event_based_ping, num_pings);
...@@ -248,7 +250,7 @@ class server : public event_based_actor { ...@@ -248,7 +250,7 @@ class server : public event_based_actor {
CPPA_CHECK_EQUAL(pongs(), num_pings); CPPA_CHECK_EQUAL(pongs(), num_pings);
await_sync_msg(); await_sync_msg();
}); });
return {atom("PingPtr"), pptr}; return make_any_tuple(atom("PingPtr"), pptr);
} }
); );
} }
...@@ -275,7 +277,7 @@ class server : public event_based_actor { ...@@ -275,7 +277,7 @@ class server : public event_based_actor {
CPPA_CHECK_EQUAL(*foobars, 100); CPPA_CHECK_EQUAL(*foobars, 100);
test_group_comm(); test_group_comm();
} }
return self->last_dequeued(); return last_dequeued();
} }
); );
} }
...@@ -284,23 +286,23 @@ class server : public event_based_actor { ...@@ -284,23 +286,23 @@ class server : public event_based_actor {
CPPA_PRINT("test group communication via network"); CPPA_PRINT("test group communication via network");
become ( become (
on(atom("GClient")) >> [=]() -> any_tuple { on(atom("GClient")) >> [=]() -> any_tuple {
auto cptr = self->last_sender(); auto cptr = last_sender();
auto s5c = spawn<monitored>(spawn5_client); auto s5c = spawn<monitored>(spawn5_client);
await_down(s5c, [=] { await_down(s5c, [=] {
test_group_comm_inverted(cptr); //test_group_comm_inverted(cptr);
}); });
return {atom("GClient"), s5c}; return make_any_tuple(atom("GClient"), s5c);
} }
); );
} }
void test_group_comm_inverted(actor_ptr cptr) { void test_group_comm_inverted(actor cptr) {
CPPA_PRINT("test group communication via network (inverted setup)"); CPPA_PRINT("test group communication via network (inverted setup)");
sync_send(cptr, atom("GClient")).then ( sync_send(cptr, atom("GClient")).then (
on(atom("GClient"), arg_match) >> [=](actor_ptr gclient) { on(atom("GClient"), arg_match) >> [=](actor gclient) {
await_down(spawn<monitored>(spawn5_server, gclient, true), [=] { await_down(spawn<monitored>(spawn5_server, gclient, true), [=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
self->quit(); quit();
}); });
} }
); );
...@@ -321,6 +323,7 @@ int main(int argc, char** argv) { ...@@ -321,6 +323,7 @@ int main(int argc, char** argv) {
} }
else { else {
run_client_part(get_kv_pairs(argc, argv), [](uint16_t port) { run_client_part(get_kv_pairs(argc, argv), [](uint16_t port) {
scoped_actor self;
auto serv = remote_actor("localhost", port); auto serv = remote_actor("localhost", port);
// remote_actor is supposed to return the same server // remote_actor is supposed to return the same server
// when connecting to the same host again // when connecting to the same host again
...@@ -331,8 +334,8 @@ int main(int argc, char** argv) { ...@@ -331,8 +334,8 @@ int main(int argc, char** argv) {
auto server3 = remote_actor(localhost, port); auto server3 = remote_actor(localhost, port);
CPPA_CHECK(serv == server3); CPPA_CHECK(serv == server3);
} }
auto c = spawn<client, monitored>(serv); auto c = self->spawn<client, monitored>(serv);
receive ( self->receive (
on(atom("DOWN"), arg_match) >> [=](uint32_t rsn) { on(atom("DOWN"), arg_match) >> [=](uint32_t rsn) {
CPPA_CHECK_EQUAL(self->last_sender(), c); CPPA_CHECK_EQUAL(self->last_sender(), c);
CPPA_CHECK_EQUAL(rsn, exit_reason::normal); CPPA_CHECK_EQUAL(rsn, exit_reason::normal);
...@@ -343,7 +346,10 @@ int main(int argc, char** argv) { ...@@ -343,7 +346,10 @@ int main(int argc, char** argv) {
} }
} }
CPPA_TEST(test_remote_actor); CPPA_TEST(test_remote_actor);
auto serv = spawn<server, monitored>(); thread child;
{ // lifetime scope of self
scoped_actor self;
auto serv = self->spawn<server, monitored>();
uint16_t port = 4242; uint16_t port = 4242;
bool success = false; bool success = false;
do { do {
...@@ -358,7 +364,6 @@ int main(int argc, char** argv) { ...@@ -358,7 +364,6 @@ int main(int argc, char** argv) {
} }
} }
while (!success); while (!success);
thread child;
ostringstream oss; ostringstream oss;
if (run_remote_actor) { if (run_remote_actor) {
oss << app_path << " run=remote_actor port=" << port << " &>/dev/null"; oss << app_path << " run=remote_actor port=" << port << " &>/dev/null";
...@@ -375,12 +380,13 @@ int main(int argc, char** argv) { ...@@ -375,12 +380,13 @@ int main(int argc, char** argv) {
} }
else { CPPA_PRINT("actor published at port " << port); } else { CPPA_PRINT("actor published at port " << port); }
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
receive ( self->receive (
on(atom("DOWN"), arg_match) >> [=](uint32_t rsn) { on(atom("DOWN"), arg_match) >> [&](uint32_t rsn) {
CPPA_CHECK_EQUAL(self->last_sender(), serv); CPPA_CHECK_EQUAL(self->last_sender(), serv);
CPPA_CHECK_EQUAL(rsn, exit_reason::normal); CPPA_CHECK_EQUAL(rsn, exit_reason::normal);
} }
); );
} // lifetime scope of self
// wait until separate process (in sep. thread) finished execution // wait until separate process (in sep. thread) finished execution
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include "test.hpp" #include "test.hpp"
#include "cppa/self.hpp"
#include "cppa/cow_tuple.hpp" #include "cppa/cow_tuple.hpp"
#include "cppa/any_tuple.hpp" #include "cppa/any_tuple.hpp"
#include "cppa/announce.hpp" #include "cppa/announce.hpp"
...@@ -227,7 +226,8 @@ int main() { ...@@ -227,7 +226,8 @@ int main() {
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); } catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try { try {
auto ttup = make_any_tuple(1, 2, actor_ptr(self)); scoped_actor self;
auto ttup = make_any_tuple(1, 2, actor{self.get()});
util::buffer wr_buf; util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing); binary_serializer bs(&wr_buf, &addressing);
bs << ttup; bs << ttup;
...@@ -239,7 +239,8 @@ int main() { ...@@ -239,7 +239,8 @@ int main() {
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); } catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try { try {
auto ttup = make_any_tuple(1, 2, actor_ptr(self)); scoped_actor self;
auto ttup = make_any_tuple(1, 2, actor{self.get()});
util::buffer wr_buf; util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing); binary_serializer bs(&wr_buf, &addressing);
bs << ttup; bs << ttup;
...@@ -275,47 +276,6 @@ int main() { ...@@ -275,47 +276,6 @@ int main() {
} }
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); } catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try {
/*
any_tuple msg1 = cppa::make_cow_tuple(42, string("Hello \"World\"!"));
auto msg1_tostring = to_string(msg1);
if (msg1str != msg1_tostring) {
CPPA_FAILURE("msg1str != to_string(msg1)");
cerr << "to_string(msg1) = " << msg1_tostring << endl;
cerr << "to_string(msg1str) = " << msg1str << endl;
}
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
bs << msg1;
binary_deserializer bd(wr_buf.data(), wr_buf.size(), &addressing);
object obj1;
bd >> obj1;
object obj2 = from_string(to_string(msg1));
CPPA_CHECK(obj1 == obj2);
if (typeid(any_tuple) == *(obj1.type()) && obj2.type() == obj1.type()) {
auto& content1 = get<any_tuple>(obj1);
auto& content2 = get<any_tuple>(obj2);
auto opt1 = tuple_cast<decltype(42), string>(content1);
auto opt2 = tuple_cast<decltype(42), string>(content2);
CPPA_CHECK(opt1.valid() && opt2.valid());
if (opt1.valid() && opt2.valid()) {
auto& tup1 = *opt1;
auto& tup2 = *opt2;
CPPA_CHECK_EQUAL(tup1.size(), 2);
CPPA_CHECK_EQUAL(tup2.size(), 2);
CPPA_CHECK_EQUAL(get<0>(tup1), 42);
CPPA_CHECK_EQUAL(get<0>(tup2), 42);
CPPA_CHECK_EQUAL(get<1>(tup1), "Hello \"World\"!");
CPPA_CHECK_EQUAL(get<1>(tup2), "Hello \"World\"!");
}
}
else {
CPPA_FAILURE("obj.type() != typeid(message)");
}
*/
}
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
CPPA_CHECK((is_iterable<int>::value) == false); CPPA_CHECK((is_iterable<int>::value) == false);
// string is primitive and thus not identified by is_iterable // string is primitive and thus not identified by is_iterable
CPPA_CHECK((is_iterable<string>::value) == false); CPPA_CHECK((is_iterable<string>::value) == false);
...@@ -333,71 +293,5 @@ int main() { ...@@ -333,71 +293,5 @@ int main() {
} }
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); } catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try
{ // test serializers / deserializers with struct_b
// get meta object for struct_b
/*
announce<struct_b>(compound_member(&struct_b::a,
&struct_a::x,
&struct_a::y),
&struct_b::z,
&struct_b::ints);
// testees
struct_b b1 = { { 1, 2 }, 3, list<int>{ 4, 5, 6, 7, 8, 9, 10 } };
struct_b b2;
struct_b b3;
// expected result of to_string(&b1, meta_b)
auto b1str = "struct_b ( struct_a ( 1, 2 ), 3, "
"{ 4, 5, 6, 7, 8, 9, 10 } )";
// verify
CPPA_CHECK_EQUAL((to_string(b1)), b1str); {
// serialize b1 to buf
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
bs << b1;
// deserialize b2 from buf
binary_deserializer bd(wr_buf.data(), wr_buf.size(), &addressing);
object res;
bd >> res;
CPPA_CHECK_EQUAL(res.type()->name(), "struct_b");
b2 = get<struct_b>(res);
}
// verify result of serialization / deserialization
CPPA_CHECK(b1 == b2);
CPPA_CHECK_EQUAL(to_string(b2), b1str);
{ // deserialize b3 from string
object res = from_string(b1str);
CPPA_CHECK_EQUAL(res.type()->name(), "struct_b");
b3 = get<struct_b>(res);
}
CPPA_CHECK(b1 == b3);
*/
}
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
try { // test serializers / deserializers with struct_c
// get meta type of struct_c and "announce"
/*
announce<struct_c>(&struct_c::strings, &struct_c::ints);
// testees
struct_c c1{strmap{{"abc", u"cba" }, { "x", u"y" }}, set<int>{9, 4, 5}};
struct_c c2; {
// serialize c1 to buf
util::buffer wr_buf;
binary_serializer bs(&wr_buf, &addressing);
bs << c1;
// serialize c2 from buf
binary_deserializer bd(wr_buf.data(), wr_buf.size(), &addressing);
object res;
bd >> res;
CPPA_CHECK_EQUAL(res.type()->name(), "struct_c");
c2 = get<struct_c>(res);
}
// verify result of serialization / deserialization
CPPA_CHECK(c1 == c2);
*/
}
catch (exception& e) { CPPA_FAILURE(to_verbose_string(e)); }
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
...@@ -6,16 +6,7 @@ ...@@ -6,16 +6,7 @@
#include "test.hpp" #include "test.hpp"
#include "ping_pong.hpp" #include "ping_pong.hpp"
#include "cppa/on.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/actor.hpp"
#include "cppa/factory.hpp"
#include "cppa/scheduler.hpp"
#include "cppa/sb_actor.hpp"
#include "cppa/to_string.hpp"
#include "cppa/exit_reason.hpp"
#include "cppa/util/type_traits.hpp"
#include "cppa/event_based_actor.hpp"
using namespace std; using namespace std;
using namespace cppa; using namespace cppa;
...@@ -64,7 +55,7 @@ class event_testee : public sb_actor<event_testee> { ...@@ -64,7 +55,7 @@ class event_testee : public sb_actor<event_testee> {
}; };
// quits after 5 timeouts // quits after 5 timeouts
actor_ptr spawn_event_testee2() { actor spawn_event_testee2() {
struct impl : sb_actor<impl> { struct impl : sb_actor<impl> {
behavior wait4timeout(int remaining) { behavior wait4timeout(int remaining) {
return ( return (
...@@ -84,7 +75,7 @@ actor_ptr spawn_event_testee2() { ...@@ -84,7 +75,7 @@ actor_ptr spawn_event_testee2() {
struct chopstick : public sb_actor<chopstick> { struct chopstick : public sb_actor<chopstick> {
behavior taken_by(actor_ptr whom) { behavior taken_by(actor whom) {
return ( return (
on<atom("take")>() >> [=] { on<atom("take")>() >> [=] {
return atom("busy"); return atom("busy");
...@@ -92,7 +83,7 @@ struct chopstick : public sb_actor<chopstick> { ...@@ -92,7 +83,7 @@ struct chopstick : public sb_actor<chopstick> {
on(atom("put"), whom) >> [=] { on(atom("put"), whom) >> [=] {
become(available); become(available);
}, },
on(atom("break")) >> [=]() { on(atom("break")) >> [=] {
quit(); quit();
} }
); );
...@@ -104,7 +95,7 @@ struct chopstick : public sb_actor<chopstick> { ...@@ -104,7 +95,7 @@ struct chopstick : public sb_actor<chopstick> {
chopstick() { chopstick() {
available = ( available = (
on(atom("take"), arg_match) >> [=](actor_ptr whom) -> atom_value { on(atom("take"), arg_match) >> [=](actor whom) -> atom_value {
become(taken_by(whom)); become(taken_by(whom));
return atom("taken"); return atom("taken");
}, },
...@@ -118,9 +109,9 @@ struct chopstick : public sb_actor<chopstick> { ...@@ -118,9 +109,9 @@ struct chopstick : public sb_actor<chopstick> {
class testee_actor { class testee_actor {
void wait4string() { void wait4string(blocking_untyped_actor* self) {
bool string_received = false; bool string_received = false;
do_receive ( self->do_receive (
on<string>() >> [&] { on<string>() >> [&] {
string_received = true; string_received = true;
}, },
...@@ -131,9 +122,9 @@ class testee_actor { ...@@ -131,9 +122,9 @@ class testee_actor {
.until(gref(string_received)); .until(gref(string_received));
} }
void wait4float() { void wait4float(blocking_untyped_actor* self) {
bool float_received = false; bool float_received = false;
do_receive ( self->do_receive (
on<float>() >> [&] { on<float>() >> [&] {
float_received = true; float_received = true;
}, },
...@@ -142,15 +133,15 @@ class testee_actor { ...@@ -142,15 +133,15 @@ class testee_actor {
} }
) )
.until(gref(float_received)); .until(gref(float_received));
wait4string(); wait4string(self);
} }
public: public:
void operator()() { void operator()(blocking_untyped_actor* self) {
receive_loop ( self->receive_loop (
on<int>() >> [&] { on<int>() >> [&] {
wait4float(); wait4float(self);
}, },
on<atom("get_state")>() >> [&] { on<atom("get_state")>() >> [&] {
return "wait4int"; return "wait4int";
...@@ -160,40 +151,43 @@ class testee_actor { ...@@ -160,40 +151,43 @@ class testee_actor {
}; };
// receives one timeout and quits // self->receives one timeout and quits
void testee1() { void testee1(untyped_actor* self) {
become(after(chrono::milliseconds(10)) >> [] { unbecome(); }); self->become(after(chrono::milliseconds(10)) >> [=] { self->unbecome(); });
} }
void testee2(actor_ptr other) { void testee2(untyped_actor* self, actor other) {
self->link_to(other); self->link_to(other);
send(other, uint32_t(1)); self->send(other, uint32_t(1));
become ( self->become (
on<uint32_t>() >> [](uint32_t sleep_time) { on<uint32_t>() >> [=](uint32_t sleep_time) {
// "sleep" for sleep_time milliseconds // "sleep" for sleep_time milliseconds
become ( self->become (
keep_behavior, keep_behavior,
after(chrono::milliseconds(sleep_time)) >> [] { unbecome(); } after(chrono::milliseconds(sleep_time)) >> [=] {
self->unbecome();
}
); );
} }
); );
} }
template<class Testee> template<class Testee>
string behavior_test(actor_ptr et) { string behavior_test(actor et) {
scoped_actor self;
string result; string result;
string testee_name = detail::to_uniform_name(typeid(Testee)); string testee_name = detail::to_uniform_name(typeid(Testee));
send(et, 1); self->send(et, 1);
send(et, 2); self->send(et, 2);
send(et, 3); self->send(et, 3);
send(et, .1f); self->send(et, .1f);
send(et, "hello " + testee_name); self->send(et, "hello " + testee_name);
send(et, .2f); self->send(et, .2f);
send(et, .3f); self->send(et, .3f);
send(et, "hello again " + testee_name); self->send(et, "hello again " + testee_name);
send(et, "goodbye " + testee_name); self->send(et, "goodbye " + testee_name);
send(et, atom("get_state")); self->send(et, atom("get_state"));
receive ( self->receive (
on_arg_match >> [&](const string& str) { on_arg_match >> [&](const string& str) {
result = str; result = str;
}, },
...@@ -202,7 +196,7 @@ string behavior_test(actor_ptr et) { ...@@ -202,7 +196,7 @@ string behavior_test(actor_ptr et) {
throw runtime_error(testee_name + " does not reply"); throw runtime_error(testee_name + " does not reply");
} }
); );
send_exit(et, exit_reason::user_shutdown); self->send_exit(et, exit_reason::user_shutdown);
await_all_actors_done(); await_all_actors_done();
return result; return result;
} }
...@@ -259,9 +253,9 @@ class fixed_stack : public sb_actor<fixed_stack> { ...@@ -259,9 +253,9 @@ class fixed_stack : public sb_actor<fixed_stack> {
}; };
void echo_actor() { behavior echo_actor(untyped_actor* self) {
become ( return (
others() >> []() -> any_tuple { others() >> [=]() -> any_tuple {
self->quit(exit_reason::normal); self->quit(exit_reason::normal);
return self->last_dequeued(); return self->last_dequeued();
} }
...@@ -272,26 +266,26 @@ void echo_actor() { ...@@ -272,26 +266,26 @@ void echo_actor() {
struct simple_mirror : sb_actor<simple_mirror> { struct simple_mirror : sb_actor<simple_mirror> {
behavior init_state = ( behavior init_state = (
others() >> [] { others() >> [=] {
return self->last_dequeued(); return last_dequeued();
} }
); );
}; };
void high_priority_testee() { behavior high_priority_testee(untyped_actor* self) {
send(self, atom("b")); self->send(self, atom("b"));
send({self, message_priority::high}, atom("a")); self->send(message_priority::high, self, atom("a"));
// 'a' must be received before 'b' // 'a' must be self->received before 'b'
become ( return (
on(atom("b")) >> [] { on(atom("b")) >> [=] {
CPPA_FAILURE("received 'b' before 'a'"); CPPA_FAILURE("received 'b' before 'a'");
self->quit(); self->quit();
}, },
on(atom("a")) >> [] { on(atom("a")) >> [=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
become ( self->become (
on(atom("b")) >> [] { on(atom("b")) >> [=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
self->quit(); self->quit();
}, },
...@@ -302,65 +296,65 @@ void high_priority_testee() { ...@@ -302,65 +296,65 @@ void high_priority_testee() {
); );
} }
struct high_priority_testee_class : event_based_actor { struct high_priority_testee_class : untyped_actor {
void init() { behavior make_behavior() override {
high_priority_testee(); return high_priority_testee(this);
} }
}; };
struct master : event_based_actor { struct master : untyped_actor {
void init() override { behavior make_behavior() override {
become( return (
on(atom("done")) >> []() { on(atom("done")) >> [=] {
self->quit(exit_reason::user_shutdown); quit(exit_reason::user_shutdown);
} }
); );
} }
}; };
struct slave : event_based_actor { struct slave : untyped_actor {
slave(actor_ptr master) : master{master} { } slave(actor master) : master{master} { }
void init() override { behavior make_behavior() override {
link_to(master); link_to(master);
become ( return (
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
} }
actor_ptr master; actor master;
}; };
void test_serial_reply() { void test_serial_reply() {
auto mirror_behavior = [](int num) { auto mirror_behavior = [=](untyped_actor* self, int num) {
become(others() >> [=]() -> any_tuple { self->become(others() >> [=]() -> any_tuple {
cout << "right back at you from " << num cout << "right back at you from " << num
<< "; ID: " << self->id() << endl; << "; ID: " << self->id() << endl;
return self->last_dequeued(); return self->last_dequeued();
}); });
}; };
auto master = spawn([=] { auto master = spawn([=](untyped_actor* self) {
cout << "ID of master: " << self->id() << endl; cout << "ID of master: " << self->id() << endl;
// produce 5 mirror actors // produce 5 mirror actors
auto c0 = spawn<linked>(mirror_behavior, 0); auto c0 = self->spawn<linked>(mirror_behavior, 0);
auto c1 = spawn<linked>(mirror_behavior, 1); auto c1 = self->spawn<linked>(mirror_behavior, 1);
auto c2 = spawn<linked>(mirror_behavior, 2); auto c2 = self->spawn<linked>(mirror_behavior, 2);
auto c3 = spawn<linked>(mirror_behavior, 3); auto c3 = self->spawn<linked>(mirror_behavior, 3);
auto c4 = spawn<linked>(mirror_behavior, 4); auto c4 = self->spawn<linked>(mirror_behavior, 4);
become ( self->become (
on(atom("hi there")) >> [=] { on(atom("hi there")) >> [=] {
// * // *
return sync_send(c0, atom("sub0")).then( return self->sync_send(c0, atom("sub0")).then(
on(atom("sub0")) >> [=] { on(atom("sub0")) >> [=] {
return sync_send(c1, atom("sub1")).then( return self->sync_send(c1, atom("sub1")).then(
on(atom("sub1")) >> [=] { on(atom("sub1")) >> [=] {
return sync_send(c2, atom("sub2")).then( return self->sync_send(c2, atom("sub2")).then(
on(atom("sub2")) >> [=] { on(atom("sub2")) >> [=] {
return sync_send(c3, atom("sub3")).then( return self->sync_send(c3, atom("sub3")).then(
on(atom("sub3")) >> [=] { on(atom("sub3")) >> [=] {
return sync_send(c4, atom("sub4")).then( return self->sync_send(c4, atom("sub4")).then(
on(atom("sub4")) >> [=] { on(atom("sub4")) >> [=] {
return atom("hiho"); return atom("hiho");
} }
...@@ -373,24 +367,25 @@ void test_serial_reply() { ...@@ -373,24 +367,25 @@ void test_serial_reply() {
); );
} }
); );
//*/
//return atom("hiho");
} }
); );
}); });
{ // lifetime scope of self
scoped_actor self;
cout << "ID of main: " << self->id() << endl; cout << "ID of main: " << self->id() << endl;
sync_send(master, atom("hi there")).await( self->sync_send(master, atom("hi there")).await(
on(atom("hiho")) >> [] { on(atom("hiho")) >> [] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
}, },
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
send_exit(master, exit_reason::user_shutdown); self->send_exit(master, exit_reason::user_shutdown);
}
await_all_actors_done(); await_all_actors_done();
} }
void test_or_else() { void test_or_else() {
scoped_actor self;
partial_function handle_a { partial_function handle_a {
on("a") >> [] { return 1; } on("a") >> [] { return 1; }
}; };
...@@ -400,32 +395,28 @@ void test_or_else() { ...@@ -400,32 +395,28 @@ void test_or_else() {
partial_function handle_c { partial_function handle_c {
on("c") >> [] { return 3; } on("c") >> [] { return 3; }
}; };
auto run_testee([](actor_ptr testee) { auto run_testee([&](actor testee) {
sync_send(testee, "a").await([](int i) { self->sync_send(testee, "a").await([](int i) {
CPPA_CHECK_EQUAL(i, 1); CPPA_CHECK_EQUAL(i, 1);
}); });
sync_send(testee, "b").await([](int i) { self->sync_send(testee, "b").await([](int i) {
CPPA_CHECK_EQUAL(i, 2); CPPA_CHECK_EQUAL(i, 2);
}); });
sync_send(testee, "c").await([](int i) { self->sync_send(testee, "c").await([](int i) {
CPPA_CHECK_EQUAL(i, 3); CPPA_CHECK_EQUAL(i, 3);
}); });
send_exit(testee, exit_reason::user_shutdown); self->send_exit(testee, exit_reason::user_shutdown);
await_all_actors_done(); self->await_all_other_actors_done();
}); });
run_testee( run_testee(
spawn([=] { spawn([=] {
become(handle_a.or_else(handle_b).or_else(handle_c)); return handle_a.or_else(handle_b).or_else(handle_c);
})
);
run_testee(
spawn([=] {
become(handle_a, handle_b, handle_c);
}) })
); );
run_testee( run_testee(
spawn([=] { spawn([=] {
become( return (
handle_a.or_else(handle_b), handle_a.or_else(handle_b),
on("c") >> [] { return 3; } on("c") >> [] { return 3; }
); );
...@@ -433,7 +424,7 @@ void test_or_else() { ...@@ -433,7 +424,7 @@ void test_or_else() {
); );
run_testee( run_testee(
spawn([=] { spawn([=] {
become( return (
on("a") >> [] { return 1; }, on("a") >> [] { return 1; },
handle_b.or_else(handle_c) handle_b.or_else(handle_c)
); );
...@@ -443,8 +434,8 @@ void test_or_else() { ...@@ -443,8 +434,8 @@ void test_or_else() {
void test_continuation() { void test_continuation() {
auto mirror = spawn<simple_mirror>(); auto mirror = spawn<simple_mirror>();
spawn([=] { spawn([=](untyped_actor* self) {
sync_send(mirror, 42).then( self->sync_send(mirror, 42).then(
on(42) >> [] { on(42) >> [] {
return "fourty-two"; return "fourty-two";
} }
...@@ -456,7 +447,7 @@ void test_continuation() { ...@@ -456,7 +447,7 @@ void test_continuation() {
).continue_with( ).continue_with(
[=](float f) { [=](float f) {
CPPA_CHECK_EQUAL(f, 4.2f); CPPA_CHECK_EQUAL(f, 4.2f);
send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
self->quit(); self->quit();
} }
); );
...@@ -464,8 +455,8 @@ void test_continuation() { ...@@ -464,8 +455,8 @@ void test_continuation() {
await_all_actors_done(); await_all_actors_done();
} }
int main() { void test_spawn() {
CPPA_TEST(test_spawn); scoped_actor self;
test_serial_reply(); test_serial_reply();
test_or_else(); test_or_else();
...@@ -475,36 +466,36 @@ int main() { ...@@ -475,36 +466,36 @@ int main() {
auto m = spawn<master, detached>(); auto m = spawn<master, detached>();
spawn<slave>(m); spawn<slave>(m);
spawn<slave>(m); spawn<slave>(m);
send(m, atom("done")); self->send(m, atom("done"));
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_PRINT("test send()"); CPPA_PRINT("test self->send()");
send(self, 1, 2, 3, true); self->send(self, 1, 2, 3, true);
receive(on(1, 2, 3, true) >> [] { }); self->receive(on(1, 2, 3, true) >> [] { });
self << any_tuple{}; self->send(self, any_tuple{});
receive(on() >> [] { }); self->receive(on() >> [] { });
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
self << any_tuple{}; self->send(self, any_tuple{});
receive(on() >> [] { }); self->receive(on() >> [] { });
CPPA_PRINT("test receive with zero timeout"); CPPA_PRINT("test self->receive with zero timeout");
receive ( self->receive (
others() >> CPPA_UNEXPECTED_MSG_CB(), others() >> CPPA_UNEXPECTED_MSG_CB(),
after(chrono::seconds(0)) >> [] { /* mailbox empty */ } after(chrono::seconds(0)) >> [] { /* mailbox empty */ }
); );
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_PRINT("test mirror"); { CPPA_PRINT("test mirror"); {
auto mirror = spawn<simple_mirror, monitored>(); auto mirror = self->spawn<simple_mirror, monitored>();
send(mirror, "hello mirror"); self->send(mirror, "hello mirror");
receive ( self->receive (
on("hello mirror") >> CPPA_CHECKPOINT_CB(), on("hello mirror") >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
receive ( self->receive (
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()
); );
...@@ -513,14 +504,14 @@ int main() { ...@@ -513,14 +504,14 @@ int main() {
} }
CPPA_PRINT("test detached mirror"); { CPPA_PRINT("test detached mirror"); {
auto mirror = spawn<simple_mirror, monitored+detached>(); auto mirror = self->spawn<simple_mirror, monitored+detached>();
send(mirror, "hello mirror"); self->send(mirror, "hello mirror");
receive ( self->receive (
on("hello mirror") >> CPPA_CHECKPOINT_CB(), on("hello mirror") >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
receive ( self->receive (
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()
); );
...@@ -529,15 +520,15 @@ int main() { ...@@ -529,15 +520,15 @@ int main() {
} }
CPPA_PRINT("test priority aware mirror"); { CPPA_PRINT("test priority aware mirror"); {
auto mirror = spawn<simple_mirror, monitored+priority_aware>(); auto mirror = self->spawn<simple_mirror, monitored+priority_aware>();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
send(mirror, "hello mirror"); self->send(mirror, "hello mirror");
receive ( self->receive (
on("hello mirror") >> CPPA_CHECKPOINT_CB(), on("hello mirror") >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
receive ( self->receive (
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()
); );
...@@ -547,8 +538,8 @@ int main() { ...@@ -547,8 +538,8 @@ int main() {
CPPA_PRINT("test echo actor"); CPPA_PRINT("test echo actor");
auto mecho = spawn(echo_actor); auto mecho = spawn(echo_actor);
send(mecho, "hello echo"); self->send(mecho, "hello echo");
receive ( self->receive (
on("hello echo") >> [] { }, on("hello echo") >> [] { },
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
...@@ -556,12 +547,12 @@ int main() { ...@@ -556,12 +547,12 @@ int main() {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_PRINT("test delayed_send()"); CPPA_PRINT("test delayed_send()");
delayed_send(self, chrono::seconds(1), 1, 2, 3); self->delayed_send(self, chrono::seconds(1), 1, 2, 3);
receive(on(1, 2, 3) >> [] { }); self->receive(on(1, 2, 3) >> [] { });
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_PRINT("test timeout"); CPPA_PRINT("test timeout");
receive(after(chrono::seconds(1)) >> [] { }); self->receive(after(chrono::seconds(1)) >> [] { });
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
spawn(testee1); spawn(testee1);
...@@ -573,42 +564,11 @@ int main() { ...@@ -573,42 +564,11 @@ int main() {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto cstk = spawn<chopstick>(); auto cstk = spawn<chopstick>();
send(cstk, atom("take"), self); self->send(cstk, atom("take"), self);
receive ( self->receive (
on(atom("taken")) >> [&]() { on(atom("taken")) >> [&]() {
send(cstk, atom("put"), self); self->send(cstk, atom("put"), self);
send(cstk, atom("break")); self->send(cstk, atom("break"));
}
);
await_all_actors_done();
CPPA_CHECKPOINT();
auto factory = factory::event_based([&](int* i, float*, string*) {
become (
on(atom("get_int")) >> [i] {
return *i;
},
on(atom("set_int"), arg_match) >> [i](int new_value) {
*i = new_value;
},
on(atom("done")) >> [] {
self->quit();
}
);
});
auto foobaz_actor = factory.spawn(23);
send(foobaz_actor, atom("get_int"));
send(foobaz_actor, atom("set_int"), 42);
send(foobaz_actor, atom("get_int"));
send(foobaz_actor, atom("done"));
receive (
on_arg_match >> [&](int value) {
CPPA_CHECK_EQUAL(value, 23);
}
);
receive (
on_arg_match >> [&](int value) {
CPPA_CHECK_EQUAL(value, 42);
} }
); );
await_all_actors_done(); await_all_actors_done();
...@@ -616,13 +576,13 @@ int main() { ...@@ -616,13 +576,13 @@ int main() {
auto st = spawn<fixed_stack>(10); auto st = spawn<fixed_stack>(10);
// push 20 values // push 20 values
for (int i = 0; i < 20; ++i) send(st, atom("push"), i); for (int i = 0; i < 20; ++i) self->send(st, atom("push"), i);
// pop 20 times // pop 20 times
for (int i = 0; i < 20; ++i) send(st, atom("pop")); for (int i = 0; i < 20; ++i) self->send(st, atom("pop"));
// expect 10 failure messages // expect 10 failure messages
{ {
int i = 0; int i = 0;
receive_for(i, 10) ( self->receive_for(i, 10) (
on(atom("failure")) >> [] { } on(atom("failure")) >> [] { }
); );
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
...@@ -631,7 +591,7 @@ int main() { ...@@ -631,7 +591,7 @@ int main() {
{ {
vector<int> values; vector<int> values;
int i = 0; int i = 0;
receive_for(i, 10) ( self->receive_for(i, 10) (
on(atom("ok"), arg_match) >> [&](int value) { on(atom("ok"), arg_match) >> [&](int value) {
values.push_back(value); values.push_back(value);
} }
...@@ -640,31 +600,31 @@ int main() { ...@@ -640,31 +600,31 @@ int main() {
CPPA_CHECK_EQUAL(util::join(values, ","), util::join(values, ",")); CPPA_CHECK_EQUAL(util::join(values, ","), util::join(values, ","));
} }
// terminate st // terminate st
send_exit(st, exit_reason::user_shutdown); self->send_exit(st, exit_reason::user_shutdown);
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto sync_testee1 = spawn<blocking_api>([] { auto sync_testee1 = spawn<blocking_api>([](blocking_untyped_actor* self) {
receive ( self->receive (
on(atom("get")) >> [] { on(atom("get")) >> [] {
return make_cow_tuple(42, 2); return make_cow_tuple(42, 2);
} }
); );
}); });
send(self, 0, 0); self->send(self, 0, 0);
auto handle = sync_send(sync_testee1, atom("get")); auto handle = self->sync_send(sync_testee1, atom("get"));
// wait for some time (until sync response arrived in mailbox) // wait for some time (until sync response arrived in mailbox)
receive (after(chrono::milliseconds(50)) >> [] { }); self->receive (after(chrono::milliseconds(50)) >> [] { });
// enqueue async messages (must be skipped by receive_response) // enqueue async messages (must be skipped by self->receive_response)
send(self, 42, 1); self->send(self, 42, 1);
// must skip sync message // must skip sync message
receive ( self->receive (
on(42, arg_match) >> [&](int i) { on(42, arg_match) >> [&](int i) {
CPPA_CHECK_EQUAL(i, 1); CPPA_CHECK_EQUAL(i, 1);
} }
); );
// must skip remaining async message // must skip remaining async message
receive_response (handle) ( self->receive_response (handle) (
on_arg_match >> [&](int a, int b) { on_arg_match >> [&](int a, int b) {
CPPA_CHECK_EQUAL(a, 42); CPPA_CHECK_EQUAL(a, 42);
CPPA_CHECK_EQUAL(b, 2); CPPA_CHECK_EQUAL(b, 2);
...@@ -673,28 +633,27 @@ int main() { ...@@ -673,28 +633,27 @@ int main() {
after(chrono::seconds(10)) >> CPPA_UNEXPECTED_TOUT_CB() after(chrono::seconds(10)) >> CPPA_UNEXPECTED_TOUT_CB()
); );
// dequeue remaining async. message // dequeue remaining async. message
receive (on(0, 0) >> CPPA_CHECKPOINT_CB()); self->receive (on(0, 0) >> CPPA_CHECKPOINT_CB());
// make sure there's no other message in our mailbox // make sure there's no other message in our mailbox
receive ( self->receive (
others() >> CPPA_UNEXPECTED_MSG_CB(), others() >> CPPA_UNEXPECTED_MSG_CB(),
after(chrono::seconds(0)) >> [] { } after(chrono::seconds(0)) >> [] { }
); );
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_PRINT("test sync send with factory spawned actor"); CPPA_PRINT("test sync send");
auto sync_testee_factory = factory::event_based(
[&]() { CPPA_CHECKPOINT();
become ( auto sync_testee = spawn<blocking_api>([](blocking_untyped_actor* self) {
on("hi") >> [&]() { self->receive (
auto handle = sync_send(self->last_sender(), "whassup?"); on("hi", arg_match) >> [&](actor from) {
handle_response(handle) ( self->sync_send(from, "whassup?", self).await(
on_arg_match >> [&](const string& str) { on_arg_match >> [&](const string& str) -> string {
CPPA_CHECK(self->last_sender() != nullptr); CPPA_CHECK(self->last_sender() != nullptr);
CPPA_CHECK_EQUAL(str, "nothing"); CPPA_CHECK_EQUAL(str, "nothing");
self->quit(); self->quit();
// TODO: should return the value instead return "goodbye!";
send(self->last_sender(), "goodbye!");
}, },
after(chrono::minutes(1)) >> [] { after(chrono::minutes(1)) >> [] {
cerr << "PANIC!!!!" << endl; cerr << "PANIC!!!!" << endl;
...@@ -704,25 +663,22 @@ int main() { ...@@ -704,25 +663,22 @@ int main() {
}, },
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
} });
);
CPPA_CHECKPOINT();
auto sync_testee = sync_testee_factory.spawn();
self->monitor(sync_testee); self->monitor(sync_testee);
send(sync_testee, "hi"); self->send(sync_testee, "hi", self);
receive ( self->receive (
on("whassup?") >> [&]() -> std::string { on("whassup?", arg_match) >> [&](actor other) -> std::string {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
// this is NOT a reply, it's just an asynchronous message // this is NOT a reply, it's just an asynchronous message
send(self->last_sender(), "a lot!"); self->send(other, "a lot!");
return "nothing"; return "nothing";
} }
); );
receive ( self->receive (
on("goodbye!") >> CPPA_CHECKPOINT_CB(), on("goodbye!") >> CPPA_CHECKPOINT_CB(),
after(std::chrono::seconds(5)) >> CPPA_UNEXPECTED_TOUT_CB() after(std::chrono::seconds(5)) >> CPPA_UNEXPECTED_TOUT_CB()
); );
receive ( self->receive (
on(atom("DOWN"), exit_reason::normal) >> [&] { on(atom("DOWN"), exit_reason::normal) >> [&] {
CPPA_CHECK_EQUAL(self->last_sender(), sync_testee); CPPA_CHECK_EQUAL(self->last_sender(), sync_testee);
} }
...@@ -730,125 +686,83 @@ int main() { ...@@ -730,125 +686,83 @@ int main() {
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
sync_send(sync_testee, "!?").await( self->sync_send(sync_testee, "!?").await(
on(atom("EXITED"), any_vals) >> CPPA_CHECKPOINT_CB(), on(atom("EXITED"), any_vals) >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB(), others() >> CPPA_UNEXPECTED_MSG_CB(),
after(chrono::milliseconds(5)) >> CPPA_UNEXPECTED_TOUT_CB() after(chrono::milliseconds(5)) >> CPPA_UNEXPECTED_TOUT_CB()
); );
auto inflater = factory::event_based( auto inflater = [](untyped_actor* self, const string&, actor buddy) {
[](string*, actor_ptr* receiver) { self->become(
become(
on_arg_match >> [=](int n, const string& s) { on_arg_match >> [=](int n, const string& s) {
send(*receiver, n * 2, s); self->send(buddy, n * 2, s);
}, },
on(atom("done")) >> [] { on(atom("done")) >> [=] {
self->quit(); self->quit();
} }
); );
} };
); auto joe = spawn(inflater, "Joe", self);
auto joe = inflater.spawn("Joe", self); auto bob = spawn(inflater, "Bob", joe);
auto bob = inflater.spawn("Bob", joe); self->send(bob, 1, "hello actor");
send(bob, 1, "hello actor"); self->receive (
receive (
on(4, "hello actor") >> CPPA_CHECKPOINT_CB(), on(4, "hello actor") >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
// kill joe and bob // kill joe and bob
auto poison_pill = make_any_tuple(atom("done")); auto poison_pill = make_any_tuple(atom("done"));
joe << poison_pill; anon_send(joe, poison_pill);
bob << poison_pill; anon_send(bob, poison_pill);
await_all_actors_done(); await_all_actors_done();
function<actor_ptr (const string&, const actor_ptr&)> spawn_next; function<actor (const string&, const actor&)> spawn_next;
auto kr34t0r = factory::event_based( // it's safe to capture spawn_next as reference here, because
// it's safe to pass spawn_next as reference here, because
// - it is guaranteeed to outlive kr34t0r by general scoping rules // - it is guaranteeed to outlive kr34t0r by general scoping rules
// - the lambda is always executed in the current actor's thread // - the lambda is always executed in the current actor's thread
// but using spawn_next in a message handler could // but using spawn_next in a message handler could
// still cause undefined behavior! // still cause undefined behavior!
[&spawn_next](string* name, actor_ptr* pal) { auto kr34t0r = [&spawn_next](untyped_actor* self, const string& name, actor pal) {
if (*name == "Joe" && !*pal) { if (name == "Joe" && !pal) {
*pal = spawn_next("Bob", self); pal = spawn_next("Bob", self);
} }
become ( self->become (
others() >> [pal]() { others() >> [=] {
// forward message and die // forward message and die
*pal << self->last_dequeued(); self->send_tuple(pal, self->last_dequeued());
self->quit(); self->quit();
} }
); );
}
);
spawn_next = [&kr34t0r](const string& name, const actor_ptr& pal) {
return kr34t0r.spawn(name, pal);
}; };
auto joe_the_second = kr34t0r.spawn("Joe"); spawn_next = [&kr34t0r](const string& name, const actor& pal) {
send(joe_the_second, atom("done")); return spawn(kr34t0r, name, pal);
};
auto joe_the_second = spawn(kr34t0r, "Joe", invalid_actor);
self->send(joe_the_second, atom("done"));
await_all_actors_done(); await_all_actors_done();
int zombie_init_called = 0; auto f = [](const string& name) -> behavior {
int zombie_on_exit_called = 0; return (
factory::event_based([&]() { ++zombie_init_called; },
[&]() { ++zombie_on_exit_called; }).spawn();
CPPA_CHECK_EQUAL(zombie_init_called, 1);
CPPA_CHECK_EQUAL(zombie_on_exit_called, 1);
factory::event_based([&](int* i) {
CPPA_CHECK_EQUAL(*i, 42);
++zombie_init_called;
},
[&](int* i) {
CPPA_CHECK_EQUAL(*i, 42);
++zombie_on_exit_called;
})
.spawn(42);
CPPA_CHECK_EQUAL(zombie_init_called, 2);
CPPA_CHECK_EQUAL(zombie_on_exit_called, 2);
factory::event_based([&](int* i) {
CPPA_CHECK_EQUAL(*i, 23);
++zombie_init_called;
},
[&]() {
++zombie_on_exit_called;
})
.spawn(23);
CPPA_CHECK_EQUAL(zombie_init_called, 3);
CPPA_CHECK_EQUAL(zombie_on_exit_called, 3);
auto f = factory::event_based([](string* name) {
become (
on(atom("get_name")) >> [name] { on(atom("get_name")) >> [name] {
return make_cow_tuple(atom("name"), *name); return make_cow_tuple(atom("name"), name);
} }
); );
}); };
auto a1 = f.spawn("alice"); auto a1 = spawn(f, "alice");
auto a2 = f.spawn("bob"); auto a2 = spawn(f, "bob");
send(a1, atom("get_name")); self->send(a1, atom("get_name"));
receive ( self->receive (
on(atom("name"), arg_match) >> [&](const string& name) { on(atom("name"), arg_match) >> [&](const string& name) {
CPPA_CHECK_EQUAL(name, "alice"); CPPA_CHECK_EQUAL(name, "alice");
} }
); );
send(a2, atom("get_name")); self->send(a2, atom("get_name"));
receive ( self->receive (
on(atom("name"), arg_match) >> [&](const string& name) { on(atom("name"), arg_match) >> [&](const string& name) {
CPPA_CHECK_EQUAL(name, "bob"); CPPA_CHECK_EQUAL(name, "bob");
} }
); );
send_exit(a1, exit_reason::user_shutdown); self->send_exit(a1, exit_reason::user_shutdown);
send_exit(a2, exit_reason::user_shutdown); self->send_exit(a2, exit_reason::user_shutdown);
await_all_actors_done();
factory::event_based([](int* i) {
become(
after(chrono::milliseconds(50)) >> [=]() {
if (++(*i) >= 5) self->quit();
}
);
}).spawn();
await_all_actors_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{}));
...@@ -857,25 +771,25 @@ int main() { ...@@ -857,25 +771,25 @@ int main() {
// create some actors linked to one single actor // create some actors linked to one single actor
// and kill them all through killing the link // and kill them all through killing the link
auto legion = spawn([] { auto legion = spawn([](untyped_actor* self) {
CPPA_LOGF_INFO("spawn 1, 000 actors"); CPPA_LOGF_INFO("spawn 1, 000 actors");
for (int i = 0; i < 1000; ++i) { for (int i = 0; i < 1000; ++i) {
spawn<event_testee, linked>(); self->spawn<event_testee, linked>();
} }
become(others() >> CPPA_UNEXPECTED_MSG_CB()); self->become(others() >> CPPA_UNEXPECTED_MSG_CB());
}); });
send_exit(legion, exit_reason::user_shutdown); self->send_exit(legion, exit_reason::user_shutdown);
await_all_actors_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 = self->spawn<monitored+blocking_api>(ping, 10);
auto pong_actor = spawn<monitored+blocking_api>(pong, ping_actor); auto pong_actor = self->spawn<monitored+blocking_api>(pong, ping_actor);
self->link_to(pong_actor); self->link_to(pong_actor);
int i = 0; int i = 0;
int flags = 0; int flags = 0;
delayed_send(self, chrono::seconds(1), atom("FooBar")); self->delayed_send(self, chrono::seconds(1), atom("FooBar"));
// wait for DOWN and EXIT messages of pong // wait for DOWN and EXIT messages of pong
receive_for(i, 4) ( self->receive_for(i, 4) (
on(atom("EXIT"), arg_match) >> [&](uint32_t reason) { on(atom("EXIT"), arg_match) >> [&](uint32_t reason) {
CPPA_CHECK_EQUAL(exit_reason::user_shutdown, reason); CPPA_CHECK_EQUAL(exit_reason::user_shutdown, reason);
CPPA_CHECK(self->last_sender() == pong_actor); CPPA_CHECK(self->last_sender() == pong_actor);
...@@ -915,20 +829,17 @@ int main() { ...@@ -915,20 +829,17 @@ int main() {
spawn<high_priority_testee_class, priority_aware>(); spawn<high_priority_testee_class, priority_aware>();
await_all_actors_done(); await_all_actors_done();
// don't try this at home, kids // don't try this at home, kids
send(self, atom("check")); self->send(self, atom("check"));
try { self->receive (
become (
on(atom("check")) >> [] { on(atom("check")) >> [] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
self->quit();
} }
); );
self->exec_behavior_stack(); }
CPPA_FAILURE("line " << __LINE__ << " should be unreachable");
} int main() {
catch (actor_exited&) { CPPA_TEST(test_spawn);
CPPA_CHECKPOINT(); test_spawn();
}
shutdown(); shutdown();
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
...@@ -7,7 +7,7 @@ using namespace cppa::placeholders; ...@@ -7,7 +7,7 @@ using namespace cppa::placeholders;
struct sync_mirror : sb_actor<sync_mirror> { struct sync_mirror : sb_actor<sync_mirror> {
behavior init_state = ( behavior init_state = (
others() >> [] { return self->last_dequeued(); } others() >> [=] { return last_dequeued(); }
); );
}; };
...@@ -19,13 +19,13 @@ struct float_or_int : sb_actor<float_or_int> { ...@@ -19,13 +19,13 @@ struct float_or_int : sb_actor<float_or_int> {
); );
}; };
struct popular_actor : event_based_actor { // popular actors have a buddy struct popular_actor : untyped_actor { // popular actors have a buddy
actor_ptr m_buddy; actor m_buddy;
popular_actor(const actor_ptr& buddy) : m_buddy(buddy) { } popular_actor(const actor& buddy) : m_buddy(buddy) { }
inline const actor_ptr& buddy() const { return m_buddy; } inline const actor& buddy() const { return m_buddy; }
void report_failure() { void report_failure() {
send(buddy(), atom("failure")); send(buddy(), atom("failure"));
self->quit(); quit();
} }
}; };
...@@ -45,10 +45,10 @@ struct popular_actor : event_based_actor { // popular actors have a buddy ...@@ -45,10 +45,10 @@ struct popular_actor : event_based_actor { // popular actors have a buddy
\******************************************************************************/ \******************************************************************************/
struct A : popular_actor { struct A : popular_actor {
A(const actor_ptr& buddy) : popular_actor(buddy) { } A(const actor& buddy) : popular_actor(buddy) { }
void init() { behavior make_behavior() override {
become ( return (
on(atom("go"), arg_match) >> [=](const actor_ptr& next) { on(atom("go"), arg_match) >> [=](const actor& next) {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
sync_send(next, atom("gogo")).then([=] { sync_send(next, atom("gogo")).then([=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
...@@ -62,9 +62,9 @@ struct A : popular_actor { ...@@ -62,9 +62,9 @@ struct A : popular_actor {
}; };
struct B : popular_actor { struct B : popular_actor {
B(const actor_ptr& buddy) : popular_actor(buddy) { } B(const actor& buddy) : popular_actor(buddy) { }
void init() { behavior make_behavior() override {
become ( return (
others() >> [=] { others() >> [=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
forward_to(buddy()); forward_to(buddy());
...@@ -77,7 +77,7 @@ struct B : popular_actor { ...@@ -77,7 +77,7 @@ struct B : popular_actor {
struct C : sb_actor<C> { struct C : sb_actor<C> {
behavior init_state = ( behavior init_state = (
on(atom("gogo")) >> [=]() -> atom_value { on(atom("gogo")) >> [=]() -> atom_value {
self->quit(); quit();
return atom("gogogo"); return atom("gogogo");
} }
); );
...@@ -100,8 +100,8 @@ struct C : sb_actor<C> { ...@@ -100,8 +100,8 @@ struct C : sb_actor<C> {
\******************************************************************************/ \******************************************************************************/
struct D : popular_actor { struct D : popular_actor {
D(const actor_ptr& buddy) : popular_actor(buddy) { } D(const actor& buddy) : popular_actor(buddy) { }
void init() { behavior make_behavior() override {
become ( become (
others() >> [=] { others() >> [=] {
/* /*
...@@ -136,13 +136,12 @@ struct D : popular_actor { ...@@ -136,13 +136,12 @@ struct D : popular_actor {
* X * * X *
\******************************************************************************/ \******************************************************************************/
struct server : event_based_actor { struct server : untyped_actor {
void init() { behavior make_behavior() override {
auto die = [=] { quit(exit_reason::user_shutdown); }; auto die = [=] { quit(exit_reason::user_shutdown); };
become ( become (
on(atom("idle")) >> [=] { on(atom("idle"), arg_match) >> [=](actor worker) {
auto worker = last_sender();
become ( become (
keep_behavior, keep_behavior,
on(atom("request")) >> [=] { on(atom("request")) >> [=] {
...@@ -160,33 +159,29 @@ struct server : event_based_actor { ...@@ -160,33 +159,29 @@ struct server : event_based_actor {
}; };
void test_sync_send() {
scoped_actor self;
int main() { self->on_sync_failure([&] {
CPPA_TEST(test_sync_send);
self->on_sync_failure([] {
CPPA_FAILURE("received: " << to_string(self->last_dequeued())); CPPA_FAILURE("received: " << to_string(self->last_dequeued()));
}); });
spawn<monitored + blocking_api>([] { self->spawn<monitored + blocking_api>([](blocking_untyped_actor* self) {
CPPA_LOGC_TRACE("NONE", "main$sync_failure_test", "id = " << self->id()); CPPA_LOGC_TRACE("NONE", "main$sync_failure_test", "id = " << self->id());
int invocations = 0; int invocations = 0;
auto foi = spawn<float_or_int, linked>(); auto foi = self->spawn<float_or_int, linked>();
send(foi, atom("i")); self->send(foi, atom("i"));
receive(on_arg_match >> [](int i) { CPPA_CHECK_EQUAL(i, 0); }); self->receive(on_arg_match >> [](int i) { CPPA_CHECK_EQUAL(i, 0); });
self->on_sync_failure([] { self->on_sync_failure([=] {
CPPA_FAILURE("received: " << to_string(self->last_dequeued())); CPPA_FAILURE("received: " << to_string(self->last_dequeued()));
}); });
sync_send(foi, atom("i")).then( self->sync_send(foi, atom("i")).await(
[&](int i) { CPPA_CHECK_EQUAL(i, 0); ++invocations; }, [&](int i) { CPPA_CHECK_EQUAL(i, 0); ++invocations; },
[&](float) { CPPA_UNEXPECTED_MSG(); } [&](float) { CPPA_UNEXPECTED_MSG(); }
) );
.continue_with([&] { self->sync_send(foi, atom("f")).await(
sync_send(foi, atom("f")).then(
[&](int) { CPPA_UNEXPECTED_MSG(); }, [&](int) { CPPA_UNEXPECTED_MSG(); },
[&](float f) { CPPA_CHECK_EQUAL(f, 0); ++invocations; } [&](float f) { CPPA_CHECK_EQUAL(f, 0); ++invocations; }
); );
}); //self->exec_behavior_stack();
self->exec_behavior_stack();
CPPA_CHECK_EQUAL(invocations, 2); CPPA_CHECK_EQUAL(invocations, 2);
CPPA_PRINT("trigger sync failure"); CPPA_PRINT("trigger sync failure");
// provoke invocation of self->handle_sync_failure() // provoke invocation of self->handle_sync_failure()
...@@ -195,7 +190,7 @@ int main() { ...@@ -195,7 +190,7 @@ int main() {
self->on_sync_failure([&] { self->on_sync_failure([&] {
sync_failure_called = true; sync_failure_called = true;
}); });
sync_send(foi, atom("f")).await( self->sync_send(foi, atom("f")).await(
on<int>() >> [&] { on<int>() >> [&] {
int_handler_called = true; int_handler_called = true;
} }
...@@ -204,22 +199,20 @@ int main() { ...@@ -204,22 +199,20 @@ int main() {
CPPA_CHECK_EQUAL(int_handler_called, false); CPPA_CHECK_EQUAL(int_handler_called, false);
self->quit(exit_reason::user_shutdown); self->quit(exit_reason::user_shutdown);
}); });
receive ( self->receive (
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()
); );
auto mirror = spawn<sync_mirror>(); auto mirror = spawn<sync_mirror>();
bool continuation_called = false; bool continuation_called = false;
sync_send(mirror, 42) self->sync_send(mirror, 42)
.then([](int value) { CPPA_CHECK_EQUAL(value, 42); }) .await([](int value) { CPPA_CHECK_EQUAL(value, 42); });
.continue_with([&] { continuation_called = true; });
self->exec_behavior_stack();
CPPA_CHECK_EQUAL(continuation_called, true); CPPA_CHECK_EQUAL(continuation_called, true);
send_exit(mirror, exit_reason::user_shutdown); self->send_exit(mirror, exit_reason::user_shutdown);
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
auto await_success_message = [&] { auto await_success_message = [&] {
receive ( self->receive (
on(atom("success")) >> CPPA_CHECKPOINT_CB(), on(atom("success")) >> CPPA_CHECKPOINT_CB(),
on(atom("failure")) >> CPPA_FAILURE_CB("A didn't receive sync response"), on(atom("failure")) >> CPPA_FAILURE_CB("A didn't receive sync response"),
on(atom("DOWN"), arg_match).when(_x2 != exit_reason::normal) on(atom("DOWN"), arg_match).when(_x2 != exit_reason::normal)
...@@ -228,23 +221,23 @@ int main() { ...@@ -228,23 +221,23 @@ int main() {
} }
); );
}; };
send(spawn<A, monitored>(self), atom("go"), spawn<B>(spawn<C>())); self->send(self->spawn<A, monitored>(self), atom("go"), spawn<B>(spawn<C>()));
await_success_message(); await_success_message();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
await_all_actors_done(); await_all_actors_done();
send(spawn<A, monitored>(self), atom("go"), spawn<D>(spawn<C>())); self->send(self->spawn<A, monitored>(self), atom("go"), spawn<D>(spawn<C>()));
await_success_message(); await_success_message();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
timed_sync_send(self, std::chrono::milliseconds(50), atom("NoWay")).await( self->timed_sync_send(self, std::chrono::milliseconds(50), atom("NoWay")).await(
on(atom("TIMEOUT")) >> CPPA_CHECKPOINT_CB(), on(atom("TIMEOUT")) >> CPPA_CHECKPOINT_CB(),
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
// we should have received two DOWN messages with normal exit reason // we should have received two DOWN messages with normal exit reason
// plus 'NoWay' // plus 'NoWay'
int i = 0; int i = 0;
receive_for(i, 3) ( self->receive_for(i, 3) (
on(atom("DOWN"), exit_reason::normal) >> CPPA_CHECKPOINT_CB(), on(atom("DOWN"), exit_reason::normal) >> CPPA_CHECKPOINT_CB(),
on(atom("NoWay")) >> [] { on(atom("NoWay")) >> [] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
...@@ -256,7 +249,7 @@ int main() { ...@@ -256,7 +249,7 @@ int main() {
); );
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
// mailbox should be empty now // mailbox should be empty now
receive ( self->receive (
others() >> CPPA_UNEXPECTED_MSG_CB(), others() >> CPPA_UNEXPECTED_MSG_CB(),
after(std::chrono::seconds(0)) >> CPPA_CHECKPOINT_CB() after(std::chrono::seconds(0)) >> CPPA_CHECKPOINT_CB()
); );
...@@ -266,28 +259,24 @@ int main() { ...@@ -266,28 +259,24 @@ int main() {
bool timeout_occured = false; bool timeout_occured = false;
self->on_sync_timeout([&] { timeout_occured = true; }); self->on_sync_timeout([&] { timeout_occured = true; });
self->on_sync_failure(CPPA_UNEXPECTED_MSG_CB()); self->on_sync_failure(CPPA_UNEXPECTED_MSG_CB());
timed_sync_send(c, std::chrono::milliseconds(500), atom("HiThere")) self->timed_sync_send(c, std::chrono::milliseconds(500), atom("HiThere"))
.then(CPPA_FAILURE_CB("C replied to 'HiThere'!")) .await(CPPA_FAILURE_CB("C replied to 'HiThere'!"));
.continue_with(CPPA_FAILURE_CB("continuation erroneously invoked"));
self->exec_behavior_stack();
CPPA_CHECK_EQUAL(timeout_occured, true); CPPA_CHECK_EQUAL(timeout_occured, true);
self->on_sync_failure(CPPA_UNEXPECTED_MSG_CB()); self->on_sync_failure(CPPA_UNEXPECTED_MSG_CB());
sync_send(c, atom("gogo")).then(CPPA_CHECKPOINT_CB()) self->sync_send(c, atom("gogo")).await(CPPA_CHECKPOINT_CB());
.continue_with(CPPA_CHECKPOINT_CB()); self->send_exit(c, exit_reason::user_shutdown);
self->exec_behavior_stack();
send_exit(c, exit_reason::user_shutdown);
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
// test use case 3 // test use case 3
spawn<monitored + blocking_api>([] { // client self->spawn<monitored + blocking_api>([](blocking_untyped_actor* self) { // client
auto s = spawn<server, linked>(); // server auto s = self->spawn<server, linked>(); // server
auto w = spawn<linked>([] { // worker auto w = self->spawn<linked>([](untyped_actor* self) { // worker
become(on(atom("request")) >> []{ return atom("response"); }); self->become(on(atom("request")) >> []{ return atom("response"); });
}); });
// first 'idle', then 'request' // first 'idle', then 'request'
send_as(w, s, atom("idle")); send_as(w, s, atom("idle"));
sync_send(s, atom("request")).await( self->sync_send(s, atom("request")).await(
on(atom("response")) >> [=] { on(atom("response")) >> [=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_CHECK_EQUAL(self->last_sender(), w); CPPA_CHECK_EQUAL(self->last_sender(), w);
...@@ -295,23 +284,28 @@ int main() { ...@@ -295,23 +284,28 @@ int main() {
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
// first 'request', then 'idle' // first 'request', then 'idle'
auto handle = sync_send(s, atom("request")); auto handle = self->sync_send(s, atom("request"));
send_as(w, s, atom("idle")); send_as(w, s, atom("idle"));
receive_response(handle) ( self->receive_response(handle) (
on(atom("response")) >> [=] { on(atom("response")) >> [=] {
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
CPPA_CHECK_EQUAL(self->last_sender(), w); CPPA_CHECK_EQUAL(self->last_sender(), w);
}, },
others() >> CPPA_UNEXPECTED_MSG_CB() others() >> CPPA_UNEXPECTED_MSG_CB()
); );
send(s, "Ever danced with the devil in the pale moonlight?"); self->send(s, "Ever danced with the devil in the pale moonlight?");
// response: {'EXIT', exit_reason::user_shutdown} // response: {'EXIT', exit_reason::user_shutdown}
receive_loop(others() >> CPPA_UNEXPECTED_MSG_CB()); self->receive_loop(others() >> CPPA_UNEXPECTED_MSG_CB());
}); });
receive ( self->receive (
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()
); );
}
int main() {
CPPA_TEST(test_sync_send);
test_sync_send();
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
shutdown(); shutdown();
......
...@@ -87,9 +87,9 @@ optional<int> str2int(const std::string& str) { ...@@ -87,9 +87,9 @@ optional<int> str2int(const std::string& str) {
CPPA_FAILURE(#FunName " erroneously invoked"); \ CPPA_FAILURE(#FunName " erroneously invoked"); \
} else { CPPA_CHECKPOINT(); } static_cast<void>(42) } else { CPPA_CHECKPOINT(); } static_cast<void>(42)
struct dummy_receiver : event_based_actor { struct dummy_receiver : untyped_actor {
void init() { behavior make_behavior() override {
become( return (
on_arg_match >> [=](expensive_copy_struct& ecs) -> expensive_copy_struct { on_arg_match >> [=](expensive_copy_struct& ecs) -> expensive_copy_struct {
ecs.value = 42; ecs.value = 42;
quit(); quit();
...@@ -425,8 +425,9 @@ void check_move_ops() { ...@@ -425,8 +425,9 @@ void check_move_ops() {
check_move_optional(); check_move_optional();
CPPA_PRINT(__func__); CPPA_PRINT(__func__);
CPPA_CHECK_EQUAL(s_expensive_copies.load(), 0); CPPA_CHECK_EQUAL(s_expensive_copies.load(), 0);
send(spawn<dummy_receiver>(), expensive_copy_struct()); scoped_actor self;
receive ( self->send(spawn<dummy_receiver>(), expensive_copy_struct());
self->receive (
on_arg_match >> [&](expensive_copy_struct& ecs) { on_arg_match >> [&](expensive_copy_struct& ecs) {
CPPA_CHECK_EQUAL(42, ecs.value); CPPA_CHECK_EQUAL(42, ecs.value);
} }
......
...@@ -41,6 +41,7 @@ bool operator==(const my_request& lhs, const my_request& rhs) { ...@@ -41,6 +41,7 @@ bool operator==(const my_request& lhs, const my_request& rhs) {
return lhs.a == rhs.a && lhs.b == rhs.b; return lhs.a == rhs.a && lhs.b == rhs.b;
} }
/*
typed_actor_ptr<replies_to<my_request>::with<bool>> typed_actor_ptr<replies_to<my_request>::with<bool>>
spawn_typed_server() { spawn_typed_server() {
return spawn_typed( return spawn_typed(
...@@ -63,10 +64,11 @@ class typed_testee : public typed_actor<replies_to<my_request>::with<bool>> { ...@@ -63,10 +64,11 @@ class typed_testee : public typed_actor<replies_to<my_request>::with<bool>> {
} }
}; };
*/
int main() { int main() {
CPPA_TEST(test_typed_spawn); CPPA_TEST(test_typed_spawn);
/*
announce<my_request>(&my_request::a, &my_request::b); announce<my_request>(&my_request::a, &my_request::b);
auto sptr = spawn_typed_server(); auto sptr = spawn_typed_server();
sync_send(sptr, my_request{2, 2}).await( sync_send(sptr, my_request{2, 2}).await(
...@@ -176,5 +178,6 @@ int main() { ...@@ -176,5 +178,6 @@ int main() {
await_all_actors_done(); await_all_actors_done();
CPPA_CHECKPOINT(); CPPA_CHECKPOINT();
shutdown(); shutdown();
*/
return CPPA_TEST_RESULT(); return CPPA_TEST_RESULT();
} }
...@@ -134,7 +134,7 @@ int main() { ...@@ -134,7 +134,7 @@ int main() {
std::string, std::u16string, std::u32string, std::string, std::u16string, std::u32string,
float, double, float, double,
atom_value, any_tuple, message_header, atom_value, any_tuple, message_header,
actor_ptr, group_ptr, actor, group_ptr,
channel, node_id_ptr channel, node_id_ptr
>::arr; >::arr;
...@@ -157,7 +157,7 @@ int main() { ...@@ -157,7 +157,7 @@ int main() {
uniform_typeid<atom_value>(), uniform_typeid<atom_value>(),
uniform_typeid<any_tuple>(), uniform_typeid<any_tuple>(),
uniform_typeid<message_header>(), uniform_typeid<message_header>(),
uniform_typeid<actor_ptr>(), uniform_typeid<actor>(),
uniform_typeid<group_ptr>(), uniform_typeid<group_ptr>(),
uniform_typeid<channel>(), 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