Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
3d3e660d28fa2a4172cb1ec80f773b2656fd2f70
[simgrid.git] / include / simgrid / simix.hpp
1 /* Copyright (c) 2007-2010, 2012-2015. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #ifndef SIMGRID_SIMIX_HPP
8 #define SIMGRID_SIMIX_HPP
9
10 #include <cstddef>
11
12 #include <string>
13 #include <utility>
14 #include <memory>
15 #include <functional>
16 #include <future>
17 #include <type_traits>
18
19 #include <xbt/function_types.h>
20 #include <simgrid/simix.h>
21
22 XBT_PUBLIC(void) simcall_run_kernel(std::function<void()> const& code);
23
24 namespace simgrid {
25 namespace simix {
26
27 /** Fulfill a promise by executing a given code */
28 template<class R, class F>
29 void fulfill_promise(std::promise<R>& promise, F&& code)
30 {
31   try {
32     promise.set_value(std::forward<F>(code)());
33   }
34   catch(...) {
35     promise.set_exception(std::current_exception());
36   }
37 }
38
39 /** Fulfill a promise by executing a given code
40  *
41  *  This is a special version for `std::promise<void>` because the default
42  *  version does not compile in this case.
43  */
44 template<class F>
45 void fulfill_promise(std::promise<void>& promise, F&& code)
46 {
47   try {
48     std::forward<F>(code)();
49     promise.set_value();
50   }
51   catch(...) {
52     promise.set_exception(std::current_exception());
53   }
54 }
55
56 /** Execute some code in the kernel/maestro
57  *
58  *  This can be used to enforce mutual exclusion with other simcall.
59  *  More importantly, this enforces a deterministic/reproducible ordering
60  *  of the operation with respect to other simcalls.
61  */
62 template<class F>
63 typename std::result_of<F()>::type kernel(F&& code)
64 {
65   // If we are in the maestro, we take the fast path and execute the
66   // code directly without simcall mashalling/unmarshalling/dispatch:
67   if (SIMIX_is_maestro())
68     return std::forward<F>(code)();
69
70   // If we are in the application, pass the code to the maestro which is
71   // executes it for us and reports the result. We use a std::future which
72   // conveniently handles the success/failure value for us.
73   typedef typename std::result_of<F()>::type R;
74   std::promise<R> promise;
75   simcall_run_kernel([&]{
76     xbt_assert(SIMIX_is_maestro(), "Not in maestro");
77     fulfill_promise(promise, std::forward<F>(code));
78   });
79   return promise.get_future().get();
80 }
81
82 class args {
83 private:
84   int argc_;
85   char** argv_;
86 public:
87
88   // Main constructors
89   args() : argc_(0), argv_(nullptr) {}
90   args(int argc, char** argv) : argc_(argc), argv_(argv) {}
91
92   // Free
93   void clear()
94   {
95     for (int i = 0; i < this->argc_; i++)
96       free(this->argv_[i]);
97     free(this->argv_);
98     this->argc_ = 0;
99     this->argv_ = nullptr;
100   }
101   ~args() { clear(); }
102
103   // Copy
104   args(args const& that) = delete;
105   args& operator=(args const& that) = delete;
106
107   // Move:
108   args(args&& that) : argc_(that.argc_), argv_(that.argv_)
109   {
110     that.argc_ = 0;
111     that.argv_ = nullptr;
112   }
113   args& operator=(args&& that)
114   {
115     this->argc_ = that.argc_;
116     this->argv_ = that.argv_;
117     that.argc_ = 0;
118     that.argv_ = nullptr;
119     return *this;
120   }
121
122   int    argc()            const { return argc_; }
123   char** argv()                  { return argv_; }
124   const char*const* argv() const { return argv_; }
125   char* operator[](std::size_t i) { return argv_[i]; }
126 };
127
128 inline
129 std::function<void()> wrap_main(xbt_main_func_t code, int argc, char **argv)
130 {
131   if (code) {
132     auto arg = std::make_shared<simgrid::simix::args>(argc, argv);
133     return [=]() {
134       code(arg->argc(), arg->argv());
135     };
136   }
137   // TODO, we should free argv
138   else return std::function<void()>();
139 }
140
141 class Context;
142 class ContextFactory;
143
144 XBT_PUBLIC_CLASS ContextFactory {
145 private:
146   std::string name_;
147 public:
148
149   ContextFactory(std::string name) : name_(std::move(name)) {}
150   virtual ~ContextFactory();
151   virtual Context* create_context(std::function<void()> code,
152     void_pfn_smxprocess_t cleanup, smx_process_t process) = 0;
153
154   // Optional methods for attaching main() as a context:
155
156   /** Creates a context from the current context of execution
157    *
158    *  This will not work on all implementation of `ContextFactory`.
159    */
160   virtual Context* attach(void_pfn_smxprocess_t cleanup_func, smx_process_t process);
161   virtual Context* create_maestro(std::function<void()> code, smx_process_t process);
162
163   virtual void run_all() = 0;
164   virtual Context* self();
165   std::string const& name() const
166   {
167     return name_;
168   }
169 private:
170   void declare_context(void* T, std::size_t size);
171 protected:
172   template<class T, class... Args>
173   T* new_context(Args&&... args)
174   {
175     T* context = new T(std::forward<Args>(args)...);
176     this->declare_context(context, sizeof(T));
177     return context;
178   }
179 };
180
181 XBT_PUBLIC_CLASS Context {
182 private:
183   std::function<void()> code_;
184   void_pfn_smxprocess_t cleanup_func_ = nullptr;
185   smx_process_t process_ = nullptr;
186 public:
187   bool iwannadie;
188 public:
189   Context(std::function<void()> code,
190           void_pfn_smxprocess_t cleanup_func,
191           smx_process_t process);
192   void operator()()
193   {
194     code_();
195   }
196   bool has_code() const
197   {
198     return (bool) code_;
199   }
200   smx_process_t process()
201   {
202     return this->process_;
203   }
204   void set_cleanup(void_pfn_smxprocess_t cleanup)
205   {
206     cleanup_func_ = cleanup;
207   }
208
209   // Virtual methods
210   virtual ~Context();
211   virtual void stop();
212   virtual void suspend() = 0;
213 };
214
215 XBT_PUBLIC_CLASS AttachContext : public Context {
216 public:
217
218   AttachContext(std::function<void()> code,
219           void_pfn_smxprocess_t cleanup_func,
220           smx_process_t process)
221     : Context(std::move(code), cleanup_func, process)
222   {}
223
224   ~AttachContext();
225
226   /** Called by the context when it is ready to give control
227    *  to the maestro.
228    */
229   virtual void attach_start() = 0;
230
231   /** Called by the context when it has finished its job */
232   virtual void attach_stop() = 0;
233 };
234
235 }
236 }
237
238 #endif