Logo AND Algorithmique Numérique Distribuée

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