Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge java simix process creation with the standard process creation
[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     free(process->name);
41     process->name = NULL;
42     free(process);
43   }
44 }
45
46 /**
47  * \brief Creates and runs the maestro process
48  */
49 void __SIMIX_create_maestro_process()
50 {
51   smx_process_t process = NULL;
52   process = xbt_new0(s_smx_process_t, 1);
53
54   /* Process data */
55   process->name = (char *)"";
56
57   /* Create a dummy context for maestro */
58   process->context = SIMIX_context_new(NULL, 0, NULL, NULL, NULL);
59
60   /* Set it as the maestro process */
61   simix_global->maestro_process = process;
62   simix_global->current_process = process;
63
64   return;
65 }
66
67 /**
68  * \brief Creates and runs a new #smx_process_t.
69  *
70  * 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.
71  *
72  * \param name a name for the object. It is for user-level information and can be NULL.
73  * \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.
74  * \param host the location where the new agent is executed.
75  * \param argc first argument passed to \a code
76  * \param argv second argument passed to \a code
77  * \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.
78  * \see smx_process_t
79  * \return The new corresponding object.
80  */
81 smx_process_t SIMIX_process_create(const char *name,
82                                    xbt_main_func_t code, void *data,
83                                    const char *hostname, int argc,
84                                    char **argv, xbt_dict_t properties)
85 {
86   smx_process_t process = NULL;
87   smx_host_t host = SIMIX_host_get_by_name(hostname);
88
89   DEBUG2("Start process %s on host %s", name, hostname);
90
91   if (!SIMIX_host_get_state(host)) {
92     WARN2("Cannot launch process '%s' on failed host '%s'", name, hostname);
93     return NULL;
94   }
95   process = xbt_new0(s_smx_process_t, 1);
96
97   xbt_assert0(((code != NULL) && (host != NULL)), "Invalid parameters");
98
99   /* Process data */
100   process->name = xbt_strdup(name);
101   process->smx_host = host;
102   process->mutex = NULL;
103   process->cond = NULL;
104   process->iwannadie = 0;
105
106   VERB1("Create context %s", process->name);
107   process->context = SIMIX_context_new(code, argc, argv, 
108                                        simix_global->cleanup_process_function,
109                                        process);
110   
111   process->data = data;
112
113   /* Add properties */
114   process->properties = properties;
115
116   /* Add the process to it's host process list */
117   xbt_swag_insert(process, host->process_list);
118
119   DEBUG1("Start context '%s'", process->name);
120   SIMIX_context_start(process->context);
121    
122   /* Now insert it in the global process list and in the process to run list */
123   xbt_swag_insert(process, simix_global->process_list);
124   DEBUG2("Inserting %s(%s) in the to_run list", process->name, host->name);
125   xbt_swag_insert(process, simix_global->process_to_run);
126
127   return process;
128 }
129
130 /** \brief Kill a SIMIX process
131  *
132  * This function simply kills a \a process... scarry isn't it ? :).
133  * \param process poor victim
134  *
135  */
136 void SIMIX_process_kill(smx_process_t process)
137 {
138   DEBUG2("Killing process %s on %s", process->name, process->smx_host->name);
139
140   /* Cleanup if we were waiting for something */
141   if (process->mutex)
142     xbt_swag_remove(process, process->mutex->sleeping);
143
144   if (process->cond)
145     xbt_swag_remove(process, process->cond->sleeping);
146
147   DEBUG2("%p here! killing %p", simix_global->current_process, process);
148
149   process->iwannadie = 1;
150
151   /* If I'm killing myself then stop otherwise schedule the process to kill */
152   if (process == SIMIX_process_self())
153     SIMIX_context_stop(process->context);
154   else
155     __SIMIX_process_schedule(process);
156   
157 }
158
159 /**
160  * \brief Return the user data of a #smx_process_t.
161  *
162  * 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.
163  * \param process SIMIX process
164  * \return A void pointer to the user data
165  */
166 void *SIMIX_process_get_data(smx_process_t process)
167 {
168   xbt_assert0((process != NULL), "Invalid parameters");
169   return (process->data);
170 }
171
172 /**
173  * \brief Set the user data of a #m_process_t.
174  *
175  * 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.
176  * \param process SIMIX process
177  * \param data User data
178  */
179 void SIMIX_process_set_data(smx_process_t process, void *data)
180 {
181   xbt_assert0((process != NULL), "Invalid parameters");
182
183   process->data = data;
184   return;
185 }
186
187 /**
188  * \brief Return the location on which an agent is running.
189  *
190  * 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.
191  * \param process SIMIX process
192  * \return SIMIX host
193  */
194 smx_host_t SIMIX_process_get_host(smx_process_t process)
195 {
196   xbt_assert0((process != NULL), "Invalid parameters");
197   return (process->smx_host);
198 }
199
200 /**
201  * \brief Return the name of an agent.
202  *
203  * This functions checks whether \a process is a valid pointer or not and return its name.
204  * \param process SIMIX process
205  * \return The process name
206  */
207 const char *SIMIX_process_get_name(smx_process_t process)
208 {
209   xbt_assert0((process != NULL), "Invalid parameters");
210   return (process->name);
211 }
212
213 /**
214  * \brief Changes the name of an agent.
215  *
216  * This functions checks whether \a process is a valid pointer or not and return its name.
217  * \param process SIMIX process
218  * \param name The new process name
219  */
220 void SIMIX_process_set_name(smx_process_t process, char *name)
221 {
222   xbt_assert0((process != NULL), "Invalid parameters");
223   process->name = name;
224 }
225
226 /** \ingroup m_process_management
227  * \brief Return the properties
228  *
229  * This functions returns the properties associated with this process
230  */
231 xbt_dict_t SIMIX_process_get_properties(smx_process_t process)
232 {
233   return process->properties;
234 }
235
236 /**
237  * \brief Return the current agent.
238  *
239  * This functions returns the currently running #smx_process_t.
240  * \return The SIMIX process
241  */
242 smx_process_t SIMIX_process_self(void)
243 {
244   return simix_global ? simix_global->current_process : NULL;
245 }
246
247 /**
248  * \brief Suspend the process.
249  *
250  * This functions suspend the process by suspending the action on
251  * which it was waiting for the completion.
252  *
253  * \param process SIMIX process
254  */
255 void SIMIX_process_suspend(smx_process_t process)
256 {
257   xbt_assert0(process, "Invalid parameters");
258
259   if (process != SIMIX_process_self()) {
260
261     if (process->mutex) {
262       /* process blocked on a mutex, only set suspend=1 */
263       process->suspended = 1;
264     } else if (process->cond) {
265       /* process blocked cond, suspend all actions */
266
267       /* temporaries variables */
268       smx_cond_t c;
269       xbt_fifo_item_t i;
270       smx_action_t act;
271
272       process->suspended = 1;
273       c = process->cond;
274       xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
275          surf_workstation_model->suspend(act->surf_action);
276       }
277     } else {
278       process->suspended = 1;
279     }
280   } else {
281     /* process executing, I can create an action and suspend it */
282     smx_action_t dummy;
283     smx_cond_t cond;
284     char name[] = "dummy";
285     process->suspended = 1;
286
287     cond = SIMIX_cond_init();
288     dummy = SIMIX_action_execute(SIMIX_process_get_host(process), name, 0);
289     surf_workstation_model->suspend(dummy->surf_action);
290     SIMIX_register_action_to_condition(dummy, cond);
291     __SIMIX_cond_wait(cond);
292     SIMIX_unregister_action_to_condition(dummy, cond);
293     SIMIX_action_destroy(dummy);
294     SIMIX_cond_destroy(cond);
295   }
296   return;
297 }
298
299 /**
300  * \brief Resume a suspended process.
301  *
302  * This functions resume a suspended process by resuming the task on which it was waiting for the completion.
303  * \param process SIMIX process
304  */
305 void SIMIX_process_resume(smx_process_t process)
306 {
307   xbt_assert0((process != NULL), "Invalid parameters");
308   SIMIX_CHECK_HOST();
309
310   if (process == SIMIX_process_self())
311     return;
312
313   if (process->mutex) {
314     DEBUG0("Resume process blocked on a mutex");
315     process->suspended = 0;     /* It'll wake up by itself when mutex releases */
316     return;
317   } else if (process->cond) {
318     /* temporaries variables */
319     smx_cond_t c;
320     xbt_fifo_item_t i;
321     smx_action_t act;
322     DEBUG0("Resume process blocked on a conditional");
323     process->suspended = 0;
324     c = process->cond;
325     xbt_fifo_foreach(c->actions, i, act, smx_action_t) {
326       surf_workstation_model->resume(act->surf_action);
327     }
328     SIMIX_cond_signal(c);
329     return;
330   } else {
331     process->suspended = 0;
332     xbt_swag_insert(process, simix_global->process_to_run);
333   }
334 }
335
336 /**
337  * \brief Migrates an agent to another location.
338  *
339  * This function changes the value of the host on which \a process is running.
340  */
341 void SIMIX_process_change_host(smx_process_t process, char *source, char *dest)
342 {
343   xbt_assert0((process != NULL), "Invalid parameters");
344   smx_host_t h1 = SIMIX_host_get_by_name(source);
345   smx_host_t h2 = SIMIX_host_get_by_name(dest);
346   process->smx_host = h2;
347   xbt_swag_remove(process, h1->process_list);
348   xbt_swag_insert(process, h2->process_list);
349 }
350
351 /**
352  * \brief Returns true if the process is suspended .
353  *
354  * This checks whether a process is suspended or not by inspecting the task on which it was waiting for the completion.
355  * \param process SIMIX process
356  * \return 1, if the process is suspended, else 0.
357  */
358 int SIMIX_process_is_suspended(smx_process_t process)
359 {
360   xbt_assert0((process != NULL), "Invalid parameters");
361
362   return (process->suspended);
363 }
364
365 /**
366  * \brief Returns the amount of SIMIX processes in the system
367  *
368  * Maestro internal process is not counted, only user code processes are
369  */
370 int SIMIX_process_count()
371 {
372   return xbt_swag_size(simix_global->process_list);
373 }
374
375 /** 
376  * Calling this function makes the process process to yield. The process
377  * that scheduled it returns from __SIMIX_process_schedule as if nothing
378  * had happened.
379  * 
380  * Only the processes can call this function, giving back the control
381  * to the maestro
382  */
383 void __SIMIX_process_yield(void)
384 {
385   DEBUG1("Yield process '%s'", simix_global->current_process->name);
386   xbt_assert0((simix_global->current_process != simix_global->maestro_process),
387               "You are not supposed to run this function here!");
388
389   SIMIX_context_suspend(simix_global->current_process->context);
390
391   if (simix_global->current_process->iwannadie)
392     SIMIX_context_stop(simix_global->current_process->context);
393 }
394
395 void __SIMIX_process_schedule(smx_process_t new_process)
396 {
397   DEBUG1("Scheduling context: '%s'", new_process->name);
398
399   /* save the current process */
400   smx_process_t old_process = simix_global->current_process;
401
402   /* update the current process */
403   simix_global->current_process = new_process;
404
405   /* schedule the context */
406   SIMIX_context_resume(old_process->context, new_process->context);
407
408   /* restore the current process to the previously saved process */
409   simix_global->current_process = old_process;
410 }