From f20fe8a11db9e893dbf55a03d4cf6132bdc4c65c Mon Sep 17 00:00:00 2001 From: Gabriel Corona Date: Thu, 16 Jun 2016 15:07:13 +0200 Subject: [PATCH] [simix] Create actor by passing function and arguments --- examples/s4u/basic/s4u_basic.cpp | 2 +- examples/s4u/mutex/s4u_mutex.cpp | 2 +- include/simgrid/s4u/actor.hpp | 65 ++++++++++++++++++++++++-- include/xbt/functional.hpp | 36 ++++++++++++++ include/xbt/utility.hpp | 80 ++++++++++++++++++++++++++++++++ tools/cmake/DefinePackages.cmake | 1 + 6 files changed, 179 insertions(+), 7 deletions(-) create mode 100644 include/xbt/utility.hpp diff --git a/examples/s4u/basic/s4u_basic.cpp b/examples/s4u/basic/s4u_basic.cpp index c08cd6dbb4..12156f2547 100644 --- a/examples/s4u/basic/s4u_basic.cpp +++ b/examples/s4u/basic/s4u_basic.cpp @@ -35,7 +35,7 @@ int main(int argc, char **argv) { simgrid::s4u::Engine *e = new simgrid::s4u::Engine(&argc,argv); e->loadPlatform("../../platforms/two_hosts.xml"); simgrid::s4u::Actor("worker", simgrid::s4u::Host::by_name("Tremblay"), Worker()); - simgrid::s4u::Actor("master", simgrid::s4u::Host::by_name("Jupiter"), 0, Master()); + simgrid::s4u::Actor("master", simgrid::s4u::Host::by_name("Jupiter"), Master()); e->run(); return 0; } diff --git a/examples/s4u/mutex/s4u_mutex.cpp b/examples/s4u/mutex/s4u_mutex.cpp index 3d0ba54f62..9e4f482bcb 100644 --- a/examples/s4u/mutex/s4u_mutex.cpp +++ b/examples/s4u/mutex/s4u_mutex.cpp @@ -86,7 +86,7 @@ public: int main(int argc, char **argv) { simgrid::s4u::Engine *e = new simgrid::s4u::Engine(&argc,argv); e->loadPlatform("../../platforms/two_hosts.xml"); - simgrid::s4u::Actor("main", simgrid::s4u::Host::by_name("Tremblay"), 0, MainActor()); + simgrid::s4u::Actor("main", simgrid::s4u::Host::by_name("Tremblay"), MainActor()); e->run(); return 0; } diff --git a/include/simgrid/s4u/actor.hpp b/include/simgrid/s4u/actor.hpp index aa5877d5d1..629ff2f8cb 100644 --- a/include/simgrid/s4u/actor.hpp +++ b/include/simgrid/s4u/actor.hpp @@ -6,8 +6,16 @@ #ifndef SIMGRID_S4U_ACTOR_HPP #define SIMGRID_S4U_ACTOR_HPP +#include +#include +#include +#include #include +#include + #include +#include + #include #include @@ -114,9 +122,39 @@ namespace s4u { * * @{ */ - + /** @brief Simulation Agent (see \ref s4u_actor)*/ XBT_PUBLIC_CLASS Actor { +private: + /** Wrap a (possibly non-copyable) single-use task into a `std::function` */ + template + class Task { + public: + Task(F&& code, Args&&... args) : + code_(std::forward(code)), + args_(std::forward(args)...) + {} + void operator()() + { + if (done_.test_and_set()) + throw std::logic_error("Actor task already executed"); + simgrid::xbt::apply(std::move(code_), std::move(args_)); + } + private: + std::atomic_flag done_ = ATOMIC_FLAG_INIT; + F code_; + std::tuple args_; + }; + /** Wrap a (possibly non-copyable) single-use task into a `std::function` */ + template + static std::function wrap_task(F f, Args... args) + { + std::shared_ptr> task( + new Task(std::move(f), std::move(args)...)); + return [=] { + (*task)(); + }; + } public: Actor() : pimpl_(nullptr) {} Actor(smx_process_t smx_proc) : @@ -143,12 +181,29 @@ public: swap(*this, actor); } + /** Create an actor using a function + * + * If the actor is restarted, the actor has a fresh copy of the function. + */ Actor(const char* name, s4u::Host *host, double killTime, std::function code); + Actor(const char* name, s4u::Host *host, std::function code) - : Actor(name, host, -1, std::move(code)) {}; - template - Actor(const char* name, s4u::Host *host, C code) - : Actor(name, host, -1, std::function(std::move(code))) {} + : Actor(name, host, -1.0d, std::move(code)) {}; + + /** Create an actor using code + * + * Using this constructor, move-only type can be used. The consequence is + * that we cannot copy the value and restart the process in its initial + * state. In order to use auto-restart, an explicit `function` must be passed + * instead. + */ + template::type + > + Actor(const char* name, s4u::Host *host, F code, Args... args) : + Actor(name, host, wrap_task(std::move(code), std::move(args)...)) + {} /** Retrieves the actor that have the given PID (or NULL if not existing) */ //static Actor *byPid(int pid); not implemented diff --git a/include/xbt/functional.hpp b/include/xbt/functional.hpp index 31f9430ea4..537ba8f9dc 100644 --- a/include/xbt/functional.hpp +++ b/include/xbt/functional.hpp @@ -15,6 +15,7 @@ #include #include +#include namespace simgrid { namespace xbt { @@ -117,6 +118,41 @@ std::function wrapMain(F code, int argc, const char*const* argv) return wrapMain(std::move(code), args(argc, argv)); } +namespace bits { +template +constexpr auto apply(F&& f, Tuple&& t, simgrid::xbt::index_sequence) + -> decltype(std::forward(f)(std::get(std::forward(t))...)) +{ + return std::forward(f)(std::get(std::forward(t))...); +} +} + +/** Call a functional object with the values in the given tuple (from C++17) + * + * @code{.cpp} + * int foo(int a, bool b); + * + * auto args = std::make_tuple(1, false); + * int res = apply(foo, args); + * @encode + **/ +template +constexpr auto apply(F&& f, Tuple&& t) + -> decltype(simgrid::xbt::bits::apply( + std::forward(f), + std::forward(t), + simgrid::xbt::make_index_sequence< + std::tuple_size::type>::value + >())) +{ + return simgrid::xbt::bits::apply( + std::forward(f), + std::forward(t), + simgrid::xbt::make_index_sequence< + std::tuple_size::type>::value + >()); +} + } } diff --git a/include/xbt/utility.hpp b/include/xbt/utility.hpp new file mode 100644 index 0000000000..09d8db40bf --- /dev/null +++ b/include/xbt/utility.hpp @@ -0,0 +1,80 @@ +/* Copyright (c) 2016. The SimGrid Team. + * All rights reserved. */ + +/* This program is free software; you can redistribute it and/or modify it + * under the terms of the license (GNU LGPL) which comes with this package. */ + +#include + +namespace simgrid { +namespace xbt { + +// integer_sequence and friends from C++14 +// We need them to implement `apply` from C++17. + +/** A compile-time sequence of integers (from C++14) + * + * `index_sequence` represents the sequence `(1,5,7,9)`. + * + * @code{.cpp} + * template + * auto extract_tuple(T&& t, integer_sequence) + * -> decltype(std::make_tuple(std::get(std::forward(t))...)) + * { + * return std::make_tuple(std::get(std::forward(t))...); + * } + * + * int main() + * { + * integer_sequence seq; + * auto a = std::make_tuple(1, 2.0, false, 'a'); + * auto b = extract_tuple(a, seq); + * std::cout << std::get<0>(b) << '\n'; // 2 + * std::cout << std::get<1>(b) << '\n'; // a + * return 0; + * } + * @endcode + */ +template +class integer_sequence { + static constexpr std::size_t size() + { + return std::tuple_size::value; + } +}; + +namespace bits { + template + struct make_integer_sequence : + public make_integer_sequence + {}; + template + struct make_integer_sequence { + typedef integer_sequence type; + }; +} + +/** A compile-time sequence of integers of the form `(0,1,2,3,...,N-1)` (from C++14) */ +template +using make_integer_sequence = typename simgrid::xbt::bits::make_integer_sequence::type; + +/** A compile-time sequence of indices (from C++14) */ +template +using index_sequence = integer_sequence; + +/** A compile-time sequence of indices of the form `(0,1,2,3,...,N-1)` (from C++14) */ +template +using make_index_sequence = make_integer_sequence; + +/** Convert a type parameter pack into a index_sequence (from C++14) */ +template +using index_sequence_for = make_index_sequence; + +static_assert(std::is_same< make_index_sequence<0>, index_sequence<> >::value, "seq0"); +static_assert(std::is_same< make_index_sequence<1>, index_sequence<0> >::value, "seq1"); +static_assert(std::is_same< make_index_sequence<2>, index_sequence<0, 1> >::value, "seq2"); +static_assert(std::is_same< make_index_sequence<3>, index_sequence<0, 1, 2> >::value, "seq3"); +static_assert(std::is_same< index_sequence_for, make_index_sequence<3> >::value, "seq4"); + +} +} diff --git a/tools/cmake/DefinePackages.cmake b/tools/cmake/DefinePackages.cmake index 2bd4041d86..760d097e75 100644 --- a/tools/cmake/DefinePackages.cmake +++ b/tools/cmake/DefinePackages.cmake @@ -699,6 +699,7 @@ set(headers_to_install include/xbt/synchro_core.h include/xbt/sysdep.h include/xbt/system_error.hpp + include/xbt/utility.hpp include/xbt/virtu.h include/xbt/xbt_os_thread.h include/xbt/xbt_os_time.h -- 2.20.1