Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add new entry in Release_Notes.
[simgrid.git] / doc / doxygen / uhood_switch.doc
1 /*! @page uhood_switch Process Synchronizations and Context Switching
2
3 @tableofcontents
4
5 @section uhood_switch_DES SimGrid as an Operating System
6
7 SimGrid is a discrete event simulator of distributed systems: it does
8 not simulate the world by small fixed-size steps but determines the
9 date of the next event (such as the end of a communication, the end of
10 a computation) and jumps to this date.
11
12 A number of actors executing user-provided code run on top of the
13 simulation kernel. The interactions between these actors and the
14 simulation kernel are very similar to the ones between the system
15 processes and the Operating System (except that the actors and
16 simulation kernel share the same address space in a single OS
17 process).
18
19 When an actor needs to interact with the outer world (eg. to start a
20 communication), it issues a <i>simcall</i> (simulation call), just
21 like a system process issues a <i>syscall</i> to interact with its
22 environment through the Operating System. Any <i>simcall</i> freezes
23 the actor until it is woken up by the simulation kernel (eg. when the
24 communication is finished).
25
26 Mimicking the OS behavior may seem over-engineered here, but this is
27 mandatory to the model-checker. The simcalls, representing actors'
28 actions, are the transitions of the formal system. Verifying the
29 system requires to manipulate these transitions explicitly. This also
30 allows one to run the actors safely in parallel, even if this is less
31 commonly used by our users.
32
33 So, the key ideas here are:
34
35  - The simulator is a discrete event simulator (event-driven).
36
37  - An actor can issue a blocking simcall and will be suspended until
38    it is woken up by the simulation kernel (when the operation is
39    completed).
40
41  - In order to move forward in (simulated) time, the simulation kernel
42    needs to know which actions the actors want to do.
43
44  - The simulated time will only move forward when all the actors are
45    blocked, waiting on a simcall.
46
47 This leads to some very important consequences:
48
49  - An actor cannot synchronize with another actor using OS-level primitives
50    such as `pthread_mutex_lock()` or `std::mutex`. The simulation kernel
51    would wait for the actor to issue a simcall and would deadlock. Instead it
52    must use simulation-level synchronization primitives
53    (such as `simcall_mutex_lock()`).
54
55  - Similarly, an actor cannot sleep using
56    `std::this_thread::sleep_for()` which waits in the real world but
57    must instead wait in the simulation with
58    `simgrid::s4u::Actor::this_actor::sleep_for()` which waits in the
59    simulation.
60
61  - The simulation kernel cannot block.
62    Only the actors can block (using simulation primitives).
63
64 @section uhood_switch_futures Futures and Promises
65
66 @subsection uhood_switch_futures_what What is a future?
67
68 Futures are a nice classical programming abstraction, present in many
69 language.  Wikipedia defines a
70 [future](https://en.wikipedia.org/wiki/Futures_and_promises) as an
71 object that acts as a proxy for a result that is initially unknown,
72 usually because the computation of its value is yet incomplete. This
73 concept is thus perfectly adapted to represent in the kernel the
74 asynchronous operations corresponding to the actors' simcalls.
75
76
77 Futures can be manipulated using two kind of APIs:
78
79  - a <b>blocking API</b> where we wait for the result to be available
80    (`res = f.get()`);
81
82  - a <b>continuation-based API</b> where we say what should be done
83    with the result when the operation completes
84    (`future.then(something_to_do_with_the_result)`). This is heavily
85    used in ECMAScript that exhibits the same kind of never-blocking
86    asynchronous model as our discrete event simulator.
87
88 C++11 includes a generic class (`std::future<T>`) which implements a
89 blocking API.  The continuation-based API is not available in the
90 standard (yet) but is [already
91 described](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0159r0.html#futures.unique_future.6)
92 in the Concurrency Technical Specification.
93
94 `Promise`s are the counterparts of `Future`s: `std::future<T>` is used
95 <em>by the consumer</em> of the result. On the other hand,
96 `std::promise<T>` is used <em>by the producer</em> of the result. The
97 producer calls `promise.set_value(42)` or `promise.set_exception(e)`
98 in order to <em>set the result</em> which will be made available to
99 the consumer by `future.get()`.
100
101 @subsection uhood_switch_futures_needs Which future do we need?
102
103 The blocking API provided by the standard C++11 futures does not suit
104 our needs since the simulation kernel <em>cannot</em> block, and since
105 we want to explicitly schedule the actors.  Instead, we need to
106 reimplement a continuation-based API to be used in our event-driven
107 simulation kernel.
108
109 Our futures are based on the C++ Concurrency Technical Specification
110 API, with a few differences:
111
112  - The simulation kernel is single-threaded so we do not need
113    inter-thread synchronization for our futures.
114
115  - As the simulation kernel cannot block, `f.wait()` is not meaningful
116    in this context.
117
118  - Similarly, `future.get()` does an implicit wait. Calling this method in the
119    simulation kernel only makes sense if the future is already ready. If the
120    future is not ready, this would deadlock the simulator and an error is
121    raised instead.
122
123  - We always call the continuations in the simulation loop (and not
124    inside the `future.then()` or `promise.set_value()` calls). That
125    way, we don't have to fear problems like invariants not being
126    restored when the callbacks are called :fearful: or stack overflows
127    triggered by deeply nested continuations chains :cold_sweat:. The
128    continuations are all called in a nice and predictable place in the
129    simulator with a nice and predictable state :relieved:.
130
131  - Some features of the standard (such as shared futures) are not
132    needed in our context, and thus not considered here.
133
134 @subsection uhood_switch_futures_implem Implementing `Future` and `Promise`
135
136 The `simgrid::kernel::Future` and `simgrid::kernel::Promise` use a
137 shared state defined as follows:
138
139 @code{cpp}
140 enum class FutureStatus {
141   not_ready,
142   ready,
143   done,
144 };
145
146 class FutureStateBase : private boost::noncopyable {
147 public:
148   void schedule(simgrid::xbt::Task<void()>&& job);
149   void set_exception(std::exception_ptr exception);
150   void set_continuation(simgrid::xbt::Task<void()>&& continuation);
151   FutureStatus get_status() const;
152   bool is_ready() const;
153   // [...]
154 private:
155   FutureStatus status_ = FutureStatus::not_ready;
156   std::exception_ptr exception_;
157   simgrid::xbt::Task<void()> continuation_;
158 };
159
160 template<class T>
161 class FutureState : public FutureStateBase {
162 public:
163   void set_value(T value);
164   T get();
165 private:
166   boost::optional<T> value_;
167 };
168
169 template<class T>
170 class FutureState<T&> : public FutureStateBase {
171   // ...
172 };
173 template<>
174 class FutureState<void> : public FutureStateBase {
175   // ...
176 };
177 @endcode
178
179 Both `Future` and `Promise` have a reference to the shared state:
180
181 @code{cpp}
182 template<class T>
183 class Future {
184   // [...]
185 private:
186   std::shared_ptr<FutureState<T>> state_;
187 };
188
189 template<class T>
190 class Promise {
191   // [...]
192 private:
193   std::shared_ptr<FutureState<T>> state_;
194   bool future_get_ = false;
195 };
196 @endcode
197
198 The crux of `future.then()` is:
199
200 @code{cpp}
201 template<class T>
202 template<class F>
203 auto simgrid::kernel::Future<T>::then_no_unwrap(F continuation)
204 -> Future<decltype(continuation(std::move(*this)))>
205 {
206   typedef decltype(continuation(std::move(*this))) R;
207
208   if (state_ == nullptr)
209     throw std::future_error(std::future_errc::no_state);
210
211   auto state = std::move(state_);
212   // Create a new future...
213   Promise<R> promise;
214   Future<R> future = promise.get_future();
215   // ...and when the current future is ready...
216   state->set_continuation(simgrid::xbt::makeTask(
217     [](Promise<R> promise, std::shared_ptr<FutureState<T>> state,
218          F continuation) {
219       // ...set the new future value by running the continuation.
220       Future<T> future(std::move(state));
221       simgrid::xbt::fulfillPromise(promise,[&]{
222         return continuation(std::move(future));
223       });
224     },
225     std::move(promise), state, std::move(continuation)));
226   return std::move(future);
227 }
228 @endcode
229
230 We added a (much simpler) `future.then_()` method which does not
231 create a new future:
232
233 @code{cpp}
234 template<class T>
235 template<class F>
236 void simgrid::kernel::Future<T>::then_(F continuation)
237 {
238   if (state_ == nullptr)
239     throw std::future_error(std::future_errc::no_state);
240   // Give shared-ownership to the continuation:
241   auto state = std::move(state_);
242   state->set_continuation(simgrid::xbt::makeTask(
243     std::move(continuation), state));
244 }
245 @endcode
246
247 The `.get()` delegates to the shared state. As we mentioned previously, an
248 error is raised if the future is not ready:
249
250 @code{cpp}
251 template<class T>
252 T simgrid::kernel::Future::get()
253 {
254   if (state_ == nullptr)
255     throw std::future_error(std::future_errc::no_state);
256   std::shared_ptr<FutureState<T>> state = std::move(state_);
257   return state->get();
258 }
259
260 template<class T>
261 T simgrid::kernel::FutureState<T>::get()
262 {
263   xbt_assert(status_ == FutureStatus::ready, "Deadlock: this future is not ready");
264   status_ = FutureStatus::done;
265   if (exception_) {
266     std::exception_ptr exception = std::move(exception_);
267     std::rethrow_exception(std::move(exception));
268   }
269   xbt_assert(this->value_);
270   auto result = std::move(this->value_.get());
271   this->value_ = boost::optional<T>();
272   return std::move(result);
273 }
274 @endcode
275
276 @section uhood_switch_simcalls Implementing the simcalls
277
278 So a simcall is a way for the actor to push a request to the
279 simulation kernel and yield the control until the request is
280 fulfilled. The performance requirements are very high because
281 the actors usually do an inordinate amount of simcalls during the
282 simulation.
283
284 As for real syscalls, the basic idea is to write the wanted call and
285 its arguments in a memory area that is specific to the actor, and
286 yield the control to the simulation kernel. Once in kernel mode, the
287 simcalls of each demanding actor are evaluated sequentially in a
288 strictly reproducible order. This makes the whole simulation
289 reproducible.
290
291
292 @subsection uhood_switch_simcalls_v2 The historical way
293
294 In the very first implementation, everything was written by hand and
295 highly optimized, making our software very hard to maintain and
296 evolve. We decided to sacrifice some performance for
297 maintainability. In a second try (that is still in use in SimGrid
298 v3.13), we had a lot of boiler code generated from a python script,
299 taking the [list of simcalls](https://github.com/simgrid/simgrid/blob/4ae2fd01d8cc55bf83654e29f294335e3cb1f022/src/simix/simcalls.in)
300 as input. It looks like this:
301
302 @code{cpp}
303 # This looks like C++ but it is a basic IDL-like language
304 # (one definition per line) parsed by a python script:
305
306 void process_kill(smx_actor_t process);
307 void process_killall(int reset_pid);
308 void process_cleanup(smx_actor_t process) [[nohandler]];
309 void process_suspend(smx_actor_t process) [[block]];
310 void process_resume(smx_actor_t process);
311 void process_set_host(smx_actor_t process, sg_host_t dest);
312 int  process_is_suspended(smx_actor_t process) [[nohandler]];
313 int  process_join(smx_actor_t process, double timeout) [[block]];
314 int  process_sleep(double duration) [[block]];
315
316 smx_mutex_t mutex_init();
317 void        mutex_lock(smx_mutex_t mutex) [[block]];
318 int         mutex_trylock(smx_mutex_t mutex);
319 void        mutex_unlock(smx_mutex_t mutex);
320
321 [...]
322 @endcode
323
324 At runtime, a simcall is represented by a structure containing a simcall
325 number and its arguments (among some other things):
326
327 @code{cpp}
328 struct s_smx_simcall {
329   // Simcall number:
330   Simcall call;
331   // Issuing actor:
332   smx_actor_t issuer;
333   // Arguments of the simcall:
334   union u_smx_scalar args[11];
335   // Result of the simcall:
336   union u_smx_scalar result;
337   // Some additional stuff:
338   smx_timer_t timer;
339 };
340 @endcode
341
342 with the a scalar union type:
343
344 @code{cpp}
345 union u_smx_scalar {
346   char            c;
347   short           s;
348   int             i;
349   long            l;
350   long long       ll;
351   unsigned char   uc;
352   unsigned short  us;
353   unsigned int    ui;
354   unsigned long   ul;
355   unsigned long long ull;
356   double          d;
357   void*           dp;
358   FPtr            fp;
359 };
360 @endcode
361
362 When manually calling the relevant [Python
363 script](https://github.com/simgrid/simgrid/blob/4ae2fd01d8cc55bf83654e29f294335e3cb1f022/src/simix/simcalls.py),
364 this generates a bunch of C++ files:
365
366 * an enum of all the [simcall numbers](https://github.com/simgrid/simgrid/blob/4ae2fd01d8cc55bf83654e29f294335e3cb1f022/src/simix/popping_enum.h#L19);
367
368 * [user-side wrappers](https://github.com/simgrid/simgrid/blob/4ae2fd01d8cc55bf83654e29f294335e3cb1f022/src/simix/popping_bodies.cpp)
369   responsible for wrapping the parameters in the `struct s_smx_simcall`;
370   and wrapping out the result;
371
372 * [accessors](https://github.com/simgrid/simgrid/blob/4ae2fd01d8cc55bf83654e29f294335e3cb1f022/src/simix/popping_accessors.hpp)
373    to get/set values of of `struct s_smx_simcall`;
374
375 * a simulation-kernel-side [big switch](https://github.com/simgrid/simgrid/blob/4ae2fd01d8cc55bf83654e29f294335e3cb1f022/src/simix/popping_generated.cpp#L106)
376   handling all the simcall numbers.
377
378 Then one has to write the code of the kernel side handler for the simcall
379 and the code of the simcall itself (which calls the code-generated
380 marshaling/unmarshaling stuff).
381
382 In order to simplify this process, we added two generic simcalls which can be
383 used to execute a function in the simulation kernel:
384
385 @code{cpp}
386 # This one should really be called run_immediate:
387 void run_kernel(std::function<void()> const* code) [[nohandler]];
388 void run_blocking(std::function<void()> const* code) [[block,nohandler]];
389 @endcode
390
391 ### Immediate simcall
392
393 The first one (`simcall_run_kernel()`) executes a function in the simulation
394 kernel context and returns immediately (without blocking the actor):
395
396 @code{cpp}
397 void simcall_run_kernel(std::function<void()> const& code)
398 {
399   simcall_BODY_run_kernel(&code);
400 }
401
402 template<class F> inline
403 void simcall_run_kernel(F& f)
404 {
405   simcall_run_kernel(std::function<void()>(std::ref(f)));
406 }
407 @endcode
408
409 On top of this, we add a wrapper which can be used to return a value of any
410 type and properly handles exceptions:
411
412 @code{cpp}
413 template<class F>
414 typename std::result_of_t<F()> kernelImmediate(F&& code)
415 {
416   // If we are in the simulation kernel, we take the fast path and
417   // execute the code directly without simcall
418   // marshalling/unmarshalling/dispatch:
419   if (SIMIX_is_maestro())
420     return std::forward<F>(code)();
421
422   // If we are in the application, pass the code to the simulation
423   // kernel which executes it for us and reports the result:
424   typedef typename std::result_of_t<F()> R;
425   simgrid::xbt::Result<R> result;
426   simcall_run_kernel([&]{
427     xbt_assert(SIMIX_is_maestro(), "Not in maestro");
428     simgrid::xbt::fulfillPromise(result, std::forward<F>(code));
429   });
430   return result.get();
431 }
432 @endcode
433
434 where [`Result<R>`](#result) can store either a `R` or an exception.
435
436 Example of usage:
437
438 @code{cpp}
439 xbt_dict_t Host::properties() {
440   return simgrid::simix::kernelImmediate([&] {
441     simgrid::kernel::resource::HostImpl* host =
442       this->extension<simgrid::kernel::resource::HostImpl>();
443     return host->getProperties();
444   });
445 }
446 @endcode
447
448 ### Blocking simcall {#uhood_switch_v2_blocking}
449
450 The second generic simcall (`simcall_run_blocking()`) executes a function in
451 the SimGrid simulation kernel immediately but does not wake up the calling actor
452 immediately:
453
454 @code{cpp}
455 void simcall_run_blocking(std::function<void()> const& code);
456
457 template<class F>
458 void simcall_run_blocking(F& f)
459 {
460   simcall_run_blocking(std::function<void()>(std::ref(f)));
461 }
462 @endcode
463
464 The `f` function is expected to setup some callbacks in the simulation
465 kernel which will wake up the actor (with
466 `simgrid::simix::unblock(actor)`) when the operation is completed.
467
468 This is wrapped in a higher-level primitive as well. The
469 `kernel_sync()` function expects a function-object which is executed
470 immediately in the simulation kernel and returns a `Future<T>`.  The
471 simulator blocks the actor and resumes it when the `Future<T>` becomes
472 ready with its result:
473
474 @code{cpp}
475 template<class F>
476 auto kernel_sync(F code) -> decltype(code().get())
477 {
478   typedef decltype(code().get()) T;
479   xbt_assert(not SIMIX_is_maestro(), "Can't execute blocking call in kernel mode");
480
481   auto self = simgrid::kernel::actor::ActorImpl::self();
482   simgrid::xbt::Result<T> result;
483
484   simcall_run_blocking([&result, self, &code]{
485     try {
486       auto future = code();
487       future.then_([&result, self](simgrid::kernel::Future<T> value) {
488         // Propagate the result from the future
489         // to the simgrid::xbt::Result:
490         simgrid::xbt::setPromise(result, value);
491         simgrid::simix::unblock(self);
492       });
493     }
494     catch (...) {
495       // The code failed immediately. We can wake up the actor
496       // immediately with the exception:
497       result.set_exception(std::current_exception());
498       simgrid::simix::unblock(self);
499     }
500   });
501
502   // Get the result of the operation (which might be an exception):
503   return result.get();
504 }
505 @endcode
506
507 A contrived example of this would be:
508
509 @code{cpp}
510 int res = simgrid::simix::kernel_sync([&] {
511   return kernel_wait_until(30).then(
512     [](simgrid::kernel::Future<void> future) {
513       return 42;
514     }
515   );
516 });
517 @endcode
518
519 ### Asynchronous operations {#uhood_switch_v2_async}
520
521 We can write the related `kernel_async()` which wakes up the actor immediately
522 and returns a future to the actor. As this future is used in the actor context,
523 it is a different future
524 (`simgrid::simix::Future` instead of `simgrid::kernel::Future`)
525 which implements a C++11 `std::future` wait-based API:
526
527 @code{cpp}
528 template <class T>
529 class Future {
530 public:
531   Future() {}
532   Future(simgrid::kernel::Future<T> future) : future_(std::move(future)) {}
533   bool valid() const { return future_.valid(); }
534   T get();
535   bool is_ready() const;
536   void wait();
537 private:
538   // We wrap an event-based kernel future:
539   simgrid::kernel::Future<T> future_;
540 };
541 @endcode
542
543 The `future.get()` method is implemented as[^getcompared]:
544
545 @code{cpp}
546 template<class T>
547 T simgrid::simix::Future<T>::get()
548 {
549   if (!valid())
550     throw std::future_error(std::future_errc::no_state);
551   auto self = simgrid::kernel::actor::ActorImpl::self();
552   simgrid::xbt::Result<T> result;
553   simcall_run_blocking([this, &result, self]{
554     try {
555       // When the kernel future is ready...
556       this->future_.then_(
557         [this, &result, self](simgrid::kernel::Future<T> value) {
558           // ... wake up the process with the result of the kernel future.
559           simgrid::xbt::setPromise(result, value);
560           simgrid::simix::unblock(self);
561       });
562     }
563     catch (...) {
564       result.set_exception(std::current_exception());
565       simgrid::simix::unblock(self);
566     }
567   });
568   return result.get();
569 }
570 @endcode
571
572 `kernel_async()` simply :wink: calls `kernelImmediate()` and wraps the
573 `simgrid::kernel::Future` into a `simgrid::simix::Future`:
574
575 @code{cpp}
576 template<class F>
577 auto kernel_async(F code)
578   -> Future<decltype(code().get())>
579 {
580   typedef decltype(code().get()) T;
581
582   // Execute the code in the simulation kernel and get the kernel future:
583   simgrid::kernel::Future<T> future =
584     simgrid::simix::kernelImmediate(std::move(code));
585
586   // Wrap the kernel future in a user future:
587   return simgrid::simix::Future<T>(std::move(future));
588 }
589 @endcode
590
591 A contrived example of this would be:
592
593 @code{cpp}
594 simgrid::simix::Future<int> future = simgrid::simix::kernel_sync([&] {
595   return kernel_wait_until(30).then(
596     [](simgrid::kernel::Future<void> future) {
597       return 42;
598     }
599   );
600 });
601 do_some_stuff();
602 int res = future.get();
603 @endcode
604
605 `kernel_sync()` could be rewritten as:
606
607 @code{cpp}
608 template<class F>
609 auto kernel_sync(F code) -> decltype(code().get())
610 {
611   return kernel_async(std::move(code)).get();
612 }
613 @endcode
614
615 The semantic is equivalent but this form would require two simcalls
616 instead of one to do the same job (one in `kernel_async()` and one in
617 `.get()`).
618
619 ## Mutexes and condition variables
620
621 ### Condition Variables
622
623 Similarly SimGrid already had simulation-level condition variables
624 which can be exposed using the same API as `std::condition_variable`:
625
626 @code{cpp}
627 class ConditionVariable {
628 private:
629   friend s_smx_cond_t;
630   smx_cond_t cond_;
631   ConditionVariable(smx_cond_t cond) : cond_(cond) {}
632 public:
633
634   ConditionVariable(ConditionVariable const&) = delete;
635   ConditionVariable& operator=(ConditionVariable const&) = delete;
636
637   friend void intrusive_ptr_add_ref(ConditionVariable* cond);
638   friend void intrusive_ptr_release(ConditionVariable* cond);
639   using Ptr = boost::intrusive_ptr<ConditionVariable>;
640   static Ptr createConditionVariable();
641
642   void wait(std::unique_lock<Mutex>& lock);
643   template<class P>
644   void wait(std::unique_lock<Mutex>& lock, P pred);
645
646   // Wait functions taking a plain double as time:
647
648   std::cv_status wait_until(std::unique_lock<Mutex>& lock,
649     double timeout_time);
650   std::cv_status wait_for(
651     std::unique_lock<Mutex>& lock, double duration);
652   template<class P>
653   bool wait_until(std::unique_lock<Mutex>& lock,
654     double timeout_time, P pred);
655   template<class P>
656   bool wait_for(std::unique_lock<Mutex>& lock,
657     double duration, P pred);
658
659   // Wait functions taking a std::chrono time:
660
661   template<class Rep, class Period, class P>
662   bool wait_for(std::unique_lock<Mutex>& lock,
663     std::chrono::duration<Rep, Period> duration, P pred);
664   template<class Rep, class Period>
665   std::cv_status wait_for(std::unique_lock<Mutex>& lock,
666     std::chrono::duration<Rep, Period> duration);
667   template<class Duration>
668   std::cv_status wait_until(std::unique_lock<Mutex>& lock,
669     const SimulationTimePoint<Duration>& timeout_time);
670   template<class Duration, class P>
671   bool wait_until(std::unique_lock<Mutex>& lock,
672     const SimulationTimePoint<Duration>& timeout_time, P pred);
673
674   // Notify:
675
676   void notify_one();
677   void notify_all();
678
679 };
680 @endcode
681
682 We currently accept both `double` (for simplicity and consistency with
683 the current codebase) and `std::chrono` types (for compatibility with
684 C++ code) as durations and timepoints. One important thing to notice here is
685 that `cond.wait_for()` and `cond.wait_until()` work in the simulated time,
686 not in the real time.
687
688 The simple `cond.wait()` and `cond.wait_for()` delegate to
689 pre-existing simcalls:
690
691 @code{cpp}
692 void ConditionVariable::wait(std::unique_lock<Mutex>& lock)
693 {
694   simcall_cond_wait(cond_, lock.mutex()->mutex_);
695 }
696
697 std::cv_status ConditionVariable::wait_for(
698   std::unique_lock<Mutex>& lock, double timeout)
699 {
700   // The simcall uses -1 for "any timeout" but we don't want this:
701   if (timeout < 0)
702     timeout = 0.0;
703
704   try {
705     simcall_cond_wait_timeout(cond_, lock.mutex()->mutex_, timeout);
706     return std::cv_status::no_timeout;
707   }
708   catch (const simgrid::TimeoutException& e) {
709     // If the exception was a timeout, we have to take the lock again:
710     try {
711       lock.mutex()->lock();
712       return std::cv_status::timeout;
713     }
714     catch (...) {
715       std::terminate();
716     }
717   }
718   catch (...) {
719     std::terminate();
720   }
721 }
722 @endcode
723
724 Other methods are simple wrappers around those two:
725
726 @code{cpp}
727 template<class P>
728 void ConditionVariable::wait(std::unique_lock<Mutex>& lock, P pred)
729 {
730   while (!pred())
731     wait(lock);
732 }
733
734 template<class P>
735 bool ConditionVariable::wait_until(std::unique_lock<Mutex>& lock,
736   double timeout_time, P pred)
737 {
738   while (!pred())
739     if (this->wait_until(lock, timeout_time) == std::cv_status::timeout)
740       return pred();
741   return true;
742 }
743
744 template<class P>
745 bool ConditionVariable::wait_for(std::unique_lock<Mutex>& lock,
746   double duration, P pred)
747 {
748   return this->wait_until(lock,
749     simgrid::s4u::Engine::get_clock() + duration, std::move(pred));
750 }
751 @endcode
752
753
754 ## Conclusion
755
756 We wrote two future implementations based on the `std::future` API:
757
758 * the first one is a non-blocking event-based (`future.then(stuff)`)
759   future used inside our (non-blocking event-based) simulation kernel;
760
761 * the second one is a wait-based (`future.get()`) future used in the actors
762   which waits using a simcall.
763
764 These futures are used to implement `kernel_sync()` and `kernel_async()` which
765 expose asynchronous operations in the simulation kernel to the actors.
766
767 In addition, we wrote variations of some other C++ standard library
768 classes (`SimulationClock`, `Mutex`, `ConditionVariable`) which work in
769 the simulation:
770
771   * using simulated time;
772
773   * using simcalls for synchronisation.
774
775 Reusing the same API as the C++ standard library is very useful because:
776
777   * we use a proven API with a clearly defined semantic;
778
779   * people already familiar with those API can use our own easily;
780
781   * users can rely on documentation, examples and tutorials made by other
782     people;
783
784   * we can reuse generic code with our types (`std::unique_lock`,
785    `std::lock_guard`, etc.).
786
787 This type of approach might be useful for other libraries which define
788 their own contexts. An example of this is
789 [Mordor](https://github.com/mozy/mordor), an I/O library using fibers
790 (cooperative scheduling): it implements cooperative/fiber
791 [mutex](https://github.com/mozy/mordor/blob/4803b6343aee531bfc3588ffc26a0d0fdf14b274/mordor/fibersynchronization.h#L70),
792 [recursive
793 mutex](https://github.com/mozy/mordor/blob/4803b6343aee531bfc3588ffc26a0d0fdf14b274/mordor/fibersynchronization.h#L105)
794 which are compatible with the
795 [`BasicLockable`](http://en.cppreference.com/w/cpp/concept/BasicLockable)
796 requirements (see
797 [`[thread.req.lockable.basic]`]((http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf#page=1175))
798 in the C++14 standard).
799
800 ## Appendix: useful helpers
801
802 ### `Result`
803
804 Result is like a mix of `std::future` and `std::promise` in a
805 single-object without shared-state and synchronisation:
806
807 @code{cpp}
808 template<class T>
809 class Result {
810 public:
811   bool is_valid() const;
812   void set_exception(std::exception_ptr e);
813   void set_value(T&& value);
814   void set_value(T const& value);
815   T get();
816 private:
817   boost::variant<boost::blank, T, std::exception_ptr> value_;
818 };
819 @endcode~
820
821 ### Promise helpers
822
823 Those helper are useful for dealing with generic future-based code:
824
825 @code{cpp}
826 template<class R, class F>
827 auto fulfillPromise(R& promise, F&& code)
828 -> decltype(promise.set_value(code()))
829 {
830   try {
831     promise.set_value(std::forward<F>(code)());
832   }
833   catch(...) {
834     promise.set_exception(std::current_exception());
835   }
836 }
837
838 template<class P, class F>
839 auto fulfillPromise(P& promise, F&& code)
840 -> decltype(promise.set_value())
841 {
842   try {
843     std::forward<F>(code)();
844     promise.set_value();
845   }
846   catch(...) {
847     promise.set_exception(std::current_exception());
848   }
849 }
850
851 template<class P, class F>
852 void setPromise(P& promise, F&& future)
853 {
854   fulfillPromise(promise, [&]{ return std::forward<F>(future).get(); });
855 }
856 @endcode
857
858 ### Task
859
860 `Task<R(F...)>` is a type-erased callable object similar to
861 `std::function<R(F...)>` but works for move-only types. It is similar to
862 `std::package_task<R(F...)>` but does not wrap the result in a `std::future<R>`
863 (it is not <i>packaged</i>).
864
865 |               |`std::function` |`std::packaged_task`|`simgrid::xbt::Task`
866 |---------------|----------------|--------------------|--------------------------
867 |Copyable       | Yes            | No                 | No
868 |Movable        | Yes            | Yes                | Yes
869 |Call           | `const`        | non-`const`        | non-`const`
870 |Callable       | multiple times | once               | once
871 |Sets a promise | No             | Yes                | No
872
873 It could be implemented as:
874
875 @code{cpp}
876 template<class T>
877 class Task {
878 private:
879   std::packaged_task<T> task_;
880 public:
881
882   template<class F>
883   void Task(F f) :
884     task_(std::forward<F>(f))
885   {}
886
887   template<class... ArgTypes>
888   auto operator()(ArgTypes... args)
889   -> decltype(task_.get_future().get())
890   {
891     task_(std::forward<ArgTypes)(args)...);
892     return task_.get_future().get();
893   }
894
895 };
896 @endcode
897
898 but we don't need a shared-state.
899
900 This is useful in order to bind move-only type arguments:
901
902 @code{cpp}
903 template<class F, class... Args>
904 class TaskImpl {
905 private:
906   F code_;
907   std::tuple<Args...> args_;
908   typedef decltype(simgrid::xbt::apply(
909     std::move(code_), std::move(args_))) result_type;
910 public:
911   TaskImpl(F code, std::tuple<Args...> args) :
912     code_(std::move(code)),
913     args_(std::move(args))
914   {}
915   result_type operator()()
916   {
917     // simgrid::xbt::apply is C++17 std::apply:
918     return simgrid::xbt::apply(std::move(code_), std::move(args_));
919   }
920 };
921
922 template<class F, class... Args>
923 auto makeTask(F code, Args... args)
924 -> Task< decltype(code(std::move(args)...))() >
925 {
926   TaskImpl<F, Args...> task(
927     std::move(code), std::make_tuple(std::move(args)...));
928   return std::move(task);
929 }
930 @endcode
931
932
933 ## Notes
934
935 [^getcompared]:
936
937     You might want to compare this method with `simgrid::kernel::Future::get()`
938     we showed previously: the method of the kernel future does not block and
939     raises an error if the future is not ready; the method of the actor future
940     blocks after having set a continuation to wake the actor when the future
941     is ready.
942
943 [^lock]:
944
945     `std::lock()` might kinda work too but it may not be such as good idea to
946     use it as it may use a [<q>deadlock avoidance algorithm such as
947     try-and-back-off</q>](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf#page=1199).
948     A backoff would probably uselessly wait in real time instead of simulated
949     time. The deadlock avoidance algorithm might as well add non-determinism
950     in the simulation which we would like to avoid.
951     `std::try_lock()` should be safe to use though.
952
953 */