Logo AND Algorithmique Numérique Distribuée

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