Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
de6db49f08c09d768d2371210b55919bb8951ec2
[simgrid.git] / src / simix / smx_process.cpp
1 /* Copyright (c) 2007-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 #include <boost/range/algorithm.hpp>
8
9 #include <xbt/functional.hpp>
10
11 #include "src/surf/surf_interface.hpp"
12 #include "smx_private.h"
13 #include "xbt/sysdep.h"
14 #include "xbt/log.h"
15 #include "xbt/dict.h"
16 #include "mc/mc.h"
17 #include "src/mc/mc_replay.h"
18 #include "src/mc/Client.hpp"
19 #include "src/msg/msg_private.h"
20
21 #include "src/simix/SynchroSleep.hpp"
22 #include "src/simix/SynchroRaw.hpp"
23 #include "src/simix/SynchroIo.hpp"
24
25 #ifdef HAVE_SMPI
26 #include "src/smpi/private.h"
27 #endif
28
29 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_process, simix, "Logging specific to SIMIX (process)");
30
31 unsigned long simix_process_maxpid = 0;
32
33 /** Increase the refcount for this process */
34 smx_process_t SIMIX_process_ref(smx_process_t process)
35 {
36   if (process != nullptr)
37     intrusive_ptr_add_ref(process);
38   return process;
39 }
40
41 /** Decrease the refcount for this process */
42 void SIMIX_process_unref(smx_process_t process)
43 {
44   if (process != nullptr)
45     intrusive_ptr_release(process);
46 }
47
48 /**
49  * \brief Returns the current agent.
50  *
51  * This functions returns the currently running SIMIX process.
52  *
53  * \return The SIMIX process
54  */
55 smx_process_t SIMIX_process_self(void)
56 {
57   smx_context_t self_context = SIMIX_context_self();
58
59   return self_context ? self_context->process() : nullptr;
60 }
61
62 /**
63  * \brief Returns whether a process has pending asynchronous communications.
64  * \return true if there are asynchronous communications in this process
65  */
66 int SIMIX_process_has_pending_comms(smx_process_t process) {
67
68   return xbt_fifo_size(process->comms) > 0;
69 }
70
71 /**
72  * \brief Moves a process to the list of processes to destroy.
73  */
74 void SIMIX_process_cleanup(smx_process_t process)
75 {
76   XBT_DEBUG("Cleanup process %s (%p), waiting synchro %p",
77       process->name.c_str(), process, process->waiting_synchro);
78
79   SIMIX_process_on_exit_runall(process);
80
81   /* Unregister from the kill timer if any */
82   if (process->kill_timer != nullptr)
83       SIMIX_timer_remove(process->kill_timer);
84
85   xbt_os_mutex_acquire(simix_global->mutex);
86
87   /* cancel non-blocking communications */
88   smx_synchro_t synchro;
89   while ((synchro = (smx_synchro_t) xbt_fifo_pop(process->comms))) {
90     simgrid::simix::Comm *comm = static_cast<simgrid::simix::Comm*>(synchro);
91
92     /* make sure no one will finish the comm after this process is destroyed,
93      * because src_proc or dst_proc would be an invalid pointer */
94     comm->cancel();
95
96     if (comm->src_proc == process) {
97       XBT_DEBUG("Found an unfinished send comm %p (detached = %d), state %d, src = %p, dst = %p",
98           comm, comm->detached, (int)comm->state, comm->src_proc, comm->dst_proc);
99       comm->src_proc = nullptr;
100
101       /* I'm not supposed to destroy a detached comm from the sender side, */
102       if (comm->detached)
103         XBT_DEBUG("Don't destroy it since it's a detached comm and I'm the sender");
104       else
105         comm->unref();
106
107     }
108     else if (comm->dst_proc == process){
109       XBT_DEBUG("Found an unfinished recv comm %p, state %d, src = %p, dst = %p",
110           comm, (int)comm->state, comm->src_proc, comm->dst_proc);
111       comm->dst_proc = nullptr;
112
113       if (comm->detached && comm->src_proc != nullptr) {
114         /* the comm will be freed right now, remove it from the sender */
115         xbt_fifo_remove(comm->src_proc->comms, comm);
116       }
117       
118       comm->unref();
119     } else {
120       xbt_die("Communication synchro %p is in my list but I'm not the sender nor the receiver", synchro);
121     }
122   }
123
124   XBT_DEBUG("%p should not be run anymore",process);
125   xbt_swag_remove(process, simix_global->process_list);
126   if (process->host)
127     xbt_swag_remove(process, sg_host_simix(process->host)->process_list);
128   xbt_swag_insert(process, simix_global->process_to_destroy);
129   process->context->iwannadie = 0;
130
131   xbt_os_mutex_release(simix_global->mutex);
132 }
133
134 /**
135  * Garbage collection
136  *
137  * Should be called some time to time to free the memory allocated for processes
138  * that have finished (or killed).
139  */
140 void SIMIX_process_empty_trash(void)
141 {
142   smx_process_t process = nullptr;
143
144   while ((process = (smx_process_t) xbt_swag_extract(simix_global->process_to_destroy))) {
145     XBT_DEBUG("Getting rid of %p",process);
146     intrusive_ptr_release(process);
147   }
148 }
149
150 namespace simgrid {
151 namespace simix {
152
153 Process::~Process()
154 {
155   delete this->context;
156   if (this->properties)
157     xbt_dict_free(&this->properties);
158   if (this->comms != nullptr)
159     xbt_fifo_free(this->comms);
160   if (this->on_exit)
161     xbt_dynar_free(&this->on_exit);
162 }
163
164 void create_maestro(std::function<void()> code)
165 {
166   smx_process_t maestro = nullptr;
167   /* Create maestro process and intilialize it */
168   maestro = new simgrid::simix::Process();
169   maestro->pid = simix_process_maxpid++;
170   maestro->ppid = -1;
171   maestro->name = "";
172   maestro->data = nullptr;
173
174   if (!code) {
175     maestro->context = SIMIX_context_new(std::function<void()>(), nullptr, maestro);
176   } else {
177     if (!simix_global)
178       xbt_die("simix is not initialized, please call MSG_init first");
179     maestro->context =
180       simix_global->context_factory->create_maestro(code, maestro);
181   }
182
183   maestro->simcall.issuer = maestro;
184   simix_global->maestro_process = maestro;
185 }
186
187 }
188 }
189
190 /**
191  * \brief Creates and runs the maestro process
192  */
193 void SIMIX_maestro_create(void (*code)(void*), void* data)
194 {
195   simgrid::simix::create_maestro(std::bind(code, data));
196 }
197
198 /**
199  * \brief Stops a process.
200  *
201  * Stops the process, execute all the registered on_exit functions,
202  * register it to the list of the process to restart if needed
203  * and stops its context.
204  */
205 void SIMIX_process_stop(smx_process_t arg) {
206   /* execute the on_exit functions */
207   SIMIX_process_on_exit_runall(arg);
208   /* Add the process to the list of process to restart, only if the host is down */
209   if (arg->auto_restart && arg->host->isOff()) {
210     SIMIX_host_add_auto_restart_process(arg->host, arg->name.c_str(),
211                                         arg->code, arg->data,
212                                         sg_host_get_name(arg->host),
213                                         SIMIX_timer_get_date(arg->kill_timer),
214                                         arg->properties,
215                                         arg->auto_restart);
216   }
217   XBT_DEBUG("Process %s (%s) is dead",
218     arg->name.c_str(), sg_host_get_name(arg->host));
219   arg->context->stop();
220 }
221
222 /**
223  * \brief Internal function to create a process.
224  *
225  * This function actually creates the process.
226  * It may be called when a SIMCALL_PROCESS_CREATE simcall occurs,
227  * or directly for SIMIX internal purposes. The sure thing is that it's called from maestro context.
228  *
229  * \return the process created
230  */
231 smx_process_t SIMIX_process_create(
232                           const char *name,
233                           std::function<void()> code,
234                           void *data,
235                           const char *hostname,
236                           double kill_time,
237                           xbt_dict_t properties,
238                           int auto_restart,
239                           smx_process_t parent_process)
240 {
241   smx_process_t process = nullptr;
242   sg_host_t host = sg_host_by_name(hostname);
243
244   XBT_DEBUG("Start process %s on host '%s'", name, hostname);
245
246   if (host->isOff()) {
247     XBT_WARN("Cannot launch process '%s' on failed host '%s'", name,
248           hostname);
249     return nullptr;
250   }
251   else {
252     process = new simgrid::simix::Process();
253
254     xbt_assert(code && host != nullptr, "Invalid parameters");
255     /* Process data */
256     process->pid = simix_process_maxpid++;
257     process->name = simgrid::xbt::string(name);
258     process->host = host;
259     process->data = data;
260     process->comms = xbt_fifo_new();
261     process->simcall.issuer = process;
262     /* Initiliaze data segment to default value */
263     SIMIX_segment_index_set(process, -1);
264
265      if (parent_process != nullptr) {
266        process->ppid = SIMIX_process_get_PID(parent_process);
267        /* SMPI process have their own data segment and
268           each other inherit from their father */
269 #if HAVE_SMPI
270        if(smpi_privatize_global_variables){
271          if( parent_process->pid != 0){
272            SIMIX_segment_index_set(process, parent_process->segment_index);
273          } else {
274            SIMIX_segment_index_set(process, process->pid - 1);
275          }
276        }
277 #endif
278      } else {
279        process->ppid = -1;
280      }
281
282     /* Process data for auto-restart */
283     process->auto_restart = auto_restart;
284     process->code = code;
285
286     XBT_VERB("Create context %s", process->name.c_str());
287     process->context = SIMIX_context_new(
288       std::move(code),
289       simix_global->cleanup_process_function, process);
290
291     /* Add properties */
292     process->properties = properties;
293
294     /* Add the process to it's host process list */
295     xbt_swag_insert(process, sg_host_simix(host)->process_list);
296
297     XBT_DEBUG("Start context '%s'", process->name.c_str());
298
299     /* Now insert it in the global process list and in the process to run list */
300     xbt_swag_insert(process, simix_global->process_list);
301     XBT_DEBUG("Inserting %s(%s) in the to_run list",
302       process->name.c_str(), sg_host_get_name(host));
303     xbt_dynar_push_as(simix_global->process_to_run, smx_process_t, process);
304
305     if (kill_time > SIMIX_get_clock() && simix_global->kill_process_function) {
306       XBT_DEBUG("Process %s(%s) will be kill at time %f",
307         process->name.c_str(), sg_host_get_name(process->host), kill_time);
308       process->kill_timer = SIMIX_timer_set(kill_time, [=]() {
309         simix_global->kill_process_function(process);
310       });
311     }
312
313     /* Tracing the process creation */
314     TRACE_msg_process_create(process->name.c_str(), process->pid, process->host);
315   }
316   return process;
317 }
318
319 smx_process_t SIMIX_process_attach(
320   const char* name,
321   void *data,
322   const char* hostname,
323   xbt_dict_t properties,
324   smx_process_t parent_process)
325 {
326   // This is mostly a copy/paste from SIMIX_process_new(),
327   // it'd be nice to share some code between those two functions.
328
329   sg_host_t host = sg_host_by_name(hostname);
330   XBT_DEBUG("Attach process %s on host '%s'", name, hostname);
331
332   if (host->isOff()) {
333     XBT_WARN("Cannot launch process '%s' on failed host '%s'",
334       name, hostname);
335     return nullptr;
336   }
337
338   smx_process_t process = new simgrid::simix::Process();
339   /* Process data */
340   process->pid = simix_process_maxpid++;
341   process->name = std::string(name);
342   process->host = host;
343   process->data = data;
344   process->comms = xbt_fifo_new();
345   process->simcall.issuer = process;
346   process->ppid = -1;
347   /* Initiliaze data segment to default value */
348   SIMIX_segment_index_set(process, -1);
349   if (parent_process != nullptr) {
350     process->ppid = SIMIX_process_get_PID(parent_process);
351    /* SMPI process have their own data segment and
352       each other inherit from their father */
353   #if HAVE_SMPI
354     if(smpi_privatize_global_variables){
355       if(parent_process->pid != 0){
356         SIMIX_segment_index_set(process, parent_process->segment_index);
357       } else {
358         SIMIX_segment_index_set(process, process->pid - 1);
359       }
360     }
361   #endif
362   }
363
364   /* Process data for auto-restart */
365   process->auto_restart = false;
366   process->code = nullptr;
367
368   XBT_VERB("Create context %s", process->name.c_str());
369   if (!simix_global)
370     xbt_die("simix is not initialized, please call MSG_init first");
371   process->context = simix_global->context_factory->attach(
372     simix_global->cleanup_process_function, process);
373
374   /* Add properties */
375   process->properties = properties;
376
377   /* Add the process to it's host process list */
378   xbt_swag_insert(process, sg_host_simix(host)->process_list);
379
380   /* Now insert it in the global process list and in the process to run list */
381   xbt_swag_insert(process, simix_global->process_list);
382   XBT_DEBUG("Inserting %s(%s) in the to_run list",
383     process->name.c_str(), sg_host_get_name(host));
384   xbt_dynar_push_as(simix_global->process_to_run, smx_process_t, process);
385
386   /* Tracing the process creation */
387   TRACE_msg_process_create(process->name.c_str(), process->pid, process->host);
388
389   auto context = dynamic_cast<simgrid::simix::AttachContext*>(process->context);
390   if (!context)
391     xbt_die("Not a suitable context");
392
393   context->attach_start();
394   return process;
395 }
396
397 void SIMIX_process_detach(void)
398 {
399   auto context = dynamic_cast<simgrid::simix::AttachContext*>(SIMIX_context_self());
400   if (!context)
401     xbt_die("Not a suitable context");
402
403   simix_global->cleanup_process_function(context->process());
404
405   // Let maestro ignore we are still alive:
406   // xbt_swag_remove(context->process(), simix_global->process_list);
407
408   // TODDO, Remove from proces list:
409   //   xbt_swag_remove(process, sg_host_simix(host)->process_list);
410
411   context->attach_stop();
412   // delete context;
413 }
414
415 /**
416  * \brief Executes the processes from simix_global->process_to_run.
417  *
418  * The processes of simix_global->process_to_run are run (in parallel if
419  * possible).  On exit, simix_global->process_to_run is empty, and
420  * simix_global->process_that_ran contains the list of processes that just ran.
421  * The two lists are swapped so, be careful when using them before and after a
422  * call to this function.
423  */
424 void SIMIX_process_runall(void)
425 {
426   SIMIX_context_runall();
427
428   xbt_dynar_t tmp = simix_global->process_that_ran;
429   simix_global->process_that_ran = simix_global->process_to_run;
430   simix_global->process_to_run = tmp;
431   xbt_dynar_reset(simix_global->process_to_run);
432 }
433
434 void simcall_HANDLER_process_kill(smx_simcall_t simcall, smx_process_t process) {
435   SIMIX_process_kill(process, simcall->issuer);
436 }
437 /**
438  * \brief Internal function to kill a SIMIX process.
439  *
440  * This function may be called when a SIMCALL_PROCESS_KILL simcall occurs,
441  * or directly for SIMIX internal purposes.
442  *
443  * \param process poor victim
444  * \param issuer the process which has sent the PROCESS_KILL. Important to not schedule twice the same process.
445  */
446 void SIMIX_process_kill(smx_process_t process, smx_process_t issuer) {
447
448   XBT_DEBUG("Killing process %s on %s",
449     process->name.c_str(), sg_host_get_name(process->host));
450
451   process->context->iwannadie = 1;
452   process->blocked = 0;
453   process->suspended = 0;
454   process->exception = nullptr;
455
456   /* destroy the blocking synchro if any */
457   if (process->waiting_synchro) {
458
459     simgrid::simix::Exec *exec = dynamic_cast<simgrid::simix::Exec*>(process->waiting_synchro);
460     simgrid::simix::Comm *comm = dynamic_cast<simgrid::simix::Comm*>(process->waiting_synchro);
461     simgrid::simix::Sleep *sleep = dynamic_cast<simgrid::simix::Sleep*>(process->waiting_synchro);
462     simgrid::simix::Raw *raw = dynamic_cast<simgrid::simix::Raw*>(process->waiting_synchro);
463     simgrid::simix::Io *io = dynamic_cast<simgrid::simix::Io*>(process->waiting_synchro);
464
465     if (exec != nullptr) {
466       exec->unref();
467
468     } else if (comm != nullptr) {
469       xbt_fifo_remove(process->comms, process->waiting_synchro);
470       comm->cancel();
471
472       // Remove first occurence of &process->simcall:
473       auto i = boost::range::find(
474         process->waiting_synchro->simcalls,
475         &process->simcall);
476       if (i != process->waiting_synchro->simcalls.end())
477         process->waiting_synchro->simcalls.remove(&process->simcall);
478
479       comm->unref();
480
481     } else if (sleep != nullptr) {
482       SIMIX_process_sleep_destroy(process->waiting_synchro);
483
484     } else if (raw != nullptr) {
485       SIMIX_synchro_stop_waiting(process, &process->simcall);
486       delete process->waiting_synchro;
487
488     } else if (io != nullptr) {
489       SIMIX_io_destroy(process->waiting_synchro);
490     }
491
492     /*
493     switch (process->waiting_synchro->type) {
494     case SIMIX_SYNC_JOIN:
495       SIMIX_process_sleep_destroy(process->waiting_synchro);
496       break;
497     } */
498
499     process->waiting_synchro = nullptr;
500   }
501   if(!xbt_dynar_member(simix_global->process_to_run, &(process)) && process != issuer) {
502     XBT_DEBUG("Inserting %s in the to_run list", process->name.c_str());
503     xbt_dynar_push_as(simix_global->process_to_run, smx_process_t, process);
504   }
505
506 }
507
508 /** @brief Ask another process to raise the given exception
509  *
510  * @param cat category of exception
511  * @param value value associated to the exception
512  * @param msg string information associated to the exception
513  */
514 void SIMIX_process_throw(smx_process_t process, xbt_errcat_t cat, int value, const char *msg) {
515   SMX_EXCEPTION(process, cat, value, msg);
516
517   if (process->suspended)
518     SIMIX_process_resume(process,SIMIX_process_self());
519
520   /* cancel the blocking synchro if any */
521   if (process->waiting_synchro) {
522
523     simgrid::simix::Exec *exec = dynamic_cast<simgrid::simix::Exec*>(process->waiting_synchro);
524     if (exec != nullptr) {
525       SIMIX_execution_cancel(process->waiting_synchro);
526     }
527
528     simgrid::simix::Comm *comm = dynamic_cast<simgrid::simix::Comm*>(process->waiting_synchro);
529     if (comm != nullptr) {
530       xbt_fifo_remove(process->comms, comm);
531       comm->cancel();
532     }
533
534     simgrid::simix::Sleep *sleep = dynamic_cast<simgrid::simix::Sleep*>(process->waiting_synchro);
535     if (sleep != nullptr) {
536       SIMIX_process_sleep_destroy(process->waiting_synchro);
537       if (!xbt_dynar_member(simix_global->process_to_run, &(process)) && process != SIMIX_process_self()) {
538         XBT_DEBUG("Inserting %s in the to_run list", process->name.c_str());
539         xbt_dynar_push_as(simix_global->process_to_run, smx_process_t, process);
540       }
541     }
542
543     simgrid::simix::Raw *raw = dynamic_cast<simgrid::simix::Raw*>(process->waiting_synchro);
544     if (raw != nullptr) {
545       SIMIX_synchro_stop_waiting(process, &process->simcall);
546     }
547
548     simgrid::simix::Io *io = dynamic_cast<simgrid::simix::Io*>(process->waiting_synchro);
549     if (io != nullptr) {
550       SIMIX_io_destroy(process->waiting_synchro);
551     }
552   }
553   process->waiting_synchro = nullptr;
554
555 }
556
557 void simcall_HANDLER_process_killall(smx_simcall_t simcall, int reset_pid) {
558   SIMIX_process_killall(simcall->issuer, reset_pid);
559 }
560 /**
561  * \brief Kills all running processes.
562  * \param issuer this one will not be killed
563  */
564 void SIMIX_process_killall(smx_process_t issuer, int reset_pid)
565 {
566   smx_process_t p = nullptr;
567
568   while ((p = (smx_process_t) xbt_swag_extract(simix_global->process_list))) {
569     if (p != issuer) {
570       SIMIX_process_kill(p,issuer);
571     }
572   }
573
574   if (reset_pid > 0)
575     simix_process_maxpid = reset_pid;
576
577   SIMIX_context_runall();
578
579   SIMIX_process_empty_trash();
580 }
581
582 void simcall_HANDLER_process_set_host(smx_simcall_t simcall, smx_process_t process, sg_host_t dest)
583 {
584   process->new_host = dest;
585 }
586 void SIMIX_process_change_host(smx_process_t process,
587              sg_host_t dest)
588 {
589   xbt_assert((process != nullptr), "Invalid parameters");
590   xbt_swag_remove(process, sg_host_simix(process->host)->process_list);
591   process->host = dest;
592   xbt_swag_insert(process, sg_host_simix(dest)->process_list);
593 }
594
595
596 void simcall_HANDLER_process_suspend(smx_simcall_t simcall, smx_process_t process)
597 {
598   smx_synchro_t sync_suspend = SIMIX_process_suspend(process, simcall->issuer);
599
600   if (process != simcall->issuer) {
601     SIMIX_simcall_answer(simcall);
602   } else {
603     sync_suspend->simcalls.push_back(simcall);
604     process->waiting_synchro = sync_suspend;
605     process->waiting_synchro->suspend();
606   }
607   /* If we are suspending ourselves, then just do not finish the simcall now */
608 }
609
610 smx_synchro_t SIMIX_process_suspend(smx_process_t process, smx_process_t issuer)
611 {
612   if (process->suspended) {
613     XBT_DEBUG("Process '%s' is already suspended", process->name.c_str());
614     return nullptr;
615   }
616
617   process->suspended = 1;
618
619   /* If we are suspending another process that is waiting on a sync, suspend its synchronization. */
620   if (process != issuer) {
621
622     if (process->waiting_synchro)
623       process->waiting_synchro->suspend();
624     /* If the other process is not waiting, its suspension is delayed to when the process is rescheduled. */
625
626     return nullptr;
627   } else {
628     /* FIXME: computation size is zero. Is it okay that bound is zero ? */
629     return SIMIX_execution_start(process, "suspend", 0.0, 1.0, 0.0, 0);
630   }
631 }
632
633 void simcall_HANDLER_process_resume(smx_simcall_t simcall, smx_process_t process){
634   SIMIX_process_resume(process, simcall->issuer);
635 }
636
637 void SIMIX_process_resume(smx_process_t process, smx_process_t issuer)
638 {
639   XBT_IN("process = %p, issuer = %p", process, issuer);
640
641   if(process->context->iwannadie) {
642     XBT_VERB("Ignoring request to suspend a process that is currently dying.");
643     return;
644   }
645
646   if(!process->suspended) return;
647   process->suspended = 0;
648
649   /* If we are resuming another process, resume the synchronization it was waiting for
650      if any. Otherwise add it to the list of process to run in the next round. */
651   if (process != issuer) {
652
653     if (process->waiting_synchro) {
654       process->waiting_synchro->resume();
655     }
656   } else XBT_WARN("Strange. Process %p is trying to resume himself.", issuer);
657
658   XBT_OUT();
659 }
660
661 int SIMIX_process_get_maxpid(void) {
662   return simix_process_maxpid;
663 }
664
665 int SIMIX_process_count(void)
666 {
667   return xbt_swag_size(simix_global->process_list);
668 }
669
670 int SIMIX_process_get_PID(smx_process_t self){
671   if (self == nullptr)
672     return 0;
673   else
674     return self->pid;
675 }
676
677 int SIMIX_process_get_PPID(smx_process_t self){
678   if (self == nullptr)
679     return 0;
680   else
681     return self->ppid;
682 }
683
684 void* SIMIX_process_self_get_data()
685 {
686   smx_process_t self = SIMIX_process_self();
687
688   if (!self) {
689     return nullptr;
690   }
691   return SIMIX_process_get_data(self);
692 }
693
694 void SIMIX_process_self_set_data(void *data)
695 {
696   smx_process_t self = SIMIX_process_self();
697
698   SIMIX_process_set_data(self, data);
699 }
700
701 void* SIMIX_process_get_data(smx_process_t process)
702 {
703   return process->data;
704 }
705
706 void SIMIX_process_set_data(smx_process_t process, void *data)
707 {
708   process->data = data;
709 }
710
711 sg_host_t SIMIX_process_get_host(smx_process_t process)
712 {
713   return process->host;
714 }
715
716 /* needs to be public and without simcall because it is called
717    by exceptions and logging events */
718 const char* SIMIX_process_self_get_name(void) {
719
720   smx_process_t process = SIMIX_process_self();
721   if (process == nullptr || process == simix_global->maestro_process)
722     return "maestro";
723
724   return SIMIX_process_get_name(process);
725 }
726
727 const char* SIMIX_process_get_name(smx_process_t process)
728 {
729   return process->name.c_str();
730 }
731
732 smx_process_t SIMIX_process_get_by_name(const char* name)
733 {
734   smx_process_t proc;
735   xbt_swag_foreach(proc, simix_global->process_list) {
736     if (proc->name == name)
737       return proc;
738   }
739   return nullptr;
740 }
741
742 int SIMIX_process_is_suspended(smx_process_t process)
743 {
744   return process->suspended;
745 }
746
747 xbt_dict_t SIMIX_process_get_properties(smx_process_t process)
748 {
749   return process->properties;
750 }
751
752 void simcall_HANDLER_process_join(smx_simcall_t simcall, smx_process_t process, double timeout)
753 {
754   smx_synchro_t sync = SIMIX_process_join(simcall->issuer, process, timeout);
755   sync->simcalls.push_back(simcall);
756   simcall->issuer->waiting_synchro = sync;
757 }
758
759 static int SIMIX_process_join_finish(smx_process_exit_status_t status, smx_synchro_t synchro){
760   simgrid::simix::Sleep *sleep = static_cast<simgrid::simix::Sleep*>(synchro);
761
762   if (sleep->surf_sleep) {
763     sleep->surf_sleep->cancel();
764
765     while (!sleep->simcalls.empty()) {
766       smx_simcall_t simcall = sleep->simcalls.front();
767       sleep->simcalls.pop_front();
768       simcall_process_sleep__set__result(simcall, SIMIX_DONE);
769       simcall->issuer->waiting_synchro = nullptr;
770       if (simcall->issuer->suspended) {
771         XBT_DEBUG("Wait! This process is suspended and can't wake up now.");
772         simcall->issuer->suspended = 0;
773         simcall_HANDLER_process_suspend(simcall, simcall->issuer);
774       } else {
775         SIMIX_simcall_answer(simcall);
776       }
777     }
778     sleep->surf_sleep->unref();
779     sleep->surf_sleep = nullptr;
780   }
781   delete sleep;
782   return 0;
783 }
784
785 smx_synchro_t SIMIX_process_join(smx_process_t issuer, smx_process_t process, double timeout)
786 {
787   smx_synchro_t res = SIMIX_process_sleep(issuer, timeout);
788   SIMIX_process_on_exit(process, (int_f_pvoid_pvoid_t)SIMIX_process_join_finish, res);
789   return res;
790 }
791
792 void simcall_HANDLER_process_sleep(smx_simcall_t simcall, double duration)
793 {
794   if (MC_is_active() || MC_record_replay_is_active()) {
795     MC_process_clock_add(simcall->issuer, duration);
796     simcall_process_sleep__set__result(simcall, SIMIX_DONE);
797     SIMIX_simcall_answer(simcall);
798     return;
799   }
800   smx_synchro_t sync = SIMIX_process_sleep(simcall->issuer, duration);
801   sync->simcalls.push_back(simcall);
802   simcall->issuer->waiting_synchro = sync;
803 }
804
805 smx_synchro_t SIMIX_process_sleep(smx_process_t process, double duration)
806 {
807   sg_host_t host = process->host;
808
809   /* check if the host is active */
810   if (host->isOff())
811     THROWF(host_error, 0, "Host %s failed, you cannot call this function", sg_host_get_name(host));
812
813   simgrid::simix::Sleep *synchro = new simgrid::simix::Sleep();
814   synchro->host = host;
815   synchro->surf_sleep = surf_host_sleep(host, duration);
816   synchro->surf_sleep->setData(synchro);
817   XBT_DEBUG("Create sleep synchronization %p", synchro);
818
819   return synchro;
820 }
821
822 void SIMIX_process_sleep_destroy(smx_synchro_t synchro)
823 {
824   XBT_DEBUG("Destroy synchro %p", synchro);
825   simgrid::simix::Sleep *sleep = static_cast<simgrid::simix::Sleep*>(synchro);
826
827   if (sleep->surf_sleep) {
828     sleep->surf_sleep->unref();
829     sleep->surf_sleep = nullptr;
830   }
831 }
832
833 /**
834  * \brief Calling this function makes the process to yield.
835  *
836  * Only the current process can call this function, giving back the control to
837  * maestro.
838  *
839  * \param self the current process
840  */
841 void SIMIX_process_yield(smx_process_t self)
842 {
843   XBT_DEBUG("Yield process '%s'", self->name.c_str());
844
845   /* Go into sleep and return control to maestro */
846   self->context->suspend();
847
848   /* Ok, maestro returned control to us */
849   XBT_DEBUG("Control returned to me: '%s'", self->name.c_str());
850
851   if (self->new_host) {
852     SIMIX_process_change_host(self, self->new_host);
853     self->new_host = nullptr;
854   }
855
856   if (self->context->iwannadie){
857     XBT_DEBUG("I wanna die!");
858     SIMIX_process_stop(self);
859   }
860
861   if (self->suspended) {
862     XBT_DEBUG("Hey! I'm suspended.");
863     xbt_assert(self->exception != nullptr, "Gasp! This exception may be lost by subsequent calls.");
864     self->suspended = 0;
865     SIMIX_process_suspend(self, self);
866   }
867
868   if (self->exception != nullptr) {
869     XBT_DEBUG("Wait, maestro left me an exception");
870     std::exception_ptr exception = std::move(self->exception);
871     self->exception = nullptr;
872     std::rethrow_exception(std::move(exception));
873   }
874
875   if(SMPI_switch_data_segment && self->segment_index != -1){
876     SMPI_switch_data_segment(self->segment_index);
877   }
878 }
879
880 /* callback: termination */
881 void SIMIX_process_exception_terminate(xbt_ex_t * e)
882 {
883   xbt_ex_display(e);
884   xbt_abort();
885 }
886
887 smx_context_t SIMIX_process_get_context(smx_process_t p) {
888   return p->context;
889 }
890
891 void SIMIX_process_set_context(smx_process_t p,smx_context_t c) {
892   p->context = c;
893 }
894
895 /**
896  * \brief Returns the list of processes to run.
897  */
898 xbt_dynar_t SIMIX_process_get_runnable(void)
899 {
900   return simix_global->process_to_run;
901 }
902
903 /**
904  * \brief Returns the process from PID.
905  */
906 smx_process_t SIMIX_process_from_PID(int PID)
907 {
908   smx_process_t proc;
909   xbt_swag_foreach(proc, simix_global->process_list) {
910    if (proc->pid == (unsigned long) PID)
911     return proc;
912   }
913   return nullptr;
914 }
915
916 /** @brief returns a dynar containg all currently existing processes */
917 xbt_dynar_t SIMIX_processes_as_dynar(void) {
918   smx_process_t proc;
919   xbt_dynar_t res = xbt_dynar_new(sizeof(smx_process_t),nullptr);
920   xbt_swag_foreach(proc, simix_global->process_list) {
921     xbt_dynar_push(res,&proc);
922   }
923   return res;
924 }
925
926
927 void SIMIX_process_on_exit_runall(smx_process_t process) {
928   s_smx_process_exit_fun_t exit_fun;
929   smx_process_exit_status_t exit_status = (process->context->iwannadie) ?
930                                          SMX_EXIT_FAILURE : SMX_EXIT_SUCCESS;
931   while (!xbt_dynar_is_empty(process->on_exit)) {
932     exit_fun = xbt_dynar_pop_as(process->on_exit,s_smx_process_exit_fun_t);
933     (exit_fun.fun)((void*)exit_status, exit_fun.arg);
934   }
935 }
936
937 void SIMIX_process_on_exit(smx_process_t process, int_f_pvoid_pvoid_t fun, void *data) {
938   xbt_assert(process, "current process not found: are you in maestro context ?");
939
940   if (!process->on_exit) {
941     process->on_exit = xbt_dynar_new(sizeof(s_smx_process_exit_fun_t), nullptr);
942   }
943
944   s_smx_process_exit_fun_t exit_fun = {fun, data};
945
946   xbt_dynar_push_as(process->on_exit,s_smx_process_exit_fun_t,exit_fun);
947 }
948
949 /**
950  * \brief Sets the auto-restart status of the process.
951  * If set to 1, the process will be automatically restarted when its host
952  * comes back.
953  */
954 void SIMIX_process_auto_restart_set(smx_process_t process, int auto_restart) {
955   process->auto_restart = auto_restart;
956 }
957
958 smx_process_t simcall_HANDLER_process_restart(smx_simcall_t simcall, smx_process_t process) {
959   return SIMIX_process_restart(process, simcall->issuer);
960 }
961 /** @brief Restart a process, starting it again from the beginning. */
962 smx_process_t SIMIX_process_restart(smx_process_t process, smx_process_t issuer) {
963   XBT_DEBUG("Restarting process %s on %s",
964     process->name.c_str(), sg_host_get_name(process->host));
965
966   //retrieve the arguments of the old process
967   //FIXME: Factorize this with SIMIX_host_add_auto_restart_process ?
968   simgrid::simix::ProcessArg arg;
969   arg.name = process->name;
970   arg.code = process->code;
971   arg.hostname = sg_host_get_name(process->host);
972   arg.kill_time = SIMIX_timer_get_date(process->kill_timer);
973   arg.data = process->data;
974   arg.properties = nullptr;
975   arg.auto_restart = process->auto_restart;
976
977   //kill the old process
978   SIMIX_process_kill(process, issuer);
979
980   //start the new process
981   if (simix_global->create_process_function)
982     return simix_global->create_process_function(
983       arg.name.c_str(), std::move(arg.code), arg.data,
984       arg.hostname, arg.kill_time,
985       arg.properties, arg.auto_restart,
986       nullptr);
987   else
988     return simcall_process_create(
989       arg.name.c_str(), std::move(arg.code), arg.data,
990       arg.hostname, arg.kill_time,
991       arg.properties, arg.auto_restart);
992 }
993
994 void SIMIX_segment_index_set(smx_process_t proc, int index){
995   proc->segment_index = index;
996 }
997
998 /**
999  * \ingroup simix_process_management
1000  * \brief Creates and runs a new SIMIX process.
1001  *
1002  * The structure and the corresponding thread are created and put in the list of ready processes.
1003  *
1004  * \param name a name for the process. It is for user-level information and can be nullptr.
1005  * \param code the main function of the process
1006  * \param data a pointer to any data one may want to attach to the new object. It is for user-level information and can be nullptr.
1007  * It can be retrieved with the function \ref simcall_process_get_data.
1008  * \param hostname name of the host where the new agent is executed.
1009  * \param kill_time time when the process is killed
1010  * \param argc first argument passed to \a code
1011  * \param argv second argument passed to \a code
1012  * \param properties the properties of the process
1013  * \param auto_restart either it is autorestarting or not.
1014  */
1015 smx_process_t simcall_process_create(const char *name,
1016                               xbt_main_func_t code,
1017                               void *data,
1018                               const char *hostname,
1019                               double kill_time,
1020                               int argc, char **argv,
1021                               xbt_dict_t properties,
1022                               int auto_restart)
1023 {
1024   if (name == nullptr)
1025     name = "";
1026   auto wrapped_code = simgrid::xbt::wrapMain(code, argc, argv);
1027   for (int i = 0; i != argc; ++i)
1028     xbt_free(argv[i]);
1029   xbt_free(argv);
1030   smx_process_t res = simcall_process_create(name,
1031     std::move(wrapped_code),
1032     data, hostname, kill_time, properties, auto_restart);
1033   return res;
1034 }
1035
1036 smx_process_t simcall_process_create(
1037   const char *name, std::function<void()> code, void *data,
1038   const char *hostname, double kill_time,
1039   xbt_dict_t properties, int auto_restart)
1040 {
1041   if (name == nullptr)
1042     name = "";
1043   smx_process_t self = SIMIX_process_self();
1044   return simgrid::simix::kernelImmediate([&] {
1045     return SIMIX_process_create(name,
1046           std::move(code), data, hostname,
1047           kill_time, properties, auto_restart,
1048           self);
1049   });
1050 }