Logo AND Algorithmique Numérique Distribuée

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