Logo AND Algorithmique Numérique Distribuée

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