Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Keep improving the traces
[simgrid.git] / src / msg / m_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/error.h"
11 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(m_process, msg,
12                                 "Logging specific to MSG (process)");
13
14 /******************************** Process ************************************/
15 /** \ingroup m_process_management
16  * \brief Creates and runs a new #m_process_t.
17  *
18  * Does exactly the same as #MSG_process_create_with_arguments but without 
19    providing standard arguments (\a argc, \a argv).
20  * \sa MSG_process_create_with_arguments
21  */
22 m_process_t MSG_process_create(const char *name,
23                                m_process_code_t code, void *data,
24                                m_host_t host)
25 {
26   return MSG_process_create_with_arguments(name, code, data, host, -1, NULL);
27 }
28
29 static void MSG_process_cleanup(void *arg)
30 {
31
32   PAJE_PROCESS_FREE(arg);
33
34   while(((m_process_t)arg)->simdata->paje_state) {
35     PAJE_PROCESS_POP_STATE((m_process_t)arg);
36   }
37
38   xbt_fifo_remove(msg_global->process_list, arg);
39   xbt_fifo_remove(msg_global->process_to_run, arg);
40   xbt_fifo_remove(((m_process_t) arg)->simdata->host->simdata->process_list, arg);
41   xbt_free(((m_process_t) arg)->name);
42   xbt_free(((m_process_t) arg)->simdata);
43   xbt_free(arg);
44 }
45
46 /** \ingroup m_process_management
47  * \brief Creates and runs a new #m_process_t.
48
49  * A constructor for #m_process_t taking four arguments and returning the 
50  * corresponding object. The structure (and the corresponding thread) is
51  * created, and put in the list of ready process.
52  * \param name a name for the object. It is for user-level information
53    and can be NULL.
54  * \param code is a function describing the behavior of the agent. It
55    should then only use functions described in \ref
56    m_process_management (to create a new #m_process_t for example),
57    in \ref m_host_management (only the read-only functions i.e. whose
58    name contains the word get), in \ref m_task_management (to create
59    or destroy some #m_task_t for example) and in \ref
60    msg_gos_functions (to handle file transfers and task processing).
61  * \param data a pointer to any data may want to attach to the new
62    object.  It is for user-level information and can be NULL. It can
63    be retrieved with the function \ref MSG_process_get_data.
64  * \param host the location where the new agent is executed.
65  * \param argc first argument passed to \a code
66  * \param argv second argument passed to \a code
67  * \see m_process_t
68  * \return The new corresponding object.
69  */
70 m_process_t MSG_process_create_with_arguments(const char *name,
71                                               m_process_code_t code, void *data,
72                                               m_host_t host, int argc, char **argv)
73 {
74   simdata_process_t simdata = xbt_new0(s_simdata_process_t,1);
75   m_process_t process = xbt_new0(s_m_process_t,1);
76   m_process_t self = NULL;
77
78   xbt_assert0(((code != NULL) && (host != NULL)), "Invalid parameters");
79   /* Simulator Data */
80
81   simdata->PID = msg_global->PID++;
82   simdata->host = host;
83   simdata->waiting_task = NULL;
84   simdata->argc = argc;
85   simdata->argv = argv;
86   simdata->context = xbt_context_new(code, NULL, NULL, 
87                                      MSG_process_cleanup, process, 
88                                      simdata->argc, simdata->argv);
89
90   if((self=msg_global->current_process)) {
91     simdata->PPID = MSG_process_get_PID(self);
92   } else {
93     simdata->PPID = -1;
94   }
95   simdata->last_errno=MSG_OK;
96
97
98   /* Process structure */
99   process->name = xbt_strdup(name);
100   process->simdata = simdata;
101   process->data = data;
102
103   xbt_fifo_push(host->simdata->process_list, process);
104
105   /* /////////////// FIX du current_process !!! ////////////// */
106   self = msg_global->current_process;
107   xbt_context_start(process->simdata->context);
108   msg_global->current_process = self;
109
110   xbt_fifo_push(msg_global->process_list, process);
111   xbt_fifo_push(msg_global->process_to_run, process);
112
113   PAJE_PROCESS_NEW(process);
114
115   return process;
116 }
117
118 /** \ingroup m_process_management
119  * \param process poor victim
120  *
121  * This function simply kills a \a process... scarry isn't it ? :)
122  */
123 void MSG_process_kill(m_process_t process)
124 {
125   int i;
126   simdata_process_t p_simdata = process->simdata;
127   simdata_host_t h_simdata= p_simdata->host->simdata;
128
129 /*   fprintf(stderr,"Killing %s(%d) on %s.\n",process->name, */
130 /*        p_simdata->PID,p_simdata->host->name); */
131   
132   for (i=0; i<msg_global->max_channel; i++) {
133     if (h_simdata->sleeping[i] == process) {
134       h_simdata->sleeping[i] = NULL;
135       break;
136     }
137   }
138   if (i==msg_global->max_channel) {
139     if(p_simdata->waiting_task) {
140       if(p_simdata->waiting_task->simdata->compute)
141         surf_workstation_resource->common_public->
142           action_free(p_simdata->waiting_task->simdata->compute);
143       else if (p_simdata->waiting_task->simdata->comm)
144         surf_workstation_resource->common_public->
145           action_change_state(p_simdata->waiting_task->simdata->comm,SURF_ACTION_FAILED);
146       else
147         fprintf(stderr,"UNKNOWN STATUS. Please report this bug.\n");
148     } else { /* Must be trying to put a task somewhere */
149       fprintf(stderr,"UNKNOWN STATUS. Please report this bug.\n");
150     }
151   }
152
153   xbt_fifo_remove(msg_global->process_list,process);
154   xbt_context_free(process->simdata->context);
155 }
156
157 /** \ingroup m_process_management
158  * \brief Migrates an agent to another location.
159  *
160  * This functions checks whether \a process and \a host are valid pointers
161    and change the value of the #m_host_t on which \a process is running.
162  */
163 MSG_error_t MSG_process_change_host(m_process_t process, m_host_t host)
164 {
165   simdata_process_t simdata = NULL;
166
167   /* Sanity check */
168
169   xbt_assert0(((process) && (process->simdata)
170           && (host)), "Invalid parameters");
171   simdata = process->simdata;
172
173   xbt_fifo_remove(simdata->host->simdata->process_list,process);
174   simdata->host = host;
175   xbt_fifo_push(host->simdata->process_list,process);
176
177   return MSG_OK;
178 }
179
180 /** \ingroup m_process_management
181  * \brief Return the user data of a #m_process_t.
182  *
183  * This functions checks whether \a process is a valid pointer or not 
184    and return the user data associated to \a process if it is possible.
185  */
186 void *MSG_process_get_data(m_process_t process)
187 {
188   xbt_assert0((process != NULL), "Invalid parameters");
189
190   return (process->data);
191 }
192
193 /** \ingroup m_process_management
194  * \brief Set the user data of a #m_process_t.
195  *
196  * This functions checks whether \a process is a valid pointer or not 
197    and set the user data associated to \a process if it is possible.
198  */
199 MSG_error_t MSG_process_set_data(m_process_t process,void *data)
200 {
201   xbt_assert0((process != NULL), "Invalid parameters");
202   xbt_assert0((process->data == NULL), "Data already set");
203   
204   process->data = data;
205    
206   return MSG_OK;
207 }
208
209 /** \ingroup m_process_management
210  * \brief Return the location on which an agent is running.
211  *
212  * This functions checks whether \a process is a valid pointer or not 
213    and return the m_host_t corresponding to the location on which \a 
214    process is running.
215  */
216 m_host_t MSG_process_get_host(m_process_t process)
217 {
218   xbt_assert0(((process != NULL) && (process->simdata)), "Invalid parameters");
219
220   return (((simdata_process_t) process->simdata)->host);
221 }
222
223 /** \ingroup m_process_management
224  *
225  * \brief Return a #m_process_t given its PID.
226  *
227  * This functions search in the list of all the created m_process_t for a m_process_t 
228    whose PID is equal to \a PID. If no host is found, \c NULL is returned. 
229    Note that the PID are uniq in the whole simulation, not only on a given host.
230  */
231 m_process_t MSG_process_from_PID(int PID)
232 {
233   xbt_fifo_item_t i = NULL;
234   m_process_t process = NULL;
235
236   xbt_fifo_foreach(msg_global->process_list,i,process,m_process_t) {
237     if(MSG_process_get_PID(process) == PID) return process;
238   }
239   return NULL;
240 }
241
242 /** \ingroup m_process_management
243  * \brief Returns the process ID of \a process.
244  *
245  * This functions checks whether \a process is a valid pointer or not 
246    and return its PID.
247  */
248 int MSG_process_get_PID(m_process_t process)
249 {
250   xbt_assert0(((process != NULL) && (process->simdata)), "Invalid parameters");
251
252   return (((simdata_process_t) process->simdata)->PID);
253 }
254
255 /** \ingroup m_process_management
256  * \brief Returns the process ID of the parent of \a process.
257  *
258  * This functions checks whether \a process is a valid pointer or not 
259    and return its PID. Returns -1 if the agent has not been created by 
260    another agent.
261  */
262 int MSG_process_get_PPID(m_process_t process)
263 {
264   xbt_assert0(((process != NULL) && (process->simdata)), "Invalid parameters");
265
266   return (((simdata_process_t) process->simdata)->PPID);
267 }
268
269 /** \ingroup m_process_management
270  * \brief Return the name of an agent.
271  *
272  * This functions checks whether \a process is a valid pointer or not 
273    and return its name.
274  */
275 const char *MSG_process_get_name(m_process_t process)
276 {
277   xbt_assert0(((process != NULL) && (process->simdata)), "Invalid parameters");
278
279   return (process->name);
280 }
281
282 /** \ingroup m_process_management
283  * \brief Return the PID of the current agent.
284  *
285  * This functions returns the PID of the currently running #m_process_t.
286  */
287 int MSG_process_self_PID(void)
288 {
289   return (MSG_process_get_PID(MSG_process_self()));
290 }
291
292 /** \ingroup m_process_management
293  * \brief Return the PPID of the current agent.
294  *
295  * This functions returns the PID of the parent of the currently
296  * running #m_process_t.
297  */
298 int MSG_process_self_PPID(void)
299 {
300   return (MSG_process_get_PPID(MSG_process_self()));
301 }
302
303 /** \ingroup m_process_management
304  * \brief Return the current agent.
305  *
306  * This functions returns the currently running #m_process_t.
307  */
308 m_process_t MSG_process_self(void)
309 {
310   return msg_global->current_process;
311 }
312
313 /** \ingroup m_process_management
314  * \brief Suspend the process.
315  *
316  * This functions suspend the process by suspending the task on which
317  * it was waiting for the completion.
318  */
319 MSG_error_t MSG_process_suspend(m_process_t process)
320 {
321   simdata_process_t simdata = NULL;
322   simdata_task_t simdata_task = NULL;
323   int i;
324
325   xbt_assert0(((process) && (process->simdata)), "Invalid parameters");
326
327   PAJE_PROCESS_PUSH_STATE(process,"S");
328
329   if(process!=MSG_process_self()) {
330     simdata = process->simdata;
331     
332     xbt_assert0(simdata->waiting_task,"Process not waiting for anything else. Weird !");
333
334     simdata_task = simdata->waiting_task->simdata;
335
336     simdata->suspended = 1;
337     if(simdata->blocked) return MSG_OK;
338
339     xbt_assert0(((simdata_task->compute)||(simdata_task->comm))&&
340                 !((simdata_task->compute)&&(simdata_task->comm)),
341                 "Got a problem in deciding which action to choose !");
342     simdata->suspended = 1;
343     if(simdata_task->compute) 
344       surf_workstation_resource->common_public->suspend(simdata_task->compute);
345     else
346       surf_workstation_resource->common_public->suspend(simdata_task->comm);
347   } else {
348     m_task_t dummy = MSG_TASK_UNINITIALIZED;
349     dummy = MSG_task_create("suspended", 0.0, 0, NULL);
350
351     simdata = process->simdata;
352     simdata->suspended = 1;
353     __MSG_task_execute(process,dummy);
354     surf_workstation_resource->common_public->suspend(dummy->simdata->compute);
355     __MSG_wait_for_computation(process,dummy);
356     simdata->suspended = 0;
357
358     MSG_task_destroy(dummy);
359   }
360   return MSG_OK;
361 }
362
363 /** \ingroup m_process_management
364  * \brief Resume a suspended process.
365  *
366  * This functions resume a suspended process by resuming the task on
367  * which it was waiting for the completion.
368  */
369 MSG_error_t MSG_process_resume(m_process_t process)
370 {
371   simdata_process_t simdata = NULL;
372   simdata_task_t simdata_task = NULL;
373   int i;
374
375   xbt_assert0(((process != NULL) && (process->simdata)), "Invalid parameters");
376   CHECK_HOST();
377
378   simdata = process->simdata;
379
380
381   if(simdata->blocked) {
382     PAJE_PROCESS_POP_STATE(process);
383
384     simdata->suspended = 0; /* He'll wake up by itself */
385     MSG_RETURN(MSG_OK);
386   }
387
388   if(!(simdata->waiting_task)) {
389     xbt_assert0(0,"Process not waiting for anything else. Weird !");
390     return MSG_WARNING;
391   }
392   simdata_task = simdata->waiting_task->simdata;
393
394
395   if(simdata_task->compute) {
396     surf_workstation_resource->common_public->resume(simdata_task->compute);
397     PAJE_PROCESS_POP_STATE(process);
398   }
399   else {
400     PAJE_PROCESS_POP_STATE(process);
401     surf_workstation_resource->common_public->resume(simdata_task->comm);
402   }
403
404   MSG_RETURN(MSG_OK);
405 }
406
407 /** \ingroup m_process_management
408  * \brief Returns true if the process is suspended .
409  *
410  * This checks whether a process is suspended or not by inspecting the
411  * task on which it was waiting for the completion.
412  */
413 int MSG_process_isSuspended(m_process_t process)
414 {
415   xbt_assert0(((process != NULL) && (process->simdata)), "Invalid parameters");
416
417   return (process->simdata->suspended);
418 }
419
420 MSG_error_t __MSG_process_block(void)
421 {
422   m_process_t process = MSG_process_self();
423
424   m_task_t dummy = MSG_TASK_UNINITIALIZED;
425   dummy = MSG_task_create("blocked", 0.0, 0, NULL);
426   
427   PAJE_PROCESS_PUSH_STATE(process,"B");
428
429   process->simdata->blocked=1;
430   __MSG_task_execute(process,dummy);
431   surf_workstation_resource->common_public->suspend(dummy->simdata->compute);
432   __MSG_wait_for_computation(process,dummy);
433   process->simdata->blocked=0;
434
435   if(process->simdata->suspended)
436     MSG_process_suspend(process);
437   
438   MSG_task_destroy(dummy);
439
440   return MSG_OK;
441 }
442
443 MSG_error_t __MSG_process_unblock(m_process_t process)
444 {
445   simdata_process_t simdata = NULL;
446   simdata_task_t simdata_task = NULL;
447   int i;
448
449   xbt_assert0(((process != NULL) && (process->simdata)), "Invalid parameters");
450   CHECK_HOST();
451
452   simdata = process->simdata;
453   if(!(simdata->waiting_task)) {
454     xbt_assert0(0,"Process not waiting for anything else. Weird !");
455     return MSG_WARNING;
456   }
457   simdata_task = simdata->waiting_task->simdata;
458
459   xbt_assert0(simdata->blocked,"Process not blocked");
460
461   surf_workstation_resource->common_public->resume(simdata_task->compute);
462
463   PAJE_PROCESS_POP_STATE(process);
464
465   MSG_RETURN(MSG_OK);
466 }
467
468 int __MSG_process_isBlocked(m_process_t process)
469 {
470   xbt_assert0(((process != NULL) && (process->simdata)), "Invalid parameters");
471
472   return (process->simdata->blocked);
473 }