Logo AND Algorithmique Numérique Distribuée

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