Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
e7e7070ce31f9653fca06316542b6c6a7a34a3e7
[simgrid.git] / src / simix / smx_global.cpp
1 /* Copyright (c) 2007-2018. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "mc/mc.h"
7 #include "simgrid/s4u/Engine.hpp"
8 #include "simgrid/s4u/Host.hpp"
9 #include "simgrid/sg_config.hpp"
10 #include "smx_private.hpp"
11 #include "src/kernel/activity/SleepImpl.hpp"
12 #include "src/kernel/activity/SynchroIo.hpp"
13 #include "src/kernel/activity/SynchroRaw.hpp"
14 #include "src/mc/mc_record.hpp"
15 #include "src/mc/mc_replay.hpp"
16 #include "src/simix/smx_host_private.hpp"
17 #include "src/smpi/include/smpi_process.hpp"
18 #include "src/surf/StorageImpl.hpp"
19 #include "src/surf/xml/platf.hpp"
20
21 #if SIMGRID_HAVE_MC
22 #include "src/mc/mc_private.hpp"
23 #include "src/mc/remote/Client.hpp"
24 #include "src/mc/remote/mc_protocol.h"
25 #endif
26
27 #if HAVE_SMPI
28 #include "src/smpi/include/private.hpp"
29 #endif
30
31 #include <boost/heap/fibonacci_heap.hpp>
32
33 XBT_LOG_NEW_CATEGORY(simix, "All SIMIX categories");
34 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_kernel, simix, "Logging specific to SIMIX (kernel)");
35
36 std::unique_ptr<simgrid::simix::Global> simix_global;
37
38 namespace {
39 typedef std::pair<double, smx_timer_t> TimerQelt;
40 boost::heap::fibonacci_heap<TimerQelt, boost::heap::compare<simgrid::xbt::HeapComparator<TimerQelt>>> simix_timers;
41 }
42
43 /** @brief Timer datatype */
44 class s_smx_timer_t {
45   double date = 0.0;
46
47 public:
48   decltype(simix_timers)::handle_type handle_;
49   simgrid::xbt::Task<void()> callback;
50   double getDate() { return date; }
51   s_smx_timer_t(double date, simgrid::xbt::Task<void()> callback) : date(date), callback(std::move(callback)) {}
52 };
53
54 void (*SMPI_switch_data_segment)(simgrid::s4u::ActorPtr) = nullptr;
55
56 int _sg_do_verbose_exit = 1;
57 static void inthandler(int)
58 {
59   if ( _sg_do_verbose_exit ) {
60      XBT_INFO("CTRL-C pressed. The current status will be displayed before exit (disable that behavior with option 'verbose-exit').");
61      SIMIX_display_process_status();
62   }
63   else {
64      XBT_INFO("CTRL-C pressed, exiting. Hiding the current process status since 'verbose-exit' is set to false.");
65   }
66   exit(1);
67 }
68
69 #ifndef _WIN32
70 static void segvhandler(int signum, siginfo_t* siginfo, void* /*context*/)
71 {
72   if (siginfo->si_signo == SIGSEGV && siginfo->si_code == SEGV_ACCERR) {
73     fprintf(stderr, "Access violation detected.\n"
74                     "This probably comes from a programming error in your code, or from a stack\n"
75                     "overflow. If you are certain of your code, try increasing the stack size\n"
76                     "   --cfg=contexts/stack-size=XXX (current size is %u KiB).\n"
77                     "\n"
78                     "If it does not help, this may have one of the following causes:\n"
79                     "a bug in SimGrid, a bug in the OS or a bug in a third-party libraries.\n"
80                     "Failing hardware can sometimes generate such errors too.\n"
81                     "\n"
82                     "If you think you've found a bug in SimGrid, please report it along with a\n"
83                     "Minimal Working Example (MWE) reproducing your problem and a full backtrace\n"
84                     "of the fault captured with gdb or valgrind.\n",
85             smx_context_stack_size / 1024);
86   } else  if (siginfo->si_signo == SIGSEGV) {
87     fprintf(stderr, "Segmentation fault.\n");
88 #if HAVE_SMPI
89     if (smpi_enabled() && smpi_privatize_global_variables == SmpiPrivStrategies::None) {
90 #if HAVE_PRIVATIZATION
91       fprintf(stderr, "Try to enable SMPI variable privatization with --cfg=smpi/privatization:yes.\n");
92 #else
93       fprintf(stderr, "Sadly, your system does not support --cfg=smpi/privatization:yes (yet).\n");
94 #endif /* HAVE_PRIVATIZATION */
95     }
96 #endif /* HAVE_SMPI */
97   }
98   raise(signum);
99 }
100
101 char sigsegv_stack[SIGSTKSZ];   /* alternate stack for SIGSEGV handler */
102
103 /**
104  * Install signal handler for SIGSEGV.  Check that nobody has already installed
105  * its own handler.  For example, the Java VM does this.
106  */
107 static void install_segvhandler()
108 {
109   stack_t stack;
110   stack_t old_stack;
111   stack.ss_sp = sigsegv_stack;
112   stack.ss_size = sizeof sigsegv_stack;
113   stack.ss_flags = 0;
114
115   if (sigaltstack(&stack, &old_stack) == -1) {
116     XBT_WARN("Failed to register alternate signal stack: %s", strerror(errno));
117     return;
118   }
119   if (not(old_stack.ss_flags & SS_DISABLE)) {
120     XBT_DEBUG("An alternate stack was already installed (sp=%p, size=%zu, flags=%x). Restore it.", old_stack.ss_sp,
121               old_stack.ss_size, (unsigned)old_stack.ss_flags);
122     sigaltstack(&old_stack, nullptr);
123   }
124
125   struct sigaction action;
126   struct sigaction old_action;
127   action.sa_sigaction = &segvhandler;
128   action.sa_flags = SA_ONSTACK | SA_RESETHAND | SA_SIGINFO;
129   sigemptyset(&action.sa_mask);
130
131   if (sigaction(SIGSEGV, &action, &old_action) == -1) {
132     XBT_WARN("Failed to register signal handler for SIGSEGV: %s", strerror(errno));
133     return;
134   }
135   if ((old_action.sa_flags & SA_SIGINFO) || old_action.sa_handler != SIG_DFL) {
136     XBT_DEBUG("A signal handler was already installed for SIGSEGV (%p). Restore it.",
137              (old_action.sa_flags & SA_SIGINFO) ? (void*)old_action.sa_sigaction : (void*)old_action.sa_handler);
138     sigaction(SIGSEGV, &old_action, nullptr);
139   }
140 }
141
142 #endif /* _WIN32 */
143
144 /********************************* SIMIX **************************************/
145 double SIMIX_timer_next()
146 {
147   return simix_timers.empty() ? -1.0 : simix_timers.top().first;
148 }
149
150 static void kill_process(smx_actor_t process)
151 {
152   SIMIX_process_kill(process, nullptr);
153 }
154
155
156 namespace simgrid {
157 namespace simix {
158
159 simgrid::xbt::signal<void()> onDeadlock;
160
161 }
162 }
163
164 static std::function<void()> maestro_code;
165 void SIMIX_set_maestro(void (*code)(void*), void* data)
166 {
167 #ifdef _WIN32
168   XBT_INFO("WARNING, SIMIX_set_maestro is believed to not work on windows. Please help us investigating this issue if you need that feature");
169 #endif
170   maestro_code = std::bind(code, data);
171 }
172
173 /**
174  * \ingroup SIMIX_API
175  * \brief Initialize SIMIX internal data.
176  */
177 void SIMIX_global_init(int *argc, char **argv)
178 {
179 #if SIMGRID_HAVE_MC
180   // The communication initialization is done ASAP.
181   // We need to communicate  initialization of the different layers to the model-checker.
182   simgrid::mc::Client::initialize();
183 #endif
184
185   if (not simix_global) {
186     simix_global = std::unique_ptr<simgrid::simix::Global>(new simgrid::simix::Global());
187     simix_global->maestro_process = nullptr;
188     simix_global->create_process_function = &SIMIX_process_create;
189     simix_global->kill_process_function = &kill_process;
190     simix_global->cleanup_process_function = &SIMIX_process_cleanup;
191     simix_global->mutex = xbt_os_mutex_init();
192
193     surf_init(argc, argv);      /* Initialize SURF structures */
194     SIMIX_context_mod_init();
195
196     // Either create a new context with maestro or create
197     // a context object with the current context mestro):
198     simgrid::kernel::actor::create_maestro(maestro_code);
199
200     /* Prepare to display some more info when dying on Ctrl-C pressing */
201     signal(SIGINT, inthandler);
202
203 #ifndef _WIN32
204     install_segvhandler();
205 #endif
206     /* register a function to be called by SURF after the environment creation */
207     sg_platf_init();
208     simgrid::s4u::onPlatformCreated.connect(SIMIX_post_create_environment);
209     simgrid::s4u::Host::onCreation.connect([](simgrid::s4u::Host& host) {
210       if (host.extension<simgrid::simix::Host>() == nullptr) // another callback to the same signal may have created it
211         host.extension_set<simgrid::simix::Host>(new simgrid::simix::Host());
212     });
213
214     simgrid::surf::storageCreatedCallbacks.connect([](simgrid::surf::StorageImpl* storage) {
215       sg_storage_t s = simgrid::s4u::Storage::byName(storage->get_cname());
216       xbt_assert(s != nullptr, "Storage not found for name %s", storage->get_cname());
217     });
218   }
219
220   if (xbt_cfg_get_boolean("clean-atexit"))
221     atexit(SIMIX_clean);
222
223   if (_sg_cfg_exit_asap)
224     exit(0);
225 }
226
227 int smx_cleaned = 0;
228 /**
229  * \ingroup SIMIX_API
230  * \brief Clean the SIMIX simulation
231  *
232  * This functions remove the memory used by SIMIX
233  */
234 void SIMIX_clean()
235 {
236   if (smx_cleaned)
237     return; // to avoid double cleaning by java and C
238
239   smx_cleaned = 1;
240   XBT_DEBUG("SIMIX_clean called. Simulation's over.");
241   if (not simix_global->process_to_run.empty() && SIMIX_get_clock() <= 0.0) {
242     XBT_CRITICAL("   ");
243     XBT_CRITICAL("The time is still 0, and you still have processes ready to run.");
244     XBT_CRITICAL("It seems that you forgot to run the simulation that you setup.");
245     xbt_die("Bailing out to avoid that stop-before-start madness. Please fix your code.");
246   }
247
248 #if HAVE_SMPI
249   if (SIMIX_process_count()>0){
250     if(smpi_process()->initialized()){
251       xbt_die("Process exited without calling MPI_Finalize - Killing simulation");
252     }else{
253       XBT_WARN("Process called exit when leaving - Skipping cleanups");
254       return;
255     }
256   }
257 #endif
258
259   /* Kill all processes (but maestro) */
260   SIMIX_process_killall(simix_global->maestro_process);
261   SIMIX_context_runall();
262   SIMIX_process_empty_trash();
263
264   /* Exit the SIMIX network module */
265   SIMIX_mailbox_exit();
266
267   while (not simix_timers.empty()) {
268     delete simix_timers.top().second;
269     simix_timers.pop();
270   }
271   /* Free the remaining data structures */
272   simix_global->process_to_run.clear();
273   simix_global->process_that_ran.clear();
274   simix_global->process_to_destroy.clear();
275   simix_global->process_list.clear();
276
277   xbt_os_mutex_destroy(simix_global->mutex);
278   simix_global->mutex = nullptr;
279 #if SIMGRID_HAVE_MC
280   xbt_dynar_free(&simix_global->actors_vector);
281   xbt_dynar_free(&simix_global->dead_actors_vector);
282 #endif
283
284   /* Let's free maestro now */
285   delete simix_global->maestro_process->context;
286   simix_global->maestro_process->context = nullptr;
287   delete simix_global->maestro_process;
288   simix_global->maestro_process = nullptr;
289
290   /* Finish context module and SURF */
291   SIMIX_context_mod_exit();
292
293   surf_exit();
294
295   simix_global = nullptr;
296 }
297
298
299 /**
300  * \ingroup SIMIX_API
301  * \brief A clock (in second).
302  *
303  * \return Return the clock.
304  */
305 double SIMIX_get_clock()
306 {
307   if(MC_is_active() || MC_record_replay_is_active()){
308     return MC_process_clock_get(SIMIX_process_self());
309   }else{
310     return surf_get_clock();
311   }
312 }
313
314 /** Wake up all processes waiting for a Surf action to finish */
315 static void SIMIX_wake_processes()
316 {
317   for (auto const& model : *all_existing_models) {
318     simgrid::kernel::resource::Action* action;
319
320     XBT_DEBUG("Handling the processes whose action failed (if any)");
321     while ((action = surf_model_extract_failed_action_set(model))) {
322       XBT_DEBUG("   Handling Action %p",action);
323       SIMIX_simcall_exit(static_cast<simgrid::kernel::activity::ActivityImpl*>(action->get_data()));
324     }
325     XBT_DEBUG("Handling the processes whose action terminated normally (if any)");
326     while ((action = surf_model_extract_done_action_set(model))) {
327       XBT_DEBUG("   Handling Action %p",action);
328       if (action->get_data() == nullptr)
329         XBT_DEBUG("probably vcpu's action %p, skip", action);
330       else
331         SIMIX_simcall_exit(static_cast<simgrid::kernel::activity::ActivityImpl*>(action->get_data()));
332     }
333   }
334 }
335
336 /** Handle any pending timer */
337 static bool SIMIX_execute_timers()
338 {
339   bool result = false;
340   while (not simix_timers.empty() && SIMIX_get_clock() >= simix_timers.top().first) {
341     result = true;
342     // FIXME: make the timers being real callbacks
343     // (i.e. provide dispatchers that read and expand the args)
344     smx_timer_t timer = simix_timers.top().second;
345     simix_timers.pop();
346     try {
347       timer->callback();
348     } catch (...) {
349       xbt_die("Exception thrown ouf of timer callback");
350     }
351     delete timer;
352   }
353   return result;
354 }
355
356 /** Execute all the tasks that are queued
357  *
358  *  e.g. `.then()` callbacks of futures.
359  **/
360 static bool SIMIX_execute_tasks()
361 {
362   xbt_assert(simix_global->tasksTemp.empty());
363
364   if (simix_global->tasks.empty())
365     return false;
366
367   using std::swap;
368   do {
369     // We don't want the callbacks to modify the vector we are iterating over:
370     swap(simix_global->tasks, simix_global->tasksTemp);
371
372     // Execute all the queued tasks:
373     for (auto& task : simix_global->tasksTemp)
374       task();
375
376     simix_global->tasksTemp.clear();
377   } while (not simix_global->tasks.empty());
378
379   return true;
380 }
381
382 /**
383  * \ingroup SIMIX_API
384  * \brief Run the main simulation loop.
385  */
386 void SIMIX_run()
387 {
388   if (not MC_record_path.empty()) {
389     simgrid::mc::replay(MC_record_path);
390     return;
391   }
392
393   double time = 0;
394
395   do {
396     XBT_DEBUG("New Schedule Round; size(queue)=%zu", simix_global->process_to_run.size());
397
398     SIMIX_execute_tasks();
399
400     while (not simix_global->process_to_run.empty()) {
401       XBT_DEBUG("New Sub-Schedule Round; size(queue)=%zu", simix_global->process_to_run.size());
402
403       /* Run all processes that are ready to run, possibly in parallel */
404       SIMIX_process_runall();
405
406       /* answer sequentially and in a fixed arbitrary order all the simcalls that were issued during that sub-round */
407
408       /* WARNING, the order *must* be fixed or you'll jeopardize the simulation reproducibility (see RR-7653) */
409
410       /* Here, the order is ok because:
411        *
412        *   Short proof: only maestro adds stuff to the process_to_run array, so the execution order of user contexts do
413        *   not impact its order.
414        *
415        *   Long proof: processes remain sorted through an arbitrary (implicit, complex but fixed) order in all cases.
416        *
417        *   - if there is no kill during the simulation, processes remain sorted according by their PID.
418        *     Rationale: This can be proved inductively.
419        *        Assume that process_to_run is sorted at a beginning of one round (it is at round 0: the deployment file
420        *        is parsed linearly).
421        *        Let's show that it is still so at the end of this round.
422        *        - if a process is added when being created, that's from maestro. It can be either at startup
423        *          time (and then in PID order), or in response to a process_create simcall. Since simcalls are handled
424        *          in arbitrary order (inductive hypothesis), we are fine.
425        *        - If a process is added because it's getting killed, its subsequent actions shouldn't matter
426        *        - If a process gets added to process_to_run because one of their blocking action constituting the meat
427        *          of a simcall terminates, we're still good. Proof:
428        *          - You are added from SIMIX_simcall_answer() only. When this function is called depends on the resource
429        *            kind (network, cpu, disk, whatever), but the same arguments hold. Let's take communications as an
430        *            example.
431        *          - For communications, this function is called from SIMIX_comm_finish().
432        *            This function itself don't mess with the order since simcalls are handled in FIFO order.
433        *            The function is called:
434        *            - before the comm starts (invalid parameters, or resource already dead or whatever).
435        *              The order then trivial holds since maestro didn't interrupt its handling of the simcall yet
436        *            - because the communication failed or were canceled after startup. In this case, it's called from
437        *              the function we are in, by the chunk:
438        *                       set = model->states.failed_action_set;
439        *                       while ((synchro = extract(set)))
440        *                          SIMIX_simcall_post((smx_synchro_t) synchro->data);
441        *              This order is also fixed because it depends of the order in which the surf actions were
442        *              added to the system, and only maestro can add stuff this way, through simcalls.
443        *              We thus use the inductive hypothesis once again to conclude that the order in which synchros are
444        *              poped out of the set does not depend on the user code's execution order.
445        *            - because the communication terminated. In this case, synchros are served in the order given by
446        *                       set = model->states.done_action_set;
447        *                       while ((synchro = extract(set)))
448        *                          SIMIX_simcall_post((smx_synchro_t) synchro->data);
449        *              and the argument is very similar to the previous one.
450        *            So, in any case, the orders of calls to SIMIX_comm_finish() do not depend on the order in which user
451        *            processes are executed.
452        *          So, in any cases, the orders of processes within process_to_run do not depend on the order in which
453        *          user processes were executed previously.
454        *     So, if there is no killing in the simulation, the simulation reproducibility is not jeopardized.
455        *   - If there is some process killings, the order is changed by this decision that comes from user-land
456        *     But this decision may not have been motivated by a situation that were different because the simulation is
457        *     not reproducible.
458        *     So, even the order change induced by the process killing is perfectly reproducible.
459        *
460        *   So science works, bitches [http://xkcd.com/54/].
461        *
462        *   We could sort the process_that_ran array completely so that we can describe the order in which simcalls are
463        *   handled (like "according to the PID of issuer"), but it's not mandatory (order is fixed already even if
464        *   unfriendly).
465        *   That would thus be a pure waste of time.
466        */
467
468       for (smx_actor_t const& process : simix_global->process_that_ran) {
469         if (process->simcall.call != SIMCALL_NONE) {
470           SIMIX_simcall_handle(&process->simcall, 0);
471         }
472       }
473
474       SIMIX_execute_tasks();
475       do {
476         SIMIX_wake_processes();
477       } while (SIMIX_execute_tasks());
478
479       /* If only daemon processes remain, cancel their actions, mark them to die and reschedule them */
480       if (simix_global->process_list.size() == simix_global->daemons.size())
481         for (auto const& dmon : simix_global->daemons) {
482           XBT_DEBUG("Kill %s", dmon->get_cname());
483           SIMIX_process_kill(dmon, simix_global->maestro_process);
484         }
485     }
486
487     time = SIMIX_timer_next();
488     if (time > -1.0 || not simix_global->process_list.empty()) {
489       XBT_DEBUG("Calling surf_solve");
490       time = surf_solve(time);
491       XBT_DEBUG("Moving time ahead : %g", time);
492     }
493
494     /* Notify all the hosts that have failed */
495     /* FIXME: iterate through the list of failed host and mark each of them */
496     /* as failed. On each host, signal all the running processes with host_fail */
497
498     // Execute timers and tasks until there isn't anything to be done:
499     bool again = false;
500     do {
501       again = SIMIX_execute_timers();
502       if (SIMIX_execute_tasks())
503         again = true;
504       SIMIX_wake_processes();
505     } while (again);
506
507     /* Autorestart all process */
508     for (auto const& host : host_that_restart) {
509       XBT_INFO("Restart processes on host %s", host->get_cname());
510       SIMIX_host_autorestart(host);
511     }
512     host_that_restart.clear();
513
514     /* Clean processes to destroy */
515     SIMIX_process_empty_trash();
516
517     XBT_DEBUG("### time %f, #processes %zu, #to_run %zu", time, simix_global->process_list.size(),
518               simix_global->process_to_run.size());
519
520     if (simix_global->process_to_run.empty() && not simix_global->process_list.empty())
521       simgrid::simix::onDeadlock();
522
523   } while (time > -1.0 || not simix_global->process_to_run.empty());
524
525   if (not simix_global->process_list.empty()) {
526
527     TRACE_end();
528
529     if (simix_global->process_list.size() <= simix_global->daemons.size()) {
530       XBT_CRITICAL("Oops! Daemon actors cannot do any blocking activity (communications, synchronization, etc) "
531                    "once the simulation is over. Please fix your on_exit() functions.");
532     } else {
533       XBT_CRITICAL("Oops! Deadlock or code not perfectly clean.");
534     }
535     SIMIX_display_process_status();
536     simgrid::s4u::onDeadlock();
537     xbt_abort();
538   }
539   simgrid::s4u::onSimulationEnd();
540 }
541
542 /**
543  *   \brief Set the date to execute a function
544  *
545  * Set the date to execute the function on the surf.
546  *   \param date Date to execute function
547  *   \param callback Function to be executed
548  *   \param arg Parameters of the function
549  *
550  */
551 smx_timer_t SIMIX_timer_set(double date, void (*callback)(void*), void *arg)
552 {
553   smx_timer_t timer = new s_smx_timer_t(date, simgrid::xbt::makeTask([callback, arg]() { callback(arg); }));
554   timer->handle_    = simix_timers.emplace(std::make_pair(date, timer));
555   return timer;
556 }
557
558 smx_timer_t SIMIX_timer_set(double date, simgrid::xbt::Task<void()> callback)
559 {
560   smx_timer_t timer = new s_smx_timer_t(date, std::move(callback));
561   timer->handle_    = simix_timers.emplace(std::make_pair(date, timer));
562   return timer;
563 }
564
565 /** @brief cancels a timer that was added earlier */
566 void SIMIX_timer_remove(smx_timer_t timer) {
567   simix_timers.erase(timer->handle_);
568   delete timer;
569 }
570
571 /** @brief Returns the date at which the timer will trigger (or 0 if nullptr timer) */
572 double SIMIX_timer_get_date(smx_timer_t timer) {
573   return timer ? timer->getDate() : 0;
574 }
575
576 /**
577  * \brief Registers a function to create a process.
578  *
579  * This function registers a function to be called
580  * when a new process is created. The function has
581  * to call SIMIX_process_create().
582  * \param function create process function
583  */
584 void SIMIX_function_register_process_create(smx_creation_func_t function)
585 {
586   simix_global->create_process_function = function;
587 }
588
589 /**
590  * \brief Registers a function to kill a process.
591  *
592  * This function registers a function to be called when a process is killed. The function has to call the
593  * SIMIX_process_kill().
594  *
595  * \param function Kill process function
596  */
597 void SIMIX_function_register_process_kill(void_pfn_smxprocess_t function)
598 {
599   simix_global->kill_process_function = function;
600 }
601
602 /**
603  * \brief Registers a function to cleanup a process.
604  *
605  * This function registers a user function to be called when a process ends properly.
606  *
607  * \param function cleanup process function
608  */
609 void SIMIX_function_register_process_cleanup(void_pfn_smxprocess_t function)
610 {
611   simix_global->cleanup_process_function = function;
612 }
613
614
615 void SIMIX_display_process_status()
616 {
617   int nbprocess = simix_global->process_list.size();
618
619   XBT_INFO("%d processes are still running, waiting for something.", nbprocess);
620   /*  List the process and their state */
621   XBT_INFO("Legend of the following listing: \"Process <pid> (<name>@<host>): <status>\"");
622   for (auto const& kv : simix_global->process_list) {
623     smx_actor_t process = kv.second;
624
625     if (process->waiting_synchro) {
626
627       const char* synchro_description = "unknown";
628
629       if (boost::dynamic_pointer_cast<simgrid::kernel::activity::ExecImpl>(process->waiting_synchro) != nullptr)
630         synchro_description = "execution";
631
632       if (boost::dynamic_pointer_cast<simgrid::kernel::activity::CommImpl>(process->waiting_synchro) != nullptr)
633         synchro_description = "communication";
634
635       if (boost::dynamic_pointer_cast<simgrid::kernel::activity::SleepImpl>(process->waiting_synchro) != nullptr)
636         synchro_description = "sleeping";
637
638       if (boost::dynamic_pointer_cast<simgrid::kernel::activity::RawImpl>(process->waiting_synchro) != nullptr)
639         synchro_description = "synchronization";
640
641       if (boost::dynamic_pointer_cast<simgrid::kernel::activity::IoImpl>(process->waiting_synchro) != nullptr)
642         synchro_description = "I/O";
643
644       XBT_INFO("Process %ld (%s@%s): waiting for %s synchro %p (%s) in state %d to finish", process->pid,
645                process->get_cname(), process->host->get_cname(), synchro_description, process->waiting_synchro.get(),
646                process->waiting_synchro->name.c_str(), (int)process->waiting_synchro->state);
647     }
648     else {
649       XBT_INFO("Process %ld (%s@%s)", process->pid, process->get_cname(), process->host->get_cname());
650     }
651   }
652 }
653
654 int SIMIX_is_maestro()
655 {
656   smx_actor_t self = SIMIX_process_self();
657   return simix_global == nullptr /*SimDag*/ || self == nullptr || self == simix_global->maestro_process;
658 }