Logo AND Algorithmique Numérique Distribuée

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