Logo AND Algorithmique Numérique Distribuée

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