Commit d90fc078 authored by Dominik Charousset's avatar Dominik Charousset

event-based actor factory

parent 85a4fc8d
...@@ -27,6 +27,7 @@ set(LIBCPPA_SRC ...@@ -27,6 +27,7 @@ set(LIBCPPA_SRC
src/empty_tuple.cpp src/empty_tuple.cpp
src/event_based_actor.cpp src/event_based_actor.cpp
src/exception.cpp src/exception.cpp
src/factory.cpp
src/fiber.cpp src/fiber.cpp
src/group.cpp src/group.cpp
src/group_manager.cpp src/group_manager.cpp
......
...@@ -262,3 +262,6 @@ cppa/detail/receive_policy.hpp ...@@ -262,3 +262,6 @@ cppa/detail/receive_policy.hpp
cppa/detail/behavior_stack.hpp cppa/detail/behavior_stack.hpp
src/behavior_stack.cpp src/behavior_stack.cpp
cppa/detail/stacked_actor_mixin.hpp cppa/detail/stacked_actor_mixin.hpp
cppa/detail/event_based_actor_factory.hpp
cppa/factory.hpp
src/factory.cpp
...@@ -40,18 +40,19 @@ ...@@ -40,18 +40,19 @@
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/atom.hpp" #include "cppa/atom.hpp"
#include "cppa/self.hpp" #include "cppa/self.hpp"
#include "cppa/cow_tuple.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/channel.hpp" #include "cppa/channel.hpp"
#include "cppa/receive.hpp" #include "cppa/receive.hpp"
#include "cppa/factory.hpp"
#include "cppa/behavior.hpp" #include "cppa/behavior.hpp"
#include "cppa/announce.hpp" #include "cppa/announce.hpp"
#include "cppa/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"
#include "cppa/fsm_actor.hpp" #include "cppa/fsm_actor.hpp"
#include "cppa/local_actor.hpp" #include "cppa/cow_tuple.hpp"
#include "cppa/exit_reason.hpp" #include "cppa/exit_reason.hpp"
#include "cppa/local_actor.hpp"
#include "cppa/scheduled_actor.hpp" #include "cppa/scheduled_actor.hpp"
#include "cppa/scheduling_hint.hpp" #include "cppa/scheduling_hint.hpp"
#include "cppa/event_based_actor.hpp" #include "cppa/event_based_actor.hpp"
...@@ -123,17 +124,24 @@ ...@@ -123,17 +124,24 @@
* features. * features.
* *
* @namespace cppa * @namespace cppa
* @brief This is the root namespace of libcppa. * @brief Root namespace of libcppa.
*
* Thie @b cppa namespace contains all functions and classes to
* implement Actor based applications.
* *
* @namespace cppa::util * @namespace cppa::util
* @brief This namespace contains utility classes and metaprogramming * @brief Contains utility classes and metaprogramming
* utilities used by the libcppa implementation. * utilities used by the libcppa implementation.
* *
* @namespace cppa::intrusive * @namespace cppa::intrusive
* @brief This namespace contains intrusive container implementations. * @brief Contains intrusive container implementations.
*
* @namespace cppa::factory
* @brief Contains factory functions to create actors from lambdas or
* other functors.
*
* @namespace cppa::exit_reason
* @brief Contains all predefined exit reasons.
*
* @namespace cppa::placeholders
* @brief Contains the guard placeholders @p _x1 to @p _x9.
* *
* @defgroup CopyOnWrite Copy-on-write optimization. * @defgroup CopyOnWrite Copy-on-write optimization.
* @p libcppa uses a copy-on-write optimization for its message * @p libcppa uses a copy-on-write optimization for its message
...@@ -246,16 +254,13 @@ ...@@ -246,16 +254,13 @@
* to define patterns: * to define patterns:
* *
* @code * @code
* receive * receive (
* ( * on(atom("hello"), val<std::string>()) >> [](const std::string& msg) {
* on(atom("hello"), val<std::string>()) >> [](const std::string& msg)
* {
* cout << "received hello message: " << msg << endl; * cout << "received hello message: " << msg << endl;
* }, * },
* on(atom("compute"), val<int>(), val<int>(), val<int>()>() >> [](int i0, int i1, int i2) * on(atom("compute"), val<int>(), val<int>()>() >> [](int i0, int i1) {
* {
* // send our result back to the sender of this messages * // send our result back to the sender of this messages
* reply(atom("result"), i0 + i1 + i2); * reply(atom("result"), i0 + i1);
* } * }
* ); * );
* @endcode * @endcode
...@@ -270,16 +275,12 @@ ...@@ -270,16 +275,12 @@
* *
* Example actor: * Example actor:
* @code * @code
* void math_actor() * void math_actor() {
* { * receive_loop (
* receive_loop * on<atom("plus"), int, int>() >> [](int a, int b) {
* (
* on<atom("plus"), int, int>() >> [](int a, int b)
* {
* reply(atom("result"), a + b); * reply(atom("result"), a + b);
* }, * },
* on<atom("minus"), int, int>() >> [](int a, int b) * on<atom("minus"), int, int>() >> [](int a, int b) {
* {
* reply(atom("result"), a - b); * reply(atom("result"), a - b);
* } * }
* ); * );
...@@ -307,10 +308,8 @@ ...@@ -307,10 +308,8 @@
* @code * @code
* // receive two integers * // receive two integers
* vector<int> received_values; * vector<int> received_values;
* receive_while([&]() { return received_values.size() < 2; }) * receive_while([&]() { return received_values.size() < 2; }) (
* ( * on<int>() >> [](int value) {
* on<int>() >> [](int value)
* {
* received_values.push_back(value); * received_values.push_back(value);
* } * }
* ); * );
...@@ -322,8 +321,7 @@ ...@@ -322,8 +321,7 @@
* @code * @code
* std::vector<int> vec {1, 2, 3, 4}; * std::vector<int> vec {1, 2, 3, 4};
* auto i = vec.begin(); * auto i = vec.begin();
* receive_for(i, vec.end()) * receive_for(i, vec.end()) (
* (
* on(atom("get")) >> [&]() { reply(atom("result"), *i); } * on(atom("get")) >> [&]() { reply(atom("result"), *i); }
* ); * );
* @endcode * @endcode
...@@ -335,10 +333,8 @@ ...@@ -335,10 +333,8 @@
* @code * @code
* // receive ints until zero was received * // receive ints until zero was received
* vector<int> received_values; * vector<int> received_values;
* do_receive * do_receive (
* ( * on<int>() >> [](int value) {
* on<int>() >> [](int value)
* {
* received_values.push_back(value); * received_values.push_back(value);
* } * }
* ) * )
...@@ -354,11 +350,9 @@ ...@@ -354,11 +350,9 @@
* *
* @code * @code
* delayed_send(self, std::chrono::seconds(1), atom("poll")); * delayed_send(self, std::chrono::seconds(1), atom("poll"));
* receive_loop * receive_loop (
* (
* // ... * // ...
* on<atom("poll")>() >> []() * on<atom("poll")>() >> []() {
* {
* // ... poll something ... * // ... poll something ...
* // and do it again after 1sec * // and do it again after 1sec
* delayed_send(self, std::chrono::seconds(1), atom("poll")); * delayed_send(self, std::chrono::seconds(1), atom("poll"));
...@@ -392,8 +386,7 @@ ...@@ -392,8 +386,7 @@
* // x has the type cppa::tuple<std::string, std::string> * // x has the type cppa::tuple<std::string, std::string>
* auto x = make_cow_tuple("hello", "tuple"); * auto x = make_cow_tuple("hello", "tuple");
* *
* receive * receive (
* (
* // equal to: on(std::string("hello actor!")) * // equal to: on(std::string("hello actor!"))
* on("hello actor!") >> []() { } * on("hello actor!") >> []() { }
* ); * );
...@@ -486,7 +479,9 @@ struct spawn_fwd_<self_type> { ...@@ -486,7 +479,9 @@ struct spawn_fwd_<self_type> {
*/ */
template<scheduling_hint Hint, typename F, typename Arg0, typename... Args> template<scheduling_hint Hint, typename F, typename Arg0, typename... Args>
inline actor_ptr spawn(F bhvr, Arg0&& arg0, Args&&... args) { inline actor_ptr spawn(F bhvr, Arg0&& arg0, Args&&... args) {
return spawn<Hint>(std::bind(std::move(bhvr), return spawn<Hint>(
std::bind(
std::move(bhvr),
spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0), spawn_fwd_<typename util::rm_ref<Arg0>::type>::_(arg0),
spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...)); spawn_fwd_<typename util::rm_ref<Args>::type>::_(args)...));
} }
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* 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 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_EVENT_BASED_ACTOR_FACTORY_HPP
#define CPPA_EVENT_BASED_ACTOR_FACTORY_HPP
#include <type_traits>
#include "cppa/scheduler.hpp"
#include "cppa/event_based_actor.hpp"
#include "cppa/detail/tdata.hpp"
#include "cppa/util/type_list.hpp"
namespace cppa { namespace detail {
template<typename InitFun, typename CleanupFun, typename... Members>
class event_based_actor_impl : public event_based_actor {
public:
template<typename... Args>
event_based_actor_impl(InitFun fun, CleanupFun cfun, Args&&... args)
: m_init(std::move(fun)), m_on_exit(std::move(cfun))
, m_members(std::forward<Args>(args)...) { }
void init() { apply(m_init); }
void on_exit() {
typedef typename util::get_arg_types<CleanupFun>::types arg_types;
std::integral_constant<size_t, arg_types::size> token;
on_exit_impl(m_on_exit, token);
}
private:
InitFun m_init;
CleanupFun m_on_exit;
tdata<Members...> m_members;
template<typename F>
void apply(F& f, typename std::add_pointer<Members>::type... args) {
f(args...);
}
template<typename F, typename... Args>
void apply(F& f, Args... args) {
apply(f, args..., &get_ref<sizeof...(Args)>(m_members));
}
typedef std::integral_constant<size_t, 0> zero_t;
template<typename OnExit, typename Token>
typename std::enable_if<std::is_same<Token, zero_t>::value>::type
on_exit_impl(OnExit& fun, Token) {
fun();
}
template<typename OnExit, typename Token>
typename std::enable_if<std::is_same<Token, zero_t>::value == false>::type
on_exit_impl(OnExit& fun, Token) {
apply(fun);
}
};
template<typename InitFun, typename CleanupFun, typename... Members>
class event_based_actor_factory {
public:
typedef event_based_actor_impl<InitFun, CleanupFun, Members...> impl;
event_based_actor_factory(InitFun fun, CleanupFun cfun)
: m_init(std::move(fun)), m_on_exit(std::move(cfun)) { }
template<typename... Args>
actor_ptr spawn(Args&&... args) {
return get_scheduler()->spawn(new impl(m_init, m_on_exit,
std::forward<Args>(args)...));
}
private:
InitFun m_init;
CleanupFun m_on_exit;
};
// event-based actor factory from type list
template<typename InitFun, typename CleanupFun, class TypeList>
struct ebaf_from_type_list;
template<typename InitFun, typename CleanupFun, typename... Ts>
struct ebaf_from_type_list<InitFun, CleanupFun, util::type_list<Ts...> > {
typedef event_based_actor_factory<InitFun, CleanupFun, Ts...> type;
};
template<typename Init, typename Cleanup>
struct ebaf_from_functor {
typedef typename util::get_arg_types<Init>::types arg_types;
typedef typename util::get_arg_types<Cleanup>::types arg_types2;
static_assert(util::tl_forall<arg_types, std::is_pointer>::value,
"First functor takes non-pointer arguments");
static_assert( std::is_same<arg_types, arg_types2>::value
|| std::is_same<util::type_list<>, arg_types2>::value,
"Second functor must provide either the same signature "
" as the first one or must take zero arguments");
typedef typename util::tl_map<arg_types, std::remove_pointer>::type mems;
typedef typename ebaf_from_type_list<Init, Cleanup, mems>::type type;
};
} } // namespace cppa::detail
#endif // CPPA_EVENT_BASED_ACTOR_FACTORY_HPP
...@@ -48,6 +48,7 @@ struct scheduled_actor_dummy : abstract_scheduled_actor { ...@@ -48,6 +48,7 @@ struct scheduled_actor_dummy : abstract_scheduled_actor {
bool attach(attachable*); bool attach(attachable*);
void unbecome(); void unbecome();
void do_become(behavior*, bool, bool); void do_become(behavior*, bool, bool);
bool has_behavior();
}; };
} } // namespace cppa::detail } } // namespace cppa::detail
......
...@@ -92,6 +92,12 @@ class stacked_actor_mixin : public Base { ...@@ -92,6 +92,12 @@ class stacked_actor_mixin : public Base {
} }
} }
virtual bool has_behavior() {
return static_cast<bool>(m_behavior)
|| ( static_cast<bool>(m_bhvr_stack_ptr)
&& m_bhvr_stack_ptr->empty() == false);
}
private: private:
std::function<void()> m_behavior; std::function<void()> m_behavior;
......
...@@ -67,8 +67,7 @@ class thread_pool_scheduler : public scheduler { ...@@ -67,8 +67,7 @@ class thread_pool_scheduler : public scheduler {
scheduled_actor_dummy m_dummy; scheduled_actor_dummy m_dummy;
std::thread m_supervisor; std::thread m_supervisor;
actor_ptr spawn_impl(scheduled_actor* what, actor_ptr spawn_impl(scheduled_actor_ptr what, bool push_to_queue = true);
bool push_to_queue = true);
static void worker_loop(worker*); static void worker_loop(worker*);
static void supervisor_loop(job_queue*, scheduled_actor*); static void supervisor_loop(job_queue*, scheduled_actor*);
......
...@@ -86,6 +86,10 @@ class event_based_actor : public detail::abstract_scheduled_actor { ...@@ -86,6 +86,10 @@ class event_based_actor : public detail::abstract_scheduled_actor {
event_based_actor(); event_based_actor();
bool has_behavior() {
return m_bhvr_stack.empty() == false;
}
// provoke compiler errors for usage of receive() and related functions // provoke compiler errors for usage of receive() and related functions
/** /**
......
...@@ -33,11 +33,6 @@ ...@@ -33,11 +33,6 @@
#include <cstdint> #include <cstdint>
/**
* @namespace cppa::exit_reason
* @brief This naemspace contains all predefined exit reasons.
*/
namespace cppa { namespace exit_reason { namespace cppa { namespace exit_reason {
/** /**
......
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* 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 3 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_FACTORY_HPP
#define CPPA_FACTORY_HPP
#include "cppa/detail/event_based_actor_factory.hpp"
namespace cppa { namespace factory {
#ifdef CPPA_DOCUMENTATION
/**
* @brief Returns a factory for event-based actors using @p fun as
* implementation for {@link cppa::event_based_actor::init() init()}.
*
* @p fun must take pointer arguments only. The factory creates an event-based
* actor implementation with member variables according to the functor's
* signature, as shown in the example below.
*
* @code
* auto f = factory::event_based([](int* a, int* b) { ... });
* auto actor1 = f.spawn();
* auto actor2 = f.spawn(1);
* auto actor3 = f.spawn(1, 2);
* @endcode
*
* The arguments @p a and @p b will point to @p int member variables of the
* actor. All member variables are initialized using the default constructor
* unless an initial value is passed to @p spawn.
*/
template<typename InitFun>
auto event_based(InitFun fun);
/**
* @brief Returns a factory for event-based actors using @p fun0 as
* implementation for {@link cppa::event_based_actor::init() init()}
* and @p fun1 as implementation for
* {@link cppa::event_based_actor::on_exit() on_exit()}.
*/
template<typename InitFun, OnExitFun>
auto event_based(InitFun fun0, OnExitFun fun1);
#else // CPPA_DOCUMENTATION
void default_cleanup();
template<typename InitFun>
inline typename detail::ebaf_from_functor<InitFun, void (*)()>::type
event_based(InitFun init) {
return {std::move(init), default_cleanup};
}
template<typename InitFun, typename OnExitFun>
inline typename detail::ebaf_from_functor<InitFun, OnExitFun>::type
event_based(InitFun init, OnExitFun on_exit) {
return {std::move(init), on_exit};
}
#endif // CPPA_DOCUMENTATION
} } // namespace cppa::factory
#endif // CPPA_FACTORY_HPP
...@@ -726,7 +726,12 @@ struct mutable_gref_wrapped<T&> { ...@@ -726,7 +726,12 @@ struct mutable_gref_wrapped<T&> {
// finally ... // finally ...
namespace placeholders { namespace { namespace placeholders {
// doxygen cannot handle anonymous namespaces
#ifndef CPPA_DOCUMENTATION
namespace {
#endif // CPPA_DOCUMENTATION
constexpr guard_placeholder<0> _x1; constexpr guard_placeholder<0> _x1;
constexpr guard_placeholder<1> _x2; constexpr guard_placeholder<1> _x2;
...@@ -738,7 +743,12 @@ constexpr guard_placeholder<6> _x7; ...@@ -738,7 +743,12 @@ constexpr guard_placeholder<6> _x7;
constexpr guard_placeholder<7> _x8; constexpr guard_placeholder<7> _x8;
constexpr guard_placeholder<8> _x9; constexpr guard_placeholder<8> _x9;
} } // namespace placeholders::<anonymous> // doxygen cannot handle anonymous namespaces
#ifndef CPPA_DOCUMENTATION
} // namespace <anonymous>
#endif // CPPA_DOCUMENTATION
} // namespace placeholders
} // namespace cppa } // namespace cppa
......
...@@ -63,6 +63,8 @@ class scheduled_actor : public local_actor { ...@@ -63,6 +63,8 @@ class scheduled_actor : public local_actor {
scheduled_actor* attach_to_scheduler(scheduler* sched); scheduled_actor* attach_to_scheduler(scheduler* sched);
virtual bool has_behavior() = 0;
protected: protected:
scheduler* m_scheduler; scheduler* m_scheduler;
...@@ -71,6 +73,8 @@ class scheduled_actor : public local_actor { ...@@ -71,6 +73,8 @@ class scheduled_actor : public local_actor {
}; };
typedef intrusive_ptr<scheduled_actor> scheduled_actor_ptr;
} // namespace cppa } // namespace cppa
#endif // CPPA_ACTOR_BEHAVIOR_HPP #endif // CPPA_ACTOR_BEHAVIOR_HPP
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* 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 3 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/factory.hpp"
namespace cppa { namespace factory {
void default_cleanup() { }
} } // namespace cppa::factory
...@@ -54,6 +54,6 @@ void scheduled_actor_dummy::detach(const attachable::token&) { } ...@@ -54,6 +54,6 @@ void scheduled_actor_dummy::detach(const attachable::token&) { }
bool scheduled_actor_dummy::attach(attachable*) { return false; } bool scheduled_actor_dummy::attach(attachable*) { return false; }
void scheduled_actor_dummy::unbecome() { } void scheduled_actor_dummy::unbecome() { }
void scheduled_actor_dummy::do_become(behavior*, bool, bool) { } void scheduled_actor_dummy::do_become(behavior*, bool, bool) { }
bool scheduled_actor_dummy::has_behavior() { return false; }
} } // namespace cppa::detail } } // namespace cppa::detail
...@@ -195,30 +195,36 @@ void thread_pool_scheduler::enqueue(scheduled_actor* what) { ...@@ -195,30 +195,36 @@ void thread_pool_scheduler::enqueue(scheduled_actor* what) {
m_queue.push_back(what); m_queue.push_back(what);
} }
actor_ptr thread_pool_scheduler::spawn_impl(scheduled_actor* what, actor_ptr thread_pool_scheduler::spawn_impl(scheduled_actor_ptr what,
bool push_to_queue) { bool push_to_queue) {
if (what->has_behavior()) {
inc_actor_count(); inc_actor_count();
std::atomic_thread_fence(std::memory_order_seq_cst); what->ref();
intrusive_ptr<scheduled_actor> ctx(what); if (push_to_queue) m_queue.push_back(what.get());
ctx->ref(); }
if (push_to_queue) m_queue.push_back(ctx.get()); else {
return std::move(ctx); what->on_exit();
}
return std::move(what);
} }
actor_ptr thread_pool_scheduler::spawn(scheduled_actor* what) { actor_ptr thread_pool_scheduler::spawn(scheduled_actor* ptr) {
// do NOT push event-based actors to the queue on startup // do NOT push event-based actors to the queue on startup
return spawn_impl(what->attach_to_scheduler(this), false); scheduled_actor_ptr what{ptr};
what->attach_to_scheduler(this);
return spawn_impl(std::move(what), false);
} }
#ifndef CPPA_DISABLE_CONTEXT_SWITCHING #ifndef CPPA_DISABLE_CONTEXT_SWITCHING
actor_ptr thread_pool_scheduler::spawn(std::function<void()> what, actor_ptr thread_pool_scheduler::spawn(std::function<void()> bhvr,
scheduling_hint hint) { scheduling_hint hint) {
if (hint == scheduled) { if (hint == scheduled) {
auto new_actor = new context_switching_actor(std::move(what)); scheduled_actor_ptr ptr{new context_switching_actor(std::move(bhvr))};
return spawn_impl(new_actor->attach_to_scheduler(this)); ptr->attach_to_scheduler(this);
return spawn_impl(std::move(ptr));
} }
else { else {
return mock_scheduler::spawn_impl(std::move(what)); return mock_scheduler::spawn_impl(std::move(bhvr));
} }
} }
#else #else
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/cppa.hpp" #include "cppa/cppa.hpp"
#include "cppa/actor.hpp" #include "cppa/actor.hpp"
#include "cppa/factory.hpp"
#include "cppa/scheduler.hpp" #include "cppa/scheduler.hpp"
#include "cppa/fsm_actor.hpp" #include "cppa/fsm_actor.hpp"
#include "cppa/to_string.hpp" #include "cppa/to_string.hpp"
...@@ -301,118 +302,6 @@ std::string behavior_test(actor_ptr et) { ...@@ -301,118 +302,6 @@ std::string behavior_test(actor_ptr et) {
return result; return result;
} }
template<class MatchExpr>
class actor_template {
MatchExpr m_expr;
public:
actor_template(MatchExpr me) : m_expr(std::move(me)) { }
actor_ptr spawn() const {
struct impl : fsm_actor<impl> {
behavior init_state;
impl(const MatchExpr& mx) : init_state(mx.as_partial_function()) {
}
};
return cppa::spawn(new impl{m_expr});
}
};
template<typename... Args>
auto actor_prototype(const Args&... args) -> actor_template<decltype(mexpr_concat(args...))> {
return {mexpr_concat(args...)};
}
template<typename InitFun, typename CleanupFun, typename... Members>
class simple_event_based_actor_impl : public event_based_actor {
public:
template<typename... Args>
simple_event_based_actor_impl(InitFun fun, CleanupFun cfun, Args&&... args)
: m_init(std::move(fun)), m_cleanup(std::move(cfun))
, m_members(std::forward<Args>(args)...) { }
void init() { apply(m_init); }
void on_exit() { m_cleanup(); }
private:
InitFun m_init;
CleanupFun m_cleanup;
detail::tdata<Members...> m_members;
template<typename F>
void apply(F& f, typename std::add_pointer<Members>::type... args) {
f(args...);
}
template<typename F, typename... Args>
void apply(F& f, Args... args) {
apply(f, args..., &get_ref<sizeof...(Args)>(m_members));
}
};
template<typename InitFun, typename CleanupFun, typename... Members>
class simple_event_based_actor_factory {
public:
typedef simple_event_based_actor_impl<InitFun, CleanupFun, Members...> impl;
simple_event_based_actor_factory(InitFun fun, CleanupFun cfun)
: m_init(std::move(fun)), m_cleanup(std::move(cfun)) { }
template<typename... Args>
actor_ptr spawn(Args&&... args) {
return cppa::spawn(new impl(m_init, m_cleanup, std::forward<Args>(args)...));
}
private:
InitFun m_init;
CleanupFun m_cleanup;
};
template<typename InitFun, typename CleanupFun, class TypeList>
struct actor_tpl_from_type_list;
template<typename InitFun, typename CleanupFun, typename... Ts>
struct actor_tpl_from_type_list<InitFun, CleanupFun, util::type_list<Ts...> > {
typedef simple_event_based_actor_factory<InitFun, CleanupFun, Ts...> type;
};
template<typename Init, typename Cleanup>
struct actor_tpl_from_fun {
typedef typename util::get_arg_types<Init>::types arg_types;
typedef typename util::get_arg_types<Cleanup>::types arg_types2;
static_assert(util::tl_forall<arg_types, std::is_pointer>::value,
"First functor takes non-pointer arguments");
static_assert( std::is_same<arg_types, arg_types2>::value
|| std::is_same<util::type_list<>, arg_types2>::value,
"Second functor must provide either the same signature "
" as the first one or take zero arguments");
typedef typename util::tl_map<arg_types, std::remove_pointer>::type mems;
typedef typename actor_tpl_from_type_list<Init, Cleanup, mems>::type type;
};
void dummy_function() { }
struct factory {
template<typename Fun>
static inline typename actor_tpl_from_fun<Fun, void (*)()>::type event_based(Fun fun) {
return {std::move(fun), dummy_function};
}
};
size_t test__spawn() { size_t test__spawn() {
using std::string; using std::string;
CPPA_TEST(test__spawn); CPPA_TEST(test__spawn);
...@@ -449,29 +338,6 @@ size_t test__spawn() { ...@@ -449,29 +338,6 @@ size_t test__spawn() {
send(mirror, atom("EXIT"), exit_reason::user_defined); send(mirror, atom("EXIT"), exit_reason::user_defined);
CPPA_IF_VERBOSE(cout << "ok" << endl); CPPA_IF_VERBOSE(cout << "ok" << endl);
auto svec = std::make_shared<std::vector<string> >();
auto avec = actor_prototype (
on(atom("push_back"), arg_match) >> [svec](const string& str) {
svec->push_back(str);
},
on(atom("get")) >> [svec]() {
reply(*svec);
}
).spawn();
send(avec, atom("push_back"), "hello");
send(avec, atom("push_back"), " world");
send(avec, atom("get"));
send(avec, atom("EXIT"), exit_reason::user_defined);
receive (
on_arg_match >> [&](const std::vector<string>& vec) {
if (vec.size() == 2)
{
CPPA_CHECK_EQUAL("hello world", vec.front() + vec.back());
}
}
);
CPPA_IF_VERBOSE(cout << "test delayed_send() ... " << std::flush); CPPA_IF_VERBOSE(cout << "test delayed_send() ... " << std::flush);
delayed_send(self, std::chrono::seconds(1), 1, 2, 3); delayed_send(self, std::chrono::seconds(1), 1, 2, 3);
receive(on(1, 2, 3) >> []() { }); receive(on(1, 2, 3) >> []() { });
...@@ -535,6 +401,39 @@ size_t test__spawn() { ...@@ -535,6 +401,39 @@ size_t test__spawn() {
await_all_others_done(); await_all_others_done();
CPPA_IF_VERBOSE(cout << "ok" << endl); CPPA_IF_VERBOSE(cout << "ok" << endl);
int zombie_init_called = 0;
int zombie_on_exit_called = 0;
factory::event_based([&]() {
++zombie_init_called;
},
[&]() {
++zombie_on_exit_called;
})
.spawn();
CPPA_CHECK_EQUAL(1, zombie_init_called);
CPPA_CHECK_EQUAL(1, zombie_on_exit_called);
factory::event_based([&](int* i) {
CPPA_CHECK_EQUAL(42, *i);
++zombie_init_called;
},
[&](int* i) {
CPPA_CHECK_EQUAL(42, *i);
++zombie_on_exit_called;
})
.spawn(42);
CPPA_CHECK_EQUAL(2, zombie_init_called);
CPPA_CHECK_EQUAL(2, zombie_on_exit_called);
factory::event_based([&](int* i) {
CPPA_CHECK_EQUAL(23, *i);
++zombie_init_called;
},
[&]() {
++zombie_on_exit_called;
})
.spawn(23);
CPPA_CHECK_EQUAL(3, zombie_init_called);
CPPA_CHECK_EQUAL(3, zombie_on_exit_called);
CPPA_CHECK_EQUAL(behavior_test<testee_actor>(spawn(testee_actor{})), "wait4int"); CPPA_CHECK_EQUAL(behavior_test<testee_actor>(spawn(testee_actor{})), "wait4int");
CPPA_CHECK_EQUAL(behavior_test<event_testee>(spawn(new event_testee)), "wait4int"); CPPA_CHECK_EQUAL(behavior_test<event_testee>(spawn(new event_testee)), "wait4int");
......
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