Logo AND Algorithmique Numérique Distribuée

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