Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
f3096b92f58fece4bb325739be9ad61ac718483f
[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, hostname);
102     return NULL;
103   }
104   process = xbt_new0(s_smx_process_t, 1);
105
106   xbt_assert0(((code != NULL) && (host != NULL)), "Invalid parameters");
107
108   /* Process data */
109   process->name = xbt_strdup(name);
110   process->smx_host = host;
111   process->mutex = NULL;
112   process->cond = NULL;
113   process->iwannadie = 0;
114   process->data = data;
115
116   VERB1("Create context %s", process->name);
117   process->context = SIMIX_context_new(code, argc, argv,
118                                        simix_global->cleanup_process_function,
119                                        process);
120
121   process->exception = xbt_new(ex_ctx_t, 1);
122   XBT_CTX_INITIALIZE(process->exception);
123
124   /* Add properties */
125   process->properties = properties;
126
127   /* Add the process to it's host process list */
128   xbt_swag_insert(process, host->process_list);
129
130   DEBUG1("Start context '%s'", process->name);
131
132   /* Now insert it in the global process list and in the process to run list */
133   xbt_swag_insert(process, simix_global->process_list);
134   DEBUG2("Inserting %s(%s) in the to_run list", process->name, host->name);
135   xbt_swag_insert(process, simix_global->process_to_run);
136
137   return process;
138 }
139
140 /** \brief Kill a SIMIX process
141  *
142  * This function simply kills a \a process... scarry isn't it ? :).
143  * \param process poor victim
144  *
145  */
146 void SIMIX_process_kill(smx_process_t process)
147 {
148   DEBUG2("Killing process %s on %s", process->name, process->smx_host->name);
149
150   process->iwannadie = 1;
151
152   /* If I'm killing myself then stop otherwise schedule the process to kill
153    * 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 */
154   if (process == SIMIX_process_self()) {
155     /* Cleanup if we were waiting for something */
156     if (process->mutex)
157       xbt_swag_remove(process, process->mutex->sleeping);
158
159     if (process->cond)
160       xbt_swag_remove(process, process->cond->sleeping);
161     if (process->waiting_action) {
162       SIMIX_unregister_action_to_condition(process->waiting_action, process->cond);
163       SIMIX_action_destroy(process->waiting_action);
164     }
165
166     if (process->sem) {
167       xbt_swag_remove(process, process->sem->sleeping);
168
169       if (process->waiting_action) {
170         SIMIX_unregister_action_to_semaphore(process->waiting_action, process->sem);
171         SIMIX_action_destroy(process->waiting_action);
172       }
173     }
174
175     SIMIX_context_stop(process->context);
176
177   } else {
178     DEBUG4("%s(%p) here! killing %s(%p)",
179         simix_global->current_process->name,simix_global->current_process,
180         process->name,process);
181
182     /* Cleanup if it were waiting for something */
183     if (process->mutex) {
184       xbt_swag_remove(process, process->mutex->sleeping);
185       process->mutex = NULL;
186     }
187
188     if (process->cond) {
189       xbt_swag_remove(process, process->cond->sleeping);
190
191       if (process->waiting_action) {
192         SIMIX_unregister_action_to_condition(process->waiting_action, process->cond);
193         SIMIX_action_destroy(process->waiting_action);
194       }
195       process->cond = NULL;
196     }
197
198     if (process->sem) {
199         xbt_swag_remove(process, process->sem->sleeping);
200
201       if (process->waiting_action) {
202         SIMIX_unregister_action_to_semaphore(process->waiting_action, process->sem);
203         SIMIX_action_destroy(process->waiting_action);
204       }
205       process->sem = NULL;
206     }
207
208     /* make sure that the process gets awake soon enough, now that we've set its iwannadie to 1 */
209     process->blocked = 0;
210     process->suspended = 0;
211     xbt_swag_insert(process, simix_global->process_to_run);
212   }
213 }
214
215 /**
216  * \brief Return the user data of a #smx_process_t.
217  *
218  * 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.
219  * \param process SIMIX process
220  * \return A void pointer to the user data
221  */
222 XBT_INLINE void *SIMIX_process_get_data(smx_process_t process)
223 {
224   xbt_assert0((process != NULL), "Invalid parameters");
225   return (process->data);
226 }
227
228 /**
229  * \brief Set the user data of a #m_process_t.
230  *
231  * 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.
232  * \param process SIMIX process
233  * \param data User data
234  */
235 XBT_INLINE void SIMIX_process_set_data(smx_process_t process, void *data)
236 {
237   xbt_assert0((process != NULL), "Invalid parameters");
238
239   process->data = data;
240   return;
241 }
242
243 /**
244  * \brief Return the location on which an agent is running.
245  *
246  * 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.
247  * \param process SIMIX process
248  * \return SIMIX host
249  */
250 XBT_INLINE smx_host_t SIMIX_process_get_host(smx_process_t process)
251 {
252   xbt_assert0((process != NULL), "Invalid parameters");
253   return (process->smx_host);
254 }
255
256 /**
257  * \brief Return the name of an agent.
258  *
259  * This functions checks whether \a process is a valid pointer or not and return its name.
260  * \param process SIMIX process
261  * \return The process name
262  */
263 XBT_INLINE const char *SIMIX_process_get_name(smx_process_t process)
264 {
265   xbt_assert0((process != NULL), "Invalid parameters");
266   return (process->name);
267 }
268
269 /**
270  * \brief Changes the name of an agent.
271  *
272  * This functions checks whether \a process is a valid pointer or not and return its name.
273  * \param process SIMIX process
274  * \param name The new process name
275  */
276 XBT_INLINE void SIMIX_process_set_name(smx_process_t process, char *name)
277 {
278   xbt_assert0((process != NULL), "Invalid parameters");
279   process->name = name;
280 }
281
282 /** \ingroup m_process_management
283  * \brief Return the properties
284  *
285  * This functions returns the properties associated with this process
286  */
287 XBT_INLINE xbt_dict_t SIMIX_process_get_properties(smx_process_t process)
288 {
289   return process->properties;
290 }
291
292 /**
293  * \brief Return the current agent.
294  *
295  * This functions returns the currently running #smx_process_t.
296  * \return The SIMIX process
297  */
298 XBT_INLINE smx_process_t SIMIX_process_self(void)
299 {
300   return simix_global ? simix_global->current_process : NULL;
301 }
302
303 /**
304  * \brief Suspend the process.
305  *
306  * This functions suspend the process by suspending the action on
307  * which it was waiting for the completion.
308  *
309  * \param process SIMIX process
310  */
311 void SIMIX_process_suspend(smx_process_t process)
312 {
313   xbt_assert0(process, "Invalid parameters");
314
315   if (process != SIMIX_process_self()) {
316
317     if (process->mutex) {
318       /* process blocked on a mutex or sem, only set suspend=1 */
319       process->suspended = 1;
320     } else if (process->cond) {
321       /* process blocked cond, suspend all actions */
322
323       /* temporaries variables */
324       smx_cond_t c;
325       xbt_fifo_item_t i;
326       smx_action_t act;
327
328       process->suspended = 1;
329       c = process->cond;
330       xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
331         SIMIX_action_suspend(act);
332       }
333     } else if (process->sem) {
334       smx_sem_t s;
335       xbt_fifo_item_t i;
336       smx_action_t act;
337
338       process->suspended = 1;
339       s = process->sem;
340       xbt_fifo_foreach(s->actions, i, act, smx_action_t) {
341         SIMIX_action_suspend(act);
342       }
343     } else {
344       process->suspended = 1;
345     }
346   } else {
347     /* process executing, I can create an action and suspend it */
348     smx_action_t dummy;
349     smx_cond_t cond;
350     char name[] = "dummy";
351     process->suspended = 1;
352
353     cond = SIMIX_cond_init();
354     dummy = SIMIX_action_execute(SIMIX_process_get_host(process), name, 0);
355     SIMIX_process_self()->waiting_action = dummy;
356     SIMIX_action_suspend(dummy);
357     SIMIX_register_action_to_condition(dummy, cond);
358     __SIMIX_cond_wait(cond);
359     SIMIX_process_self()->waiting_action = NULL;
360     SIMIX_unregister_action_to_condition(dummy, cond);
361     SIMIX_action_destroy(dummy);
362     SIMIX_cond_destroy(cond);
363   }
364   return;
365 }
366
367 /**
368  * \brief Resume a suspended process.
369  *
370  * This functions resume a suspended process by resuming the task on which it was waiting for the completion.
371  * \param process SIMIX process
372  */
373 void SIMIX_process_resume(smx_process_t process)
374 {
375   xbt_assert0((process != NULL), "Invalid parameters");
376   SIMIX_CHECK_HOST();
377
378   if (process == SIMIX_process_self())
379     return;
380
381   if (process->mutex) {
382     DEBUG0("Resume process blocked on a mutex or semaphore");
383     process->suspended = 0;     /* It'll wake up by itself when mutex releases */
384     return;
385   } else if (process->cond) {
386     /* temporaries variables */
387     smx_cond_t c;
388     xbt_fifo_item_t i;
389     smx_action_t act;
390     DEBUG0("Resume process blocked on a conditional");
391     process->suspended = 0;
392     c = process->cond;
393     xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
394       SIMIX_action_resume(act);
395     }
396     SIMIX_cond_signal(c);
397     return;
398   } else if (process->sem) {
399     /* temporaries variables */
400     smx_sem_t s;
401     xbt_fifo_item_t i;
402     smx_action_t act;
403     DEBUG0("Resume process blocked on a semaphore");
404     process->suspended = 0;
405     s = process->sem;
406     xbt_fifo_foreach(s->actions, i, act, smx_action_t) {
407       SIMIX_action_resume(act);
408     }
409     return;
410   } else {
411     process->suspended = 0;
412     xbt_swag_insert(process, simix_global->process_to_run);
413   }
414 }
415
416 /**
417  * \brief Migrates an agent to another location.
418  *
419  * This function changes the value of the host on which \a process is running.
420  */
421 void SIMIX_process_change_host(smx_process_t process, char *source,
422                                char *dest)
423 {
424   xbt_assert0((process != NULL), "Invalid parameters");
425   smx_host_t h1 = SIMIX_host_get_by_name(source);
426   smx_host_t h2 = SIMIX_host_get_by_name(dest);
427   process->smx_host = h2;
428   xbt_swag_remove(process, h1->process_list);
429   xbt_swag_insert(process, h2->process_list);
430 }
431
432 /**
433  * \brief Returns true if the process is suspended .
434  *
435  * This checks whether a process is suspended or not by inspecting the task on which it was waiting for the completion.
436  * \param process SIMIX process
437  * \return 1, if the process is suspended, else 0.
438  */
439 XBT_INLINE int SIMIX_process_is_suspended(smx_process_t process)
440 {
441   xbt_assert0((process != NULL), "Invalid parameters");
442
443   return (process->suspended);
444 }
445
446 /**
447  * \brief Returns the amount of SIMIX processes in the system
448  *
449  * Maestro internal process is not counted, only user code processes are
450  */
451 XBT_INLINE int SIMIX_process_count()
452 {
453   return xbt_swag_size(simix_global->process_list);
454 }
455
456 /** 
457  * Calling this function makes the process process to yield. The process
458  * that scheduled it returns from __SIMIX_process_schedule as if nothing
459  * had happened.
460  * 
461  * Only the processes can call this function, giving back the control
462  * to the maestro
463  */
464 void SIMIX_process_yield(void)
465 {
466   DEBUG1("Yield process '%s'", simix_global->current_process->name);
467   xbt_assert0((simix_global->current_process !=
468                simix_global->maestro_process),
469               "You are not supposed to run this function in maestro context!");
470
471
472   /* Go into sleep and return control to maestro */
473   SIMIX_context_suspend(simix_global->current_process->context);
474   /* Ok, maestro returned control to us */
475
476   if (simix_global->current_process->iwannadie)
477     SIMIX_context_stop(simix_global->current_process->context);
478 }
479
480 void SIMIX_process_schedule(smx_process_t new_process)
481 {
482   xbt_assert0(simix_global->current_process == simix_global->maestro_process,
483       "This function can only be called from maestro context");
484   DEBUG1("Scheduling context: '%s'", new_process->name);
485
486   /* update the current process */
487   simix_global->current_process = new_process;
488
489   /* schedule the context */
490   SIMIX_context_resume(new_process->context);
491   DEBUG1("Resumed from scheduling context: '%s'", new_process->name);
492
493   /* restore the current process to the previously saved process */
494   simix_global->current_process = simix_global->maestro_process;
495 }
496
497 /* callback: context fetching */
498 ex_ctx_t *SIMIX_process_get_exception(void)
499 {
500   return simix_global->current_process->exception;
501 }
502
503 /* callback: termination */
504 void SIMIX_process_exception_terminate(xbt_ex_t * e)
505 {
506   xbt_ex_display(e);
507   abort();
508 }