Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
renaming value of presence state to "presence" (to get a good time-slice value later on)
[simgrid.git] / src / simix / smx_process.c
1 //*     $Id$     */
2
3 /* Copyright (c) 2002,2003,2004 Arnaud Legrand. All rights reserved.        */
4
5 /* This program is free software; you can redistribute it and/or modify it
6  * under the terms of the license (GNU LGPL) which comes with this package. */
7
8 #include "private.h"
9 #include "xbt/sysdep.h"
10 #include "xbt/log.h"
11 #include "xbt/dict.h"
12 #include "msg/mailbox.h"
13
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_process, simix,
15                                 "Logging specific to SIMIX (process)");
16
17 /**
18  * \brief Move a process to the list of process to destroy. *
19  */
20 void SIMIX_process_cleanup(void *arg)
21 {
22   xbt_swag_remove(arg, simix_global->process_to_run);
23   xbt_swag_remove(arg, simix_global->process_list);
24   xbt_swag_remove(arg, ((smx_process_t) arg)->smx_host->process_list);
25   xbt_swag_insert(arg, simix_global->process_to_destroy);
26 }
27
28 /** 
29  * Garbage collection
30  *
31  * Should be called some time to time to free the memory allocated for processes
32  * that have finished (or killed).
33  */
34 void SIMIX_process_empty_trash(void)
35 {
36   smx_process_t process = NULL;
37
38   while ((process = xbt_swag_extract(simix_global->process_to_destroy))) {
39     SIMIX_context_free(process->context);
40
41     /* Free the exception allocated at creation time */
42     if (process->exception)
43       free(process->exception);
44     if (process->properties)
45       xbt_dict_free(&process->properties);
46
47     free(process->name);
48     process->name = NULL;
49     free(process);
50   }
51 }
52
53 /**
54  * \brief Creates and runs the maestro process
55  */
56 void SIMIX_create_maestro_process()
57 {
58   smx_process_t process = NULL;
59   process = xbt_new0(s_smx_process_t, 1);
60
61   /* Process data */
62   process->name = (char *) "";
63
64   process->exception = xbt_new(ex_ctx_t, 1);
65   XBT_CTX_INITIALIZE(process->exception);
66
67   /* Create a dummy context for maestro */
68   process->context = SIMIX_context_new(NULL, 0, NULL, NULL, NULL);
69
70   /* Set it as the maestro process */
71   simix_global->maestro_process = process;
72   simix_global->current_process = process;
73
74   return;
75 }
76
77 /**
78  * \brief Creates and runs a new #smx_process_t.
79  *
80  * A constructor for #m_process_t taking four arguments and returning the corresponding object. The structure (and the corresponding thread) is created, and put in the list of ready process.
81  *
82  * \param name a name for the object. It is for user-level information and can be NULL.
83  * \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 NULL. It can be retrieved with the function \ref MSG_process_get_data.
84  * \param host the location where the new agent is executed.
85  * \param argc first argument passed to \a code
86  * \param argv second argument passed to \a code
87  * \param clean_process_function The cleanup function of user process. It will be called when the process finish. This function have to call the SIMIX_process_cleanup.
88  * \see smx_process_t
89  * \return The new corresponding object.
90  */
91 smx_process_t SIMIX_process_create(const char *name,
92                                    xbt_main_func_t code, void *data,
93                                    const char *hostname, int argc,
94                                    char **argv, xbt_dict_t properties)
95 {
96   smx_process_t process = NULL;
97   smx_host_t host = SIMIX_host_get_by_name(hostname);
98
99   DEBUG2("Start process %s on host %s", name, hostname);
100
101   if (!SIMIX_host_get_state(host)) {
102     WARN2("Cannot launch process '%s' on failed host '%s'", name, hostname);
103     return NULL;
104   }
105   process = xbt_new0(s_smx_process_t, 1);
106
107   xbt_assert0(((code != NULL) && (host != NULL)), "Invalid parameters");
108
109   /* Process data */
110   process->name = xbt_strdup(name);
111   process->smx_host = host;
112   process->mutex = NULL;
113   process->cond = NULL;
114   process->iwannadie = 0;
115   process->data = data;
116
117   VERB1("Create context %s", process->name);
118   process->context = SIMIX_context_new(code, argc, argv,
119                                        simix_global->cleanup_process_function,
120                                        process);
121
122   process->exception = xbt_new(ex_ctx_t, 1);
123   XBT_CTX_INITIALIZE(process->exception);
124
125   /* Add properties */
126   process->properties = properties;
127
128   /* Add the process to it's host process list */
129   xbt_swag_insert(process, host->process_list);
130
131   DEBUG1("Start context '%s'", process->name);
132
133   /* Now insert it in the global process list and in the process to run list */
134   xbt_swag_insert(process, simix_global->process_list);
135   DEBUG2("Inserting %s(%s) in the to_run list", process->name, host->name);
136   xbt_swag_insert(process, simix_global->process_to_run);
137
138   return process;
139 }
140
141 /** \brief Kill a SIMIX process
142  *
143  * This function simply kills a \a process... scarry isn't it ? :).
144  * \param process poor victim
145  *
146  */
147 void SIMIX_process_kill(smx_process_t process)
148 {
149   DEBUG2("Killing process %s on %s", process->name, process->smx_host->name);
150
151   process->iwannadie = 1;
152
153   /* If I'm killing myself then stop otherwise schedule the process to kill
154    * Two different behaviors, if I'm killing my self, remove from mutex and condition and stop. Otherwise, first we must schedule the process, wait its ending and after remove it from mutex and condition */
155   if (process == SIMIX_process_self()) {
156     /* Cleanup if we were waiting for something */
157     if (process->mutex)
158       xbt_swag_remove(process, process->mutex->sleeping);
159
160     if (process->cond)
161       xbt_swag_remove(process, process->cond->sleeping);
162     if (process->waiting_action) {
163       SIMIX_unregister_action_to_condition(process->waiting_action, process->cond);
164       SIMIX_action_destroy(process->waiting_action);
165     }
166
167     if (process->sem) {
168       xbt_swag_remove(process, process->sem->sleeping);
169
170       if (process->waiting_action) {
171         SIMIX_unregister_action_to_semaphore(process->waiting_action, process->sem);
172         SIMIX_action_destroy(process->waiting_action);
173       }
174     }
175
176     SIMIX_context_stop(process->context);
177
178   } else {
179     DEBUG4("%s(%p) here! killing %s(%p)",
180         simix_global->current_process->name,simix_global->current_process,
181         process->name,process);
182
183     /* Cleanup if it were waiting for something */
184     if (process->mutex) {
185       xbt_swag_remove(process, process->mutex->sleeping);
186       process->mutex = NULL;
187     }
188
189     if (process->cond) {
190       xbt_swag_remove(process, process->cond->sleeping);
191
192       if (process->waiting_action) {
193         SIMIX_unregister_action_to_condition(process->waiting_action, process->cond);
194         SIMIX_action_destroy(process->waiting_action);
195       }
196       process->cond = NULL;
197     }
198
199     if (process->sem) {
200         xbt_swag_remove(process, process->sem->sleeping);
201
202       if (process->waiting_action) {
203         SIMIX_unregister_action_to_semaphore(process->waiting_action, process->sem);
204         SIMIX_action_destroy(process->waiting_action);
205       }
206       process->sem = NULL;
207     }
208
209     /* make sure that the process gets awake soon enough, now that we've set its iwannadie to 1 */
210     process->blocked = 0;
211     process->suspended = 0;
212     xbt_swag_insert(process, simix_global->process_to_run);
213   }
214 }
215
216 /**
217  * \brief Return the user data of a #smx_process_t.
218  *
219  * This functions checks whether \a process is a valid pointer or not and return the user data associated to \a process if it is possible.
220  * \param process SIMIX process
221  * \return A void pointer to the user data
222  */
223 XBT_INLINE void *SIMIX_process_get_data(smx_process_t process)
224 {
225   xbt_assert0((process != NULL), "Invalid parameters");
226   return (process->data);
227 }
228
229 /**
230  * \brief Set the user data of a #m_process_t.
231  *
232  * This functions checks whether \a process is a valid pointer or not and set the user data associated to \a process if it is possible.
233  * \param process SIMIX process
234  * \param data User data
235  */
236 XBT_INLINE void SIMIX_process_set_data(smx_process_t process, void *data)
237 {
238   xbt_assert0((process != NULL), "Invalid parameters");
239
240   process->data = data;
241   return;
242 }
243
244 /**
245  * \brief Return the location on which an agent is running.
246  *
247  * This functions checks whether \a process is a valid pointer or not and return the m_host_t corresponding to the location on which \a process is running.
248  * \param process SIMIX process
249  * \return SIMIX host
250  */
251 XBT_INLINE smx_host_t SIMIX_process_get_host(smx_process_t process)
252 {
253   xbt_assert0((process != NULL), "Invalid parameters");
254   return (process->smx_host);
255 }
256
257 /**
258  * \brief Return the name of an agent.
259  *
260  * This functions checks whether \a process is a valid pointer or not and return its name.
261  * \param process SIMIX process
262  * \return The process name
263  */
264 XBT_INLINE const char *SIMIX_process_get_name(smx_process_t process)
265 {
266   xbt_assert0((process != NULL), "Invalid parameters");
267   return (process->name);
268 }
269
270 /**
271  * \brief Changes the name of an agent.
272  *
273  * This functions checks whether \a process is a valid pointer or not and return its name.
274  * \param process SIMIX process
275  * \param name The new process name
276  */
277 XBT_INLINE void SIMIX_process_set_name(smx_process_t process, char *name)
278 {
279   xbt_assert0((process != NULL), "Invalid parameters");
280   process->name = name;
281 }
282
283 /** \ingroup m_process_management
284  * \brief Return the properties
285  *
286  * This functions returns the properties associated with this process
287  */
288 XBT_INLINE xbt_dict_t SIMIX_process_get_properties(smx_process_t process)
289 {
290   return process->properties;
291 }
292
293 /**
294  * \brief Return the current agent.
295  *
296  * This functions returns the currently running #smx_process_t.
297  * \return The SIMIX process
298  */
299 XBT_INLINE smx_process_t SIMIX_process_self(void)
300 {
301   return simix_global ? simix_global->current_process : NULL;
302 }
303
304 /**
305  * \brief Suspend the process.
306  *
307  * This functions suspend the process by suspending the action on
308  * which it was waiting for the completion.
309  *
310  * \param process SIMIX process
311  */
312 void SIMIX_process_suspend(smx_process_t process)
313 {
314   xbt_assert0(process, "Invalid parameters");
315
316   if (process != SIMIX_process_self()) {
317
318     if (process->mutex) {
319       /* process blocked on a mutex or sem, only set suspend=1 */
320       process->suspended = 1;
321     } else if (process->cond) {
322       /* process blocked cond, suspend all actions */
323
324       /* temporaries variables */
325       smx_cond_t c;
326       xbt_fifo_item_t i;
327       smx_action_t act;
328
329       process->suspended = 1;
330       c = process->cond;
331       xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
332         SIMIX_action_suspend(act);
333       }
334     } else if (process->sem) {
335       smx_sem_t s;
336       xbt_fifo_item_t i;
337       smx_action_t act;
338
339       process->suspended = 1;
340       s = process->sem;
341       xbt_fifo_foreach(s->actions, i, act, smx_action_t) {
342         SIMIX_action_suspend(act);
343       }
344     } else {
345       process->suspended = 1;
346     }
347   } else {
348     /* process executing, I can create an action and suspend it */
349     smx_action_t dummy;
350     smx_cond_t cond;
351     char name[] = "dummy";
352     process->suspended = 1;
353
354     cond = SIMIX_cond_init();
355     dummy = SIMIX_action_execute(SIMIX_process_get_host(process), name, 0);
356     SIMIX_process_self()->waiting_action = dummy;
357     SIMIX_action_suspend(dummy);
358     SIMIX_register_action_to_condition(dummy, cond);
359     __SIMIX_cond_wait(cond);
360     SIMIX_process_self()->waiting_action = NULL;
361     SIMIX_unregister_action_to_condition(dummy, cond);
362     SIMIX_action_destroy(dummy);
363     SIMIX_cond_destroy(cond);
364   }
365   return;
366 }
367
368 /**
369  * \brief Resume a suspended process.
370  *
371  * This functions resume a suspended process by resuming the task on which it was waiting for the completion.
372  * \param process SIMIX process
373  */
374 void SIMIX_process_resume(smx_process_t process)
375 {
376   xbt_assert0((process != NULL), "Invalid parameters");
377   SIMIX_CHECK_HOST();
378
379   if (process == SIMIX_process_self())
380     return;
381
382   if (process->mutex) {
383     DEBUG0("Resume process blocked on a mutex or semaphore");
384     process->suspended = 0;     /* It'll wake up by itself when mutex releases */
385     return;
386   } else if (process->cond) {
387     /* temporaries variables */
388     smx_cond_t c;
389     xbt_fifo_item_t i;
390     smx_action_t act;
391     DEBUG0("Resume process blocked on a conditional");
392     process->suspended = 0;
393     c = process->cond;
394     xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
395       SIMIX_action_resume(act);
396     }
397     SIMIX_cond_signal(c);
398     return;
399   } else if (process->sem) {
400     /* temporaries variables */
401     smx_sem_t s;
402     xbt_fifo_item_t i;
403     smx_action_t act;
404     DEBUG0("Resume process blocked on a semaphore");
405     process->suspended = 0;
406     s = process->sem;
407     xbt_fifo_foreach(s->actions, i, act, smx_action_t) {
408       SIMIX_action_resume(act);
409     }
410     return;
411   } else {
412     process->suspended = 0;
413     xbt_swag_insert(process, simix_global->process_to_run);
414   }
415 }
416
417 /**
418  * \brief Migrates an agent to another location.
419  *
420  * This function changes the value of the host on which \a process is running.
421  */
422 void SIMIX_process_change_host(smx_process_t process, char *source,
423                                char *dest)
424 {
425   xbt_assert0((process != NULL), "Invalid parameters");
426   smx_host_t h1 = SIMIX_host_get_by_name(source);
427   smx_host_t h2 = SIMIX_host_get_by_name(dest);
428   process->smx_host = h2;
429   xbt_swag_remove(process, h1->process_list);
430   xbt_swag_insert(process, h2->process_list);
431 }
432
433 /**
434  * \brief Returns true if the process is suspended .
435  *
436  * This checks whether a process is suspended or not by inspecting the task on which it was waiting for the completion.
437  * \param process SIMIX process
438  * \return 1, if the process is suspended, else 0.
439  */
440 XBT_INLINE int SIMIX_process_is_suspended(smx_process_t process)
441 {
442   xbt_assert0((process != NULL), "Invalid parameters");
443
444   return (process->suspended);
445 }
446
447 /**
448  * \brief Returns the amount of SIMIX processes in the system
449  *
450  * Maestro internal process is not counted, only user code processes are
451  */
452 XBT_INLINE int SIMIX_process_count()
453 {
454   return xbt_swag_size(simix_global->process_list);
455 }
456
457 /** 
458  * Calling this function makes the process process to yield. The process
459  * that scheduled it returns from __SIMIX_process_schedule as if nothing
460  * had happened.
461  * 
462  * Only the processes can call this function, giving back the control
463  * to the maestro
464  */
465 void SIMIX_process_yield(void)
466 {
467   DEBUG1("Yield process '%s'", simix_global->current_process->name);
468   xbt_assert0((simix_global->current_process !=
469                simix_global->maestro_process),
470               "You are not supposed to run this function in maestro context!");
471
472
473   /* Go into sleep and return control to maestro */
474   SIMIX_context_suspend(simix_global->current_process->context);
475   /* Ok, maestro returned control to us */
476
477   if (simix_global->current_process->iwannadie)
478     SIMIX_context_stop(simix_global->current_process->context);
479 }
480
481 void SIMIX_process_schedule(smx_process_t new_process)
482 {
483   xbt_assert0(simix_global->current_process == simix_global->maestro_process,
484       "This function can only be called from maestro context");
485   DEBUG1("Scheduling context: '%s'", new_process->name);
486
487   /* update the current process */
488   simix_global->current_process = new_process;
489
490   /* schedule the context */
491   SIMIX_context_resume(new_process->context);
492   DEBUG1("Resumed from scheduling context: '%s'", new_process->name);
493
494   /* restore the current process to the previously saved process */
495   simix_global->current_process = simix_global->maestro_process;
496 }
497
498 /* callback: context fetching */
499 ex_ctx_t *SIMIX_process_get_exception(void)
500 {
501   return simix_global->current_process->exception;
502 }
503
504 /* callback: termination */
505 void SIMIX_process_exception_terminate(xbt_ex_t * e)
506 {
507   xbt_ex_display(e);
508   abort();
509 }