Logo AND Algorithmique Numérique Distribuée

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