Logo AND Algorithmique Numérique Distribuée

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