Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[simix] Create actor by passing function and arguments
authorGabriel Corona <gabriel.corona@loria.fr>
Thu, 16 Jun 2016 13:07:13 +0000 (15:07 +0200)
committerGabriel Corona <gabriel.corona@loria.fr>
Fri, 17 Jun 2016 09:00:26 +0000 (11:00 +0200)
examples/s4u/basic/s4u_basic.cpp
examples/s4u/mutex/s4u_mutex.cpp
include/simgrid/s4u/actor.hpp
include/xbt/functional.hpp
include/xbt/utility.hpp [new file with mode: 0644]
tools/cmake/DefinePackages.cmake

index c08cd6d..12156f2 100644 (file)
@@ -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::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;
 }
   e->run();
   return 0;
 }
index 3d0ba54..9e4f482 100644 (file)
@@ -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");
 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;
 }
   e->run();
   return 0;
 }
index aa5877d..629ff2f 100644 (file)
@@ -6,8 +6,16 @@
 #ifndef SIMGRID_S4U_ACTOR_HPP
 #define SIMGRID_S4U_ACTOR_HPP
 
 #ifndef SIMGRID_S4U_ACTOR_HPP
 #define SIMGRID_S4U_ACTOR_HPP
 
+#include <atomic>
+#include <functional>
+#include <future>
+#include <memory>
 #include <stdexcept>
 #include <stdexcept>
+#include <type_traits>
+
 #include <xbt/base.h>
 #include <xbt/base.h>
+#include <xbt/functional.hpp>
+
 #include <simgrid/simix.h>
 #include <simgrid/s4u/forward.hpp>
 
 #include <simgrid/simix.h>
 #include <simgrid/s4u/forward.hpp>
 
@@ -114,9 +122,39 @@ namespace s4u {
  * 
  *  @{
  */
  * 
  *  @{
  */
-   
+
 /** @brief Simulation Agent (see \ref s4u_actor)*/
 XBT_PUBLIC_CLASS Actor {
 /** @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 F, class... Args>
+  class Task {
+  public:
+    Task(F&& code, Args&&... args) :
+      code_(std::forward<F>(code)),
+      args_(std::forward<Args>(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...> args_;
+  };
+  /** Wrap a (possibly non-copyable) single-use task into a `std::function` */
+  template<class F, class... Args>
+  static std::function<void()> wrap_task(F f, Args... args)
+  {
+    std::shared_ptr<Task<F, Args...>> task(
+      new Task<F, Args...>(std::move(f), std::move(args)...));
+    return [=] {
+      (*task)();
+    };
+  }
 public:
   Actor() : pimpl_(nullptr) {}
   Actor(smx_process_t smx_proc) :
 public:
   Actor() : pimpl_(nullptr) {}
   Actor(smx_process_t smx_proc) :
@@ -143,12 +181,29 @@ public:
     swap(*this, actor);
   }
 
     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<void()> code);
   Actor(const char* name, s4u::Host *host, double killTime, std::function<void()> code);
+
   Actor(const char* name, s4u::Host *host, std::function<void()> code)
   Actor(const char* name, s4u::Host *host, std::function<void()> code)
-    : Actor(name, host, -1, std::move(code)) {};
-  template<class C>
-  Actor(const char* name, s4u::Host *host, C code)
-    : Actor(name, host, -1, std::function<void()>(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<class F, class... Args,
+    // This constructor is enabled only if the call code(args...) is valid:
+    typename = typename std::result_of<F(Args...)>::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
 
   /** Retrieves the actor that have the given PID (or NULL if not existing) */
   //static Actor *byPid(int pid); not implemented
index 31f9430..537ba8f 100644 (file)
@@ -15,6 +15,7 @@
 #include <utility>
 
 #include <xbt/sysdep.h>
 #include <utility>
 
 #include <xbt/sysdep.h>
+#include <xbt/utility.hpp>
 
 namespace simgrid {
 namespace xbt {
 
 namespace simgrid {
 namespace xbt {
@@ -117,6 +118,41 @@ std::function<void()> wrapMain(F code, int argc, const char*const* argv)
   return wrapMain(std::move(code), args(argc, argv));
 }
 
   return wrapMain(std::move(code), args(argc, argv));
 }
 
+namespace bits {
+template <class F, class Tuple, std::size_t... I>
+constexpr auto apply(F&& f, Tuple&& t, simgrid::xbt::index_sequence<I...>)
+  -> decltype(std::forward<F>(f)(std::get<I>(std::forward<Tuple>(t))...))
+{
+  return std::forward<F>(f)(std::get<I>(std::forward<Tuple>(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 <class F, class Tuple>
+constexpr auto apply(F&& f, Tuple&& t)
+  -> decltype(simgrid::xbt::bits::apply(
+    std::forward<F>(f),
+    std::forward<Tuple>(t),
+    simgrid::xbt::make_index_sequence<
+      std::tuple_size<typename std::decay<Tuple>::type>::value
+    >()))
+{
+  return simgrid::xbt::bits::apply(
+    std::forward<F>(f),
+    std::forward<Tuple>(t),
+    simgrid::xbt::make_index_sequence<
+      std::tuple_size<typename std::decay<Tuple>::type>::value
+    >());
+}
+
 }
 }
 
 }
 }
 
diff --git a/include/xbt/utility.hpp b/include/xbt/utility.hpp
new file mode 100644 (file)
index 0000000..09d8db4
--- /dev/null
@@ -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 <tuple>
+
+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<std::size_t,1,5,7,9>` represents the sequence `(1,5,7,9)`.
+ *
+ * @code{.cpp}
+ * template<class T, std::size_t... I>
+ * auto extract_tuple(T&& t, integer_sequence<std::size_t, I...>)
+ *   -> decltype(std::make_tuple(std::get<I>(std::forward<T>(t))...))
+ * {
+ *  return std::make_tuple(std::get<I>(std::forward<T>(t))...);
+ * }
+ *
+ * int main()
+ * {
+ *   integer_sequence<std::size_t, 1, 3> 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 T, T... N>
+class integer_sequence {
+  static constexpr std::size_t size()
+  {
+    return std::tuple_size<decltype(std::make_tuple(N...))>::value;
+  }
+};
+
+namespace bits {
+  template<class T, long long N, long long... M>
+  struct make_integer_sequence :
+    public make_integer_sequence<T, N-1, N-1, M...>
+  {};
+  template<class T, long long... M>
+  struct make_integer_sequence<T, 0, M...> {
+    typedef integer_sequence<T, (T) M...> type;
+  };
+}
+
+/** A compile-time sequence of integers of the form `(0,1,2,3,...,N-1)` (from C++14) */
+template<class T, T N>
+using make_integer_sequence = typename simgrid::xbt::bits::make_integer_sequence<T,N>::type;
+
+/** A compile-time sequence of indices (from C++14) */
+template<std::size_t... Ints>
+using index_sequence = integer_sequence<std::size_t, Ints...>;
+
+/** A compile-time sequence of indices of the form `(0,1,2,3,...,N-1)` (from C++14) */
+template<std::size_t N>
+using make_index_sequence = make_integer_sequence<std::size_t, N>;
+
+/** Convert a type parameter pack into a index_sequence (from C++14) */
+template<class... T>
+using index_sequence_for = make_index_sequence<sizeof...(T)>;
+
+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<int,double,float>, make_index_sequence<3> >::value, "seq4");
+
+}
+}
index 2bd4041..760d097 100644 (file)
@@ -699,6 +699,7 @@ set(headers_to_install
   include/xbt/synchro_core.h
   include/xbt/sysdep.h
   include/xbt/system_error.hpp
   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
   include/xbt/virtu.h
   include/xbt/xbt_os_thread.h
   include/xbt/xbt_os_time.h