Logo AND Algorithmique Numérique Distribuée

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