Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
fullduplex support
[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_fifo_remove(process->sem->sleeping, process);
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_fifo_remove(process->sem->sleeping, process);
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  if(simix_global)
301          return simix_global->current_process;
302  return NULL;
303 }
304
305 /**
306  * \brief Suspend the process.
307  *
308  * This functions suspend the process by suspending the action on
309  * which it was waiting for the completion.
310  *
311  * \param process SIMIX process
312  */
313 void SIMIX_process_suspend(smx_process_t process)
314 {
315   xbt_assert0(process, "Invalid parameters");
316
317   if (process != SIMIX_process_self()) {
318
319     if (process->mutex) {
320       /* process blocked on a mutex or sem, only set suspend=1 */
321       process->suspended = 1;
322     } else if (process->cond) {
323       /* process blocked cond, suspend all actions */
324
325       /* temporaries variables */
326       smx_cond_t c;
327       xbt_fifo_item_t i;
328       smx_action_t act;
329
330       process->suspended = 1;
331       c = process->cond;
332       xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
333         SIMIX_action_suspend(act);
334       }
335     } else if (process->sem) {
336       smx_sem_t s;
337       xbt_fifo_item_t i;
338       smx_action_t act;
339
340       process->suspended = 1;
341       s = process->sem;
342       xbt_fifo_foreach(s->actions, i, act, smx_action_t) {
343         SIMIX_action_suspend(act);
344       }
345     } else {
346       process->suspended = 1;
347     }
348   } else {
349     /* process executing, I can create an action and suspend it */
350     smx_action_t dummy;
351     smx_cond_t cond;
352     char name[] = "dummy";
353     process->suspended = 1;
354
355     cond = SIMIX_cond_init();
356     dummy = SIMIX_action_execute(SIMIX_process_get_host(process), name, 0);
357     SIMIX_process_self()->waiting_action = dummy;
358     SIMIX_action_suspend(dummy);
359     SIMIX_register_action_to_condition(dummy, cond);
360     __SIMIX_cond_wait(cond);
361     SIMIX_process_self()->waiting_action = NULL;
362     SIMIX_unregister_action_to_condition(dummy, cond);
363     SIMIX_action_destroy(dummy);
364     SIMIX_cond_destroy(cond);
365   }
366   return;
367 }
368
369 /**
370  * \brief Resume a suspended process.
371  *
372  * This functions resume a suspended process by resuming the task on which it was waiting for the completion.
373  * \param process SIMIX process
374  */
375 void SIMIX_process_resume(smx_process_t process)
376 {
377   xbt_assert0((process != NULL), "Invalid parameters");
378   SIMIX_CHECK_HOST();
379
380   if (process == SIMIX_process_self())
381     return;
382
383   if (process->mutex) {
384     DEBUG0("Resume process blocked on a mutex or semaphore");
385     process->suspended = 0;     /* It'll wake up by itself when mutex releases */
386     return;
387   } else if (process->cond) {
388     /* temporaries variables */
389     smx_cond_t c;
390     xbt_fifo_item_t i;
391     smx_action_t act;
392     DEBUG0("Resume process blocked on a conditional");
393     process->suspended = 0;
394     c = process->cond;
395     xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
396       SIMIX_action_resume(act);
397     }
398     SIMIX_cond_signal(c);
399     return;
400   } else if (process->sem) {
401     /* temporaries variables */
402     smx_sem_t s;
403     xbt_fifo_item_t i;
404     smx_action_t act;
405     DEBUG0("Resume process blocked on a semaphore");
406     process->suspended = 0;
407     s = process->sem;
408     xbt_fifo_foreach(s->actions, i, act, smx_action_t) {
409       SIMIX_action_resume(act);
410     }
411     return;
412   } else {
413     process->suspended = 0;
414     xbt_swag_insert(process, simix_global->process_to_run);
415   }
416 }
417
418 /**
419  * \brief Migrates an agent to another location.
420  *
421  * This function changes the value of the host on which \a process is running.
422  */
423 void SIMIX_process_change_host(smx_process_t process, char *source,
424                                char *dest)
425 {
426   smx_host_t h1 = NULL;
427   smx_host_t h2 = NULL;
428   xbt_assert0((process != NULL), "Invalid parameters");
429   h1 = SIMIX_host_get_by_name(source);
430   h2 = SIMIX_host_get_by_name(dest);
431   process->smx_host = h2;
432   xbt_swag_remove(process, h1->process_list);
433   xbt_swag_insert(process, h2->process_list);
434 }
435
436 /**
437  * \brief Returns true if the process is suspended .
438  *
439  * This checks whether a process is suspended or not by inspecting the task on which it was waiting for the completion.
440  * \param process SIMIX process
441  * \return 1, if the process is suspended, else 0.
442  */
443 XBT_INLINE int SIMIX_process_is_suspended(smx_process_t process)
444 {
445   xbt_assert0((process != NULL), "Invalid parameters");
446
447   return (process->suspended);
448 }
449
450 /**
451  * \brief Returns the amount of SIMIX processes in the system
452  *
453  * Maestro internal process is not counted, only user code processes are
454  */
455 XBT_INLINE int SIMIX_process_count()
456 {
457   return xbt_swag_size(simix_global->process_list);
458 }
459
460 /** 
461  * Calling this function makes the process process to yield. The process
462  * that scheduled it returns from __SIMIX_process_schedule as if nothing
463  * had happened.
464  * 
465  * Only the processes can call this function, giving back the control
466  * to the maestro
467  */
468 void SIMIX_process_yield(void)
469 {
470   DEBUG1("Yield process '%s'", simix_global->current_process->name);
471   xbt_assert0((simix_global->current_process !=
472                simix_global->maestro_process),
473               "You are not supposed to run this function in maestro context!");
474
475
476   /* Go into sleep and return control to maestro */
477   SIMIX_context_suspend(simix_global->current_process->context);
478   /* Ok, maestro returned control to us */
479
480   if (simix_global->current_process->iwannadie)
481     SIMIX_context_stop(simix_global->current_process->context);
482 }
483
484 void SIMIX_process_schedule(smx_process_t new_process)
485 {
486   xbt_assert0(simix_global->current_process == simix_global->maestro_process,
487       "This function can only be called from maestro context");
488   DEBUG1("Scheduling context: '%s'", new_process->name);
489
490   /* update the current process */
491   simix_global->current_process = new_process;
492
493   /* schedule the context */
494   SIMIX_context_resume(new_process->context);
495   DEBUG1("Resumed from scheduling context: '%s'", new_process->name);
496
497   /* restore the current process to the previously saved process */
498   simix_global->current_process = simix_global->maestro_process;
499 }
500
501 /* callback: context fetching */
502 ex_ctx_t *SIMIX_process_get_exception(void)
503 {
504   return simix_global->current_process->exception;
505 }
506
507 /* callback: termination */
508 void SIMIX_process_exception_terminate(xbt_ex_t * e)
509 {
510   xbt_ex_display(e);
511   abort();
512 }