Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Bugfix of the previous commit.
[simgrid.git] / src / msg / msg_gos.c
1 /* Copyright (c) 2004-2011. The SimGrid Team. All rights reserved.          */
2
3 /* This program is free software; you can redistribute it and/or modify it
4  * under the terms of the license (GNU LGPL) which comes with this package. */
5
6 #include "msg_private.h"
7 #include "msg_mailbox.h"
8 #include "mc/mc.h"
9 #include "xbt/log.h"
10 #include "xbt/sysdep.h"
11
12 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_gos, msg,
13                                 "Logging specific to MSG (gos)");
14
15 /** \ingroup msg_task_usage
16  * \brief Executes a task and waits for its termination.
17  *
18  * This function is used for describing the behavior of a process. It
19  * takes only one parameter.
20  * \param task a #m_task_t to execute on the location on which the process is running.
21  * \return #MSG_OK if the task was successfully completed, #MSG_TASK_CANCELED
22  * or #MSG_HOST_FAILURE otherwise
23  */
24 MSG_error_t MSG_task_execute(m_task_t task)
25 {
26   xbt_ex_t e;
27   simdata_task_t simdata = NULL;
28   simdata_process_t p_simdata;
29   e_smx_state_t comp_state;
30
31   simdata = task->simdata;
32
33   xbt_assert(simdata->host_nb == 0,
34               "This is a parallel task. Go to hell.");
35
36 #ifdef HAVE_TRACING
37   TRACE_msg_task_execute_start(task);
38 #endif
39
40   xbt_assert((!simdata->compute) && (task->simdata->isused == 0),
41               "This task is executed somewhere else. Go fix your code! %d",
42               task->simdata->isused);
43
44   XBT_DEBUG("Computing on %s", MSG_process_get_name(MSG_process_self()));
45
46   if (simdata->computation_amount == 0) {
47 #ifdef HAVE_TRACING
48     TRACE_msg_task_execute_end(task);
49 #endif
50     return MSG_OK;
51   }
52
53   m_process_t self = SIMIX_process_self();
54   p_simdata = SIMIX_process_self_get_data(self);
55   simdata->isused=1;
56   simdata->compute =
57       simcall_host_execute(task->name, p_simdata->m_host->smx_host,
58                            simdata->computation_amount,
59                            simdata->priority);
60 #ifdef HAVE_TRACING
61   simcall_set_category(simdata->compute, task->category);
62 #endif
63   
64   p_simdata->waiting_action = simdata->compute;
65   TRY {
66     comp_state = simcall_host_execution_wait(simdata->compute);
67     p_simdata->waiting_action = NULL;
68
69     simdata->isused=0;
70
71     XBT_DEBUG("Execution task '%s' finished in state %d", task->name, (int)comp_state);
72
73     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
74     simdata->computation_amount = 0.0;
75     simdata->comm = NULL;
76     simdata->compute = NULL;
77 #ifdef HAVE_TRACING
78     TRACE_msg_task_execute_end(task);
79 #endif
80     MSG_RETURN(MSG_OK);
81   }  
82   CATCH(e) {
83     switch (e.category) {
84       case host_error:
85         /* action ended, set comm and compute = NULL, the actions is already  destroyed in the main function */
86         simdata->comm = NULL;
87         simdata->compute = NULL;
88         #ifdef HAVE_TRACING
89           TRACE_msg_task_execute_end(task);
90         #endif
91         MSG_RETURN(MSG_HOST_FAILURE);
92         break;  
93       case cancel_error:
94         /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
95         simdata->comm = NULL;
96         simdata->compute = NULL;
97     #ifdef HAVE_TRACING
98         TRACE_msg_task_execute_end(task);
99     #endif
100         MSG_RETURN(MSG_TASK_CANCELED);        
101       break;
102       default:
103         RETHROW;
104     }
105   }
106   MSG_RETURN(MSG_OK);
107 }
108
109 /** \ingroup m_task_management
110  * \brief Creates a new #m_task_t (a parallel one....).
111  *
112  * A constructor for #m_task_t taking six arguments and returning the
113  corresponding object.
114  * \param name a name for the object. It is for user-level information
115  and can be NULL.
116  * \param host_nb the number of hosts implied in the parallel task.
117  * \param host_list an array of \p host_nb m_host_t.
118  * \param computation_amount an array of \p host_nb
119  doubles. computation_amount[i] is the total number of operations
120  that have to be performed on host_list[i].
121  * \param communication_amount an array of \p host_nb* \p host_nb doubles.
122  * \param data a pointer to any data may want to attach to the new
123  object.  It is for user-level information and can be NULL. It can
124  be retrieved with the function \ref MSG_task_get_data.
125  * \see m_task_t
126  * \return The new corresponding object.
127  */
128 m_task_t
129 MSG_parallel_task_create(const char *name, int host_nb,
130                          const m_host_t * host_list,
131                          double *computation_amount,
132                          double *communication_amount, void *data)
133 {
134   int i;
135   simdata_task_t simdata = xbt_new0(s_simdata_task_t, 1);
136   m_task_t task = xbt_new0(s_m_task_t, 1);
137   task->simdata = simdata;
138
139   /* Task structure */
140   task->name = xbt_strdup(name);
141   task->data = data;
142
143   /* Simulator Data */
144   simdata->computation_amount = 0;
145   simdata->message_size = 0;
146   simdata->compute = NULL;
147   simdata->comm = NULL;
148   simdata->rate = -1.0;
149   simdata->isused = 0;
150   simdata->sender = NULL;
151   simdata->receiver = NULL;
152   simdata->source = NULL;
153
154   simdata->host_nb = host_nb;
155   simdata->host_list = xbt_new0(smx_host_t, host_nb);
156   simdata->comp_amount = computation_amount;
157   simdata->comm_amount = communication_amount;
158
159   for (i = 0; i < host_nb; i++)
160     simdata->host_list[i] = host_list[i]->smx_host;
161
162   return task;
163 }
164
165 /** \ingroup msg_task_usage
166  * \brief Executes a parallel task and waits for its termination.
167  *
168  * \param task a #m_task_t to execute on the location on which the process is running.
169  *
170  * \return #MSG_OK if the task was successfully completed, #MSG_TASK_CANCELED
171  * or #MSG_HOST_FAILURE otherwise
172  */
173 MSG_error_t MSG_parallel_task_execute(m_task_t task)
174 {
175   simdata_task_t simdata = NULL;
176   e_smx_state_t comp_state;
177   simdata_process_t p_simdata;
178
179   simdata = task->simdata;
180   p_simdata = SIMIX_process_self_get_data(SIMIX_process_self());
181
182   xbt_assert((!simdata->compute)
183               && (task->simdata->isused == 0),
184               "This task is executed somewhere else. Go fix your code!");
185
186   xbt_assert(simdata->host_nb,
187               "This is not a parallel task. Go to hell.");
188
189   XBT_DEBUG("Parallel computing on %s", SIMIX_host_get_name(p_simdata->m_host->smx_host));
190
191   simdata->isused=1;
192
193   simdata->compute =
194       simcall_host_parallel_execute(task->name, simdata->host_nb,
195                                   simdata->host_list,
196                                   simdata->comp_amount,
197                                   simdata->comm_amount, 1.0, -1.0);
198   XBT_DEBUG("Parallel execution action created: %p", simdata->compute);
199
200   p_simdata->waiting_action = simdata->compute;
201   comp_state = simcall_host_execution_wait(simdata->compute);
202   p_simdata->waiting_action = NULL;
203
204   XBT_DEBUG("Finished waiting for execution of action %p, state = %d", simdata->compute, (int)comp_state);
205
206   simdata->isused=0;
207
208   if (comp_state == SIMIX_DONE) {
209     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
210     simdata->computation_amount = 0.0;
211     simdata->comm = NULL;
212     simdata->compute = NULL;
213     MSG_RETURN(MSG_OK);
214   } else if (simcall_host_get_state(SIMIX_host_self()) == 0) {
215     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
216     simdata->comm = NULL;
217     simdata->compute = NULL;
218     MSG_RETURN(MSG_HOST_FAILURE);
219   } else {
220     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
221     simdata->comm = NULL;
222     simdata->compute = NULL;
223     MSG_RETURN(MSG_TASK_CANCELED);
224   }
225 }
226
227
228 /** \ingroup msg_task_usage
229  * \brief Sleep for the specified number of seconds
230  *
231  * Makes the current process sleep until \a time seconds have elapsed.
232  *
233  * \param nb_sec a number of second
234  */
235 MSG_error_t MSG_process_sleep(double nb_sec)
236 {
237   e_smx_state_t state;
238   /*m_process_t proc = MSG_process_self();*/
239
240 #ifdef HAVE_TRACING
241   TRACE_msg_process_sleep_in(MSG_process_self());
242 #endif
243
244   /* create action to sleep */
245   state = simcall_process_sleep(nb_sec);
246
247   /*proc->simdata->waiting_action = act_sleep;
248
249   FIXME: check if not setting the waiting_action breaks something on msg
250   
251   proc->simdata->waiting_action = NULL;*/
252   
253   if (state == SIMIX_DONE) {
254 #ifdef HAVE_TRACING
255   TRACE_msg_process_sleep_out(MSG_process_self());
256 #endif
257     MSG_RETURN(MSG_OK);
258   } else {
259 #ifdef HAVE_TRACING
260     TRACE_msg_process_sleep_out(MSG_process_self());
261 #endif
262     MSG_RETURN(MSG_HOST_FAILURE);
263   }
264 }
265
266 /** \ingroup msg_task_usage
267  * \brief Deprecated function that used to receive a task from a mailbox from a specific host.
268  *
269  * Sorry, this function is not supported anymore. That wouldn't be
270  * impossible to reimplement it, but we are lacking the time to do so ourselves.
271  * If you need this functionality, you can either:
272  *
273  *  - implement the buffering mechanism on the user-level by queuing all messages
274  *    received in the mailbox that do not match your expectation
275  *  - change your application logic to leverage the mailboxes features. For example,
276  *    if you have A receiving messages from B and C, you could have A waiting on
277  *    mailbox "A" most of the time, but on "A#B" when it's waiting for specific
278  *    messages from B and "A#C" when waiting for messages from C. You could even get A
279  *    sometime waiting on all these mailboxes using @ref MSG_comm_waitany. You can find
280  *    an example of use of this function in the @ref MSG_examples section.
281  *  - Provide a proper patch to implement this functionality back in MSG. That wouldn't be
282  *    very difficult actually. Check the function @ref MSG_mailbox_get_task_ext. During its call to
283  *    simcall_comm_recv(), the 5th argument, match_fun, is NULL. Create a function that filters
284  *    messages according to the host (that you will pass as sixth argument to simcall_comm_recv()
285  *    and that your filtering function will receive as first parameter, and then, the filter could
286  *    simply compare the host names, for example. After sufficient testing, provide an example that
287  *    we could add to the distribution, and your first contribution to SimGrid is ready. Thanks in advance.
288  *
289  * \param task a memory location for storing a #m_task_t.
290  * \param alias name of the mailbox to receive the task from
291  * \param host a #m_host_t host from where the task was sent
292  *
293  * \return Returns
294  * #MSG_OK if the task was successfully received,
295  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE otherwise.
296  */
297 MSG_error_t
298 MSG_task_receive_from_host(m_task_t * task, const char *alias,
299                            m_host_t host)
300 {
301   return MSG_task_receive_ext(task, alias, -1, host);
302 }
303
304 /** \ingroup msg_task_usage
305  * \brief Receives a task from a mailbox.
306  *
307  * This is a blocking function, the execution flow will be blocked
308  * until the task is received. See #MSG_task_irecv
309  * for receiving tasks asynchronously.
310  *
311  * \param task a memory location for storing a #m_task_t.
312  * \param alias name of the mailbox to receive the task from
313  *
314  * \return Returns
315  * #MSG_OK if the task was successfully received,
316  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE otherwise.
317  */
318 MSG_error_t MSG_task_receive(m_task_t * task, const char *alias)
319 {
320   return MSG_task_receive_with_timeout(task, alias, -1);
321 }
322
323 /** \ingroup msg_task_usage
324  * \brief Receives a task from a mailbox with a given timeout.
325  *
326  * This is a blocking function with a timeout, the execution flow will be blocked
327  * until the task is received or the timeout is achieved. See #MSG_task_irecv
328  * for receiving tasks asynchronously.  You can provide a -1 timeout
329  * to obtain an infinite timeout.
330  *
331  * \param task a memory location for storing a #m_task_t.
332  * \param alias name of the mailbox to receive the task from
333  * \param timeout is the maximum wait time for completion (if -1, this call is the same as #MSG_task_receive)
334  *
335  * \return Returns
336  * #MSG_OK if the task was successfully received,
337  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
338  */
339 MSG_error_t
340 MSG_task_receive_with_timeout(m_task_t * task, const char *alias,
341                               double timeout)
342 {
343   return MSG_task_receive_ext(task, alias, timeout, NULL);
344 }
345
346 /** \ingroup msg_task_usage
347  * \brief Receives a task from a mailbox from a specific host with a given timeout.
348  *
349  * This is a blocking function with a timeout, the execution flow will be blocked
350  * until the task is received or the timeout is achieved. See #MSG_task_irecv
351  * for receiving tasks asynchronously. You can provide a -1 timeout
352  * to obtain an infinite timeout.
353  *
354  * \param task a memory location for storing a #m_task_t.
355  * \param alias name of the mailbox to receive the task from
356  * \param timeout is the maximum wait time for completion (provide -1 for no timeout)
357  * \param host a #m_host_t host from where the task was sent
358  *
359  * \return Returns
360  * #MSG_OK if the task was successfully received,
361 * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
362  */
363 MSG_error_t
364 MSG_task_receive_ext(m_task_t * task, const char *alias, double timeout,
365                      m_host_t host)
366 {
367   XBT_DEBUG
368       ("MSG_task_receive_ext: Trying to receive a message on mailbox '%s'",
369        alias);
370   return MSG_mailbox_get_task_ext(MSG_mailbox_get_by_alias(alias), task,
371                                   host, timeout);
372 }
373
374 /** \ingroup msg_task_usage
375  * \brief Sends a task on a mailbox.
376  *
377  * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test()
378  * to end the communication.
379  *
380  * \param task a #m_task_t to send on another location.
381  * \param alias name of the mailbox to sent the task to
382  * \return the msg_comm_t communication created
383  */
384 msg_comm_t MSG_task_isend(m_task_t task, const char *alias)
385 {
386   return MSG_task_isend_with_matching(task,alias,NULL,NULL);
387 }
388
389 /** \ingroup msg_task_usage
390  * \brief Sends a task on a mailbox, with support for matching requests
391  *
392  * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test()
393  * to end the communication.
394  *
395  * \param task a #m_task_t to send on another location.
396  * \param alias name of the mailbox to sent the task to
397  * \param match_fun boolean function which parameters are:
398  *        - match_data_provided_here
399  *        - match_data_provided_by_other_side_if_any
400  *        - the_smx_action_describing_the_other_side
401  * \param match_data user provided data passed to match_fun
402  * \return the msg_comm_t communication created
403  */
404 XBT_INLINE msg_comm_t MSG_task_isend_with_matching(m_task_t task, const char *alias,
405     int (*match_fun)(void*,void*, smx_action_t),
406     void *match_data)
407 {
408   simdata_task_t t_simdata = NULL;
409   m_process_t process = MSG_process_self();
410   msg_mailbox_t mailbox = MSG_mailbox_get_by_alias(alias);
411
412   /* FIXME: these functions are not traceable */
413
414   /* Prepare the task to send */
415   t_simdata = task->simdata;
416   t_simdata->sender = process;
417   t_simdata->source = ((simdata_process_t) SIMIX_process_self_get_data(process))->m_host;
418
419   xbt_assert(t_simdata->isused == 0,
420               "This task is still being used somewhere else. You cannot send it now. Go fix your code!");
421
422   t_simdata->isused = 1;
423   t_simdata->comm = NULL;
424   msg_global->sent_msg++;
425
426   /* Send it by calling SIMIX network layer */
427   msg_comm_t comm = xbt_new0(s_msg_comm_t, 1);
428   comm->task_sent = task;
429   comm->task_received = NULL;
430   comm->status = MSG_OK;
431   comm->s_comm =
432     simcall_comm_isend(mailbox, t_simdata->message_size,
433                          t_simdata->rate, task, sizeof(void *), match_fun, NULL, match_data, 0);
434   t_simdata->comm = comm->s_comm; /* FIXME: is the field t_simdata->comm still useful? */
435
436   return comm;
437 }
438
439 /** \ingroup msg_task_usage
440  * \brief Sends a task on a mailbox.
441  *
442  * This is a non blocking detached send function.
443  * Think of it as a best effort send. Keep in mind that the third parameter
444  * is only called if the communication fails. If the communication does work,
445  * it is responsibility of the receiver code to free anything related to
446  * the task, as usual. More details on this can be obtained on
447  * <a href="http://lists.gforge.inria.fr/pipermail/simgrid-user/2011-November/002649.html">this thread</a>
448  * in the SimGrid-user mailing list archive.
449  *
450  * \param task a #m_task_t to send on another location.
451  * \param alias name of the mailbox to sent the task to
452  * \param cleanup a function to destroy the task if the
453  * communication fails, e.g. MSG_task_destroy
454  * (if NULL, no function will be called)
455  */
456 void MSG_task_dsend(m_task_t task, const char *alias, void_f_pvoid_t cleanup)
457 {
458   simdata_task_t t_simdata = NULL;
459   m_process_t process = MSG_process_self();
460   msg_mailbox_t mailbox = MSG_mailbox_get_by_alias(alias);
461
462   /* FIXME: these functions are not traceable */
463
464   /* Prepare the task to send */
465   t_simdata = task->simdata;
466   t_simdata->sender = process;
467   t_simdata->source = ((simdata_process_t) SIMIX_process_self_get_data(process))->m_host;
468
469   xbt_assert(t_simdata->isused == 0,
470               "This task is still being used somewhere else. You cannot send it now. Go fix your code!");
471
472   t_simdata->isused = 1;
473   t_simdata->comm = NULL;
474   msg_global->sent_msg++;
475
476   /* Send it by calling SIMIX network layer */
477   smx_action_t comm = simcall_comm_isend(mailbox, t_simdata->message_size,
478                        t_simdata->rate, task, sizeof(void *), NULL, cleanup, NULL, 1);
479   t_simdata->comm = comm;
480 }
481
482 /** \ingroup msg_task_usage
483  * \brief Starts listening for receiving a task from an asynchronous communication.
484  *
485  * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test()
486  * to end the communication.
487  * 
488  * \param task a memory location for storing a #m_task_t. has to be valid until the end of the communication.
489  * \param name of the mailbox to receive the task on
490  * \return the msg_comm_t communication created
491  */
492 msg_comm_t MSG_task_irecv(m_task_t *task, const char *name)
493 {
494   smx_rdv_t rdv = MSG_mailbox_get_by_alias(name);
495
496   /* FIXME: these functions are not traceable */
497
498   /* Sanity check */
499   xbt_assert(task, "Null pointer for the task storage");
500
501   if (*task)
502     XBT_CRITICAL
503         ("MSG_task_irecv() was asked to write in a non empty task struct.");
504
505   /* Try to receive it by calling SIMIX network layer */
506   msg_comm_t comm = xbt_new0(s_msg_comm_t, 1);
507   comm->task_sent = NULL;
508   comm->task_received = task;
509   comm->status = MSG_OK;
510   comm->s_comm = simcall_comm_irecv(rdv, task, NULL, NULL, NULL);
511
512   return comm;
513 }
514
515 /** \ingroup msg_task_usage
516  * \brief Checks whether a communication is done, and if yes, finalizes it.
517  * \param comm the communication to test
518  * \return TRUE if the communication is finished
519  * (but it may have failed, use MSG_comm_get_status() to know its status)
520  * or FALSE if the communication is not finished yet
521  * If the status is FALSE, don't forget to use MSG_process_sleep() after the test.
522  */
523 int MSG_comm_test(msg_comm_t comm)
524 {
525   xbt_ex_t e;
526   int finished = 0;
527   TRY {
528     finished = simcall_comm_test(comm->s_comm);
529
530     if (finished && comm->task_received != NULL) {
531       /* I am the receiver */
532       (*comm->task_received)->simdata->isused = 0;
533     }
534   }
535   CATCH(e) {
536     switch (e.category) {
537
538       case host_error:
539         comm->status = MSG_HOST_FAILURE;
540         finished = 1;
541         break;
542
543       case network_error:
544         comm->status = MSG_TRANSFER_FAILURE;
545         finished = 1;
546         break;
547
548       case timeout_error:
549         comm->status = MSG_TIMEOUT;
550         finished = 1;
551         break;
552
553       default:
554         RETHROW;
555     }
556     xbt_ex_free(e);
557   }
558
559   return finished;
560 }
561
562 /** \ingroup msg_task_usage
563  * \brief This function checks if a communication is finished.
564  * \param comms a vector of communications
565  * \return the position of the finished communication if any
566  * (but it may have failed, use MSG_comm_get_status() to know its status),
567  * or -1 if none is finished
568  */
569 int MSG_comm_testany(xbt_dynar_t comms)
570 {
571   xbt_ex_t e;
572   int finished_index = -1;
573
574   /* create the equivalent dynar with SIMIX objects */
575   xbt_dynar_t s_comms = xbt_dynar_new(sizeof(smx_action_t), NULL);
576   msg_comm_t comm;
577   unsigned int cursor;
578   xbt_dynar_foreach(comms, cursor, comm) {
579     xbt_dynar_push(s_comms, &comm->s_comm);
580   }
581
582   MSG_error_t status = MSG_OK;
583   TRY {
584     finished_index = simcall_comm_testany(s_comms);
585   }
586   CATCH(e) {
587     switch (e.category) {
588
589       case host_error:
590         finished_index = e.value;
591         status = MSG_HOST_FAILURE;
592         break;
593
594       case network_error:
595         finished_index = e.value;
596         status = MSG_TRANSFER_FAILURE;
597         break;
598
599       case timeout_error:
600         finished_index = e.value;
601         status = MSG_TIMEOUT;
602         break;
603
604       default:
605         RETHROW;
606     }
607     xbt_ex_free(e);
608   }
609   xbt_dynar_free(&s_comms);
610
611   if (finished_index != -1) {
612     comm = xbt_dynar_get_as(comms, finished_index, msg_comm_t);
613     /* the communication is finished */
614     comm->status = status;
615
616     if (status == MSG_OK && comm->task_received != NULL) {
617       /* I am the receiver */
618       (*comm->task_received)->simdata->isused = 0;
619     }
620   }
621
622   return finished_index;
623 }
624
625 /** \ingroup msg_task_usage
626  * \brief Destroys a communication.
627  * \param comm the communication to destroy.
628  */
629 void MSG_comm_destroy(msg_comm_t comm)
630 {
631   xbt_free(comm);
632 }
633
634 /** \ingroup msg_task_usage
635  * \brief Wait for the completion of a communication.
636  *
637  * It takes two parameters.
638  * \param comm the communication to wait.
639  * \param timeout Wait until the communication terminates or the timeout 
640  * occurs. You can provide a -1 timeout to obtain an infinite timeout.
641  * \return MSG_error_t
642  */
643 MSG_error_t MSG_comm_wait(msg_comm_t comm, double timeout)
644 {
645   xbt_ex_t e;
646   TRY {
647     simcall_comm_wait(comm->s_comm, timeout);
648
649     if (comm->task_received != NULL) {
650       /* I am the receiver */
651       (*comm->task_received)->simdata->isused = 0;
652     }
653
654     /* FIXME: these functions are not traceable */
655   }
656   CATCH(e) {
657     switch (e.category) {
658     case host_error:
659       comm->status = MSG_HOST_FAILURE;
660       break;
661     case network_error:
662       comm->status = MSG_TRANSFER_FAILURE;
663       break;
664     case timeout_error:
665       comm->status = MSG_TIMEOUT;
666       break;
667     default:
668       RETHROW;
669     }
670     xbt_ex_free(e);
671   }
672
673   return comm->status;
674 }
675
676 /** \ingroup msg_task_usage
677 * \brief This function is called by a sender and permit to wait for each communication
678 *
679 * \param comm a vector of communication
680 * \param nb_elem is the size of the comm vector
681 * \param timeout for each call of MSG_comm_wait
682 */
683 void MSG_comm_waitall(msg_comm_t * comm, int nb_elem, double timeout)
684 {
685   int i = 0;
686   for (i = 0; i < nb_elem; i++) {
687     MSG_comm_wait(comm[i], timeout);
688   }
689 }
690
691 /** \ingroup msg_task_usage
692  * \brief This function waits for the first communication finished in a list.
693  * \param comms a vector of communications
694  * \return the position of the first finished communication
695  * (but it may have failed, use MSG_comm_get_status() to know its status)
696  */
697 int MSG_comm_waitany(xbt_dynar_t comms)
698 {
699   xbt_ex_t e;
700   int finished_index = -1;
701
702   /* create the equivalent dynar with SIMIX objects */
703   xbt_dynar_t s_comms = xbt_dynar_new(sizeof(smx_action_t), NULL);
704   msg_comm_t comm;
705   unsigned int cursor;
706   xbt_dynar_foreach(comms, cursor, comm) {
707     xbt_dynar_push(s_comms, &comm->s_comm);
708   }
709
710   MSG_error_t status = MSG_OK;
711   TRY {
712     finished_index = simcall_comm_waitany(s_comms);
713   }
714   CATCH(e) {
715     switch (e.category) {
716
717       case host_error:
718         finished_index = e.value;
719         status = MSG_HOST_FAILURE;
720         break;
721
722       case network_error:
723         finished_index = e.value;
724         status = MSG_TRANSFER_FAILURE;
725         break;
726
727       case timeout_error:
728         finished_index = e.value;
729         status = MSG_TIMEOUT;
730         break;
731
732       default:
733         RETHROW;
734     }
735     xbt_ex_free(e);
736   }
737
738   xbt_assert(finished_index != -1, "WaitAny returned -1");
739   xbt_dynar_free(&s_comms);
740
741   comm = xbt_dynar_get_as(comms, finished_index, msg_comm_t);
742   /* the communication is finished */
743   comm->status = status;
744
745   if (comm->task_received != NULL) {
746     /* I am the receiver */
747     (*comm->task_received)->simdata->isused = 0;
748   }
749
750   return finished_index;
751 }
752
753 /**
754  * \ingroup msg_task_usage
755  * \brief Returns the error (if any) that occured during a finished communication.
756  * \param comm a finished communication
757  * \return the status of the communication, or #MSG_OK if no error occured
758  * during the communication
759  */
760 MSG_error_t MSG_comm_get_status(msg_comm_t comm) {
761
762   return comm->status;
763 }
764
765 /** \ingroup msg_task_usage
766  * \brief Get a task (#m_task_t) from a communication
767  *
768  * \param comm the communication where to get the task
769  * \return the task from the communication
770  */
771 m_task_t MSG_comm_get_task(msg_comm_t comm)
772 {
773   xbt_assert(comm, "Invalid parameter");
774
775   return comm->task_received ? *comm->task_received : comm->task_sent;
776 }
777
778 /**
779  * \brief This function is called by SIMIX to copy the data of a comm.
780  * \param comm the comm
781  * \param buff the data copied
782  * \param buff_size size of the buffer
783  */
784 void MSG_comm_copy_data_from_SIMIX(smx_action_t comm, void* buff, size_t buff_size) {
785
786   // copy the task
787   SIMIX_comm_copy_pointer_callback(comm, buff, buff_size);
788
789   // notify the user callback if any
790   if (msg_global->task_copy_callback) {
791     m_task_t task = buff;
792     msg_global->task_copy_callback(task,
793         simcall_comm_get_src_proc(comm), simcall_comm_get_dst_proc(comm));
794   }
795 }
796
797 /** \ingroup msg_task_usage
798  * \brief Sends a task to a mailbox
799  *
800  * This is a blocking function, the execution flow will be blocked
801  * until the task is sent (and received in the other side if #MSG_task_receive is used).
802  * See #MSG_task_isend for sending tasks asynchronously.
803  *
804  * \param task the task to be sent
805  * \param alias the mailbox name to where the task is sent
806  *
807  * \return Returns #MSG_OK if the task was successfully sent,
808  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE otherwise.
809  */
810 MSG_error_t MSG_task_send(m_task_t task, const char *alias)
811 {
812   XBT_DEBUG("MSG_task_send: Trying to send a message on mailbox '%s'", alias);
813   return MSG_task_send_with_timeout(task, alias, -1);
814 }
815
816 /** \ingroup msg_task_usage
817  * \brief Sends a task to a mailbox with a maximum rate
818  *
819  * This is a blocking function, the execution flow will be blocked
820  * until the task is sent. The maxrate parameter allows the application
821  * to limit the bandwidth utilization of network links when sending the task.
822  *
823  * \param task the task to be sent
824  * \param alias the mailbox name to where the task is sent
825  * \param maxrate the maximum communication rate for sending this task
826  *
827  * \return Returns #MSG_OK if the task was successfully sent,
828  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE otherwise.
829  */
830 MSG_error_t
831 MSG_task_send_bounded(m_task_t task, const char *alias, double maxrate)
832 {
833   task->simdata->rate = maxrate;
834   return MSG_task_send(task, alias);
835 }
836
837 /** \ingroup msg_task_usage
838  * \brief Sends a task to a mailbox with a timeout
839  *
840  * This is a blocking function, the execution flow will be blocked
841  * until the task is sent or the timeout is achieved.
842  *
843  * \param task the task to be sent
844  * \param alias the mailbox name to where the task is sent
845  * \param timeout is the maximum wait time for completion (if -1, this call is the same as #MSG_task_send)
846  *
847  * \return Returns #MSG_OK if the task was successfully sent,
848  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
849  */
850 MSG_error_t
851 MSG_task_send_with_timeout(m_task_t task, const char *alias,
852                            double timeout)
853 {
854   return MSG_mailbox_put_with_timeout(MSG_mailbox_get_by_alias(alias),
855                                       task, timeout);
856 }
857
858 /** \ingroup msg_task_usage
859  * \brief Check if there is a communication going on in a mailbox.
860  *
861  * \param alias the name of the mailbox to be considered
862  *
863  * \return Returns 1 if there is a communication, 0 otherwise
864  */
865 int MSG_task_listen(const char *alias)
866 {
867   return !MSG_mailbox_is_empty(MSG_mailbox_get_by_alias(alias));
868 }
869
870 /** \ingroup msg_task_usage
871  * \brief Check the number of communication actions of a given host pending in a mailbox.
872  *
873  * \param alias the name of the mailbox to be considered
874  * \param host the host to check for communication
875  *
876  * \return Returns the number of pending communication actions of the host in the
877  * given mailbox, 0 if there is no pending communication actions.
878  *
879  */
880 int MSG_task_listen_from_host(const char *alias, m_host_t host)
881 {
882   return
883       MSG_mailbox_get_count_host_waiting_tasks(MSG_mailbox_get_by_alias
884                                                (alias), host);
885 }
886
887 /** \ingroup msg_task_usage
888  * \brief Look if there is a communication on a mailbox and return the
889  * PID of the sender process.
890  *
891  * \param alias the name of the mailbox to be considered
892  *
893  * \return Returns the PID of sender process,
894  * -1 if there is no communication in the mailbox.
895  */
896 int MSG_task_listen_from(const char *alias)
897 {
898   m_task_t task;
899
900   if (NULL ==
901       (task = MSG_mailbox_get_head(MSG_mailbox_get_by_alias(alias))))
902     return -1;
903
904   return MSG_process_get_PID(task->simdata->sender);
905 }
906
907 /** \ingroup msg_task_usage
908  * \brief Sets the tracing category of a task.
909  *
910  * This function should be called after the creation of
911  * a MSG task, to define the category of that task. The
912  * first parameter task must contain a task that was
913  * created with the function #MSG_task_create. The second
914  * parameter category must contain a category that was
915  * previously declared with the function #TRACE_category
916  * (or with #TRACE_category_with_color).
917  *
918  * See \ref tracing_tracing for details on how to trace
919  * the (categorized) resource utilization.
920  *
921  * \param task the task that is going to be categorized
922  * \param category the name of the category to be associated to the task
923  *
924  * \see MSG_task_get_category, TRACE_category, TRACE_category_with_color
925  */
926 void MSG_task_set_category (m_task_t task, const char *category)
927 {
928 #ifdef HAVE_TRACING
929   TRACE_msg_set_task_category (task, category);
930 #endif
931 }
932
933 /** \ingroup msg_task_usage
934  *
935  * \brief Gets the current tracing category of a task.
936  *
937  * \param task the task to be considered
938  *
939  * \see MSG_task_set_category
940  *
941  * \return Returns the name of the tracing category of the given task, NULL otherwise
942  */
943 const char *MSG_task_get_category (m_task_t task)
944 {
945 #ifdef HAVE_TRACING
946   return task->category;
947 #else
948   return NULL;
949 #endif
950 }
951
952 #ifdef MSG_USE_DEPRECATED
953 /** \ingroup msg_deprecated_functions
954  *
955  * \brief Return the last value returned by a MSG function (except
956  * MSG_get_errno...).
957  */
958 MSG_error_t MSG_get_errno(void)
959 {
960   return PROCESS_GET_ERRNO();
961 }
962
963 /** \ingroup msg_deprecated_functions
964  * \brief Put a task on a channel of an host and waits for the end of the
965  * transmission.
966  *
967  * This function is used for describing the behavior of a process. It
968  * takes three parameter.
969  * \param task a #m_task_t to send on another location. This task
970  will not be usable anymore when the function will return. There is
971  no automatic task duplication and you have to save your parameters
972  before calling this function. Tasks are unique and once it has been
973  sent to another location, you should not access it anymore. You do
974  not need to call MSG_task_destroy() but to avoid using, as an
975  effect of inattention, this task anymore, you definitely should
976  renitialize it with #MSG_TASK_UNINITIALIZED. Note that this task
977  can be transfered iff it has been correctly created with
978  MSG_task_create().
979  * \param dest the destination of the message
980  * \param channel the channel on which the process should put this
981  task. This value has to be >=0 and < than the maximal number of
982  channels fixed with MSG_set_channel_number().
983  * \return #MSG_HOST_FAILURE if the host on which
984  * this function was called was shut down,
985  * #MSG_TRANSFER_FAILURE if the transfer could not be properly done
986  * (network failure, dest failure) or #MSG_OK if it succeeded.
987  */
988 MSG_error_t MSG_task_put(m_task_t task, m_host_t dest, m_channel_t channel)
989 {
990   XBT_WARN("DEPRECATED! Now use MSG_task_send");
991   return MSG_task_put_with_timeout(task, dest, channel, -1.0);
992 }
993
994 /** \ingroup msg_deprecated_functions
995  * \brief Does exactly the same as MSG_task_put but with a bounded transmition
996  * rate.
997  *
998  * \sa MSG_task_put
999  */
1000 MSG_error_t
1001 MSG_task_put_bounded(m_task_t task, m_host_t dest, m_channel_t channel,
1002                      double maxrate)
1003 {
1004   XBT_WARN("DEPRECATED! Now use MSG_task_send_bounded");
1005   task->simdata->rate = maxrate;
1006   return MSG_task_put(task, dest, channel);
1007 }
1008
1009 /** \ingroup msg_deprecated_functions
1010  *
1011  * \brief Put a task on a channel of an
1012  * host (with a timeout on the waiting of the destination host) and
1013  * waits for the end of the transmission.
1014  *
1015  * This function is used for describing the behavior of a process. It
1016  * takes four parameter.
1017  * \param task a #m_task_t to send on another location. This task
1018  will not be usable anymore when the function will return. There is
1019  no automatic task duplication and you have to save your parameters
1020  before calling this function. Tasks are unique and once it has been
1021  sent to another location, you should not access it anymore. You do
1022  not need to call MSG_task_destroy() but to avoid using, as an
1023  effect of inattention, this task anymore, you definitely should
1024  renitialize it with #MSG_TASK_UNINITIALIZED. Note that this task
1025  can be transfered iff it has been correctly created with
1026  MSG_task_create().
1027  * \param dest the destination of the message
1028  * \param channel the channel on which the process should put this
1029  task. This value has to be >=0 and < than the maximal number of
1030  channels fixed with MSG_set_channel_number().
1031  * \param timeout the maximum time to wait for a task before giving
1032  up. In such a case, #MSG_TRANSFER_FAILURE will be returned, \a task
1033  will not be modified
1034  * \return #MSG_HOST_FAILURE if the host on which
1035 this function was called was shut down,
1036 #MSG_TRANSFER_FAILURE if the transfer could not be properly done
1037 (network failure, dest failure, timeout...) or #MSG_OK if the communication succeeded.
1038  */
1039 MSG_error_t
1040 MSG_task_put_with_timeout(m_task_t task, m_host_t dest,
1041                           m_channel_t channel, double timeout)
1042 {
1043   XBT_WARN("DEPRECATED! Now use MSG_task_send_with_timeout");
1044   xbt_assert((channel >= 0)
1045               && (channel < msg_global->max_channel), "Invalid channel %d",
1046               channel);
1047
1048   XBT_DEBUG("MSG_task_put_with_timout: Trying to send a task to '%s'", SIMIX_host_get_name(dest->smx_host));
1049   return
1050       MSG_mailbox_put_with_timeout(MSG_mailbox_get_by_channel
1051                                    (dest, channel), task, timeout);
1052 }
1053
1054 /** \ingroup msg_deprecated_functions
1055  * \brief Test whether there is a pending communication on a channel, and who sent it.
1056  *
1057  * It takes one parameter.
1058  * \param channel the channel on which the process should be
1059  listening. This value has to be >=0 and < than the maximal
1060  number of channels fixed with MSG_set_channel_number().
1061  * \return -1 if there is no pending communication and the PID of the process who sent it otherwise
1062  */
1063 int MSG_task_probe_from(m_channel_t channel)
1064 {
1065   XBT_WARN("DEPRECATED! Now use MSG_task_listen_from");
1066   m_task_t task;
1067
1068   xbt_assert((channel >= 0)
1069               && (channel < msg_global->max_channel), "Invalid channel %d",
1070               channel);
1071
1072   if (NULL ==
1073       (task =
1074        MSG_mailbox_get_head(MSG_mailbox_get_by_channel
1075                             (MSG_host_self(), channel))))
1076     return -1;
1077
1078   return MSG_process_get_PID(task->simdata->sender);
1079 }
1080
1081 /** \ingroup msg_deprecated_functions
1082  * \brief Test whether there is a pending communication on a channel.
1083  *
1084  * It takes one parameter.
1085  * \param channel the channel on which the process should be
1086  listening. This value has to be >=0 and < than the maximal
1087  number of channels fixed with MSG_set_channel_number().
1088  * \return 1 if there is a pending communication and 0 otherwise
1089  */
1090 int MSG_task_Iprobe(m_channel_t channel)
1091 {
1092   XBT_WARN("DEPRECATED!");
1093   xbt_assert((channel >= 0)
1094               && (channel < msg_global->max_channel), "Invalid channel %d",
1095               channel);
1096
1097   return
1098       !MSG_mailbox_is_empty(MSG_mailbox_get_by_channel
1099                             (MSG_host_self(), channel));
1100 }
1101
1102 /** \ingroup msg_deprecated_functions
1103
1104  * \brief Return the number of tasks waiting to be received on a \a
1105  channel and sent by \a host.
1106  *
1107  * It takes two parameters.
1108  * \param channel the channel on which the process should be
1109  listening. This value has to be >=0 and < than the maximal
1110  number of channels fixed with MSG_set_channel_number().
1111  * \param host the host that is to be watched.
1112  * \return the number of tasks waiting to be received on \a channel
1113  and sent by \a host.
1114  */
1115 int MSG_task_probe_from_host(int channel, m_host_t host)
1116 {
1117   XBT_WARN("DEPRECATED! Now use MSG_task_listen_from_host");
1118   xbt_assert((channel >= 0)
1119               && (channel < msg_global->max_channel), "Invalid channel %d",
1120               channel);
1121
1122   return
1123       MSG_mailbox_get_count_host_waiting_tasks(MSG_mailbox_get_by_channel
1124                                                (MSG_host_self(), channel),
1125                                                host);
1126
1127 }
1128
1129 /** \ingroup msg_deprecated_functions
1130  * \brief Listen on \a channel and waits for receiving a task from \a host.
1131  *
1132  * It takes three parameters.
1133  * \param task a memory location for storing a #m_task_t. It will
1134  hold a task when this function will return. Thus \a task should not
1135  be equal to \c NULL and \a *task should be equal to \c NULL. If one of
1136  those two condition does not hold, there will be a warning message.
1137  * \param channel the channel on which the process should be
1138  listening. This value has to be >=0 and < than the maximal
1139  number of channels fixed with MSG_set_channel_number().
1140  * \param host the host that is to be watched.
1141  * \return a #MSG_error_t indicating whether the operation was successful (#MSG_OK), or why it failed otherwise.
1142  */
1143 MSG_error_t
1144 MSG_task_get_from_host(m_task_t * task, m_channel_t channel, m_host_t host)
1145 {
1146   XBT_WARN("DEPRECATED! Now use MSG_task_receive_from_host");
1147   return MSG_task_get_ext(task, channel, -1, host);
1148 }
1149
1150 /** \ingroup msg_deprecated_functions
1151  * \brief Listen on a channel and wait for receiving a task.
1152  *
1153  * It takes two parameters.
1154  * \param task a memory location for storing a #m_task_t. It will
1155  hold a task when this function will return. Thus \a task should not
1156  be equal to \c NULL and \a *task should be equal to \c NULL. If one of
1157  those two condition does not hold, there will be a warning message.
1158  * \param channel the channel on which the process should be
1159  listening. This value has to be >=0 and < than the maximal
1160  number of channels fixed with MSG_set_channel_number().
1161  * \return a #MSG_error_t indicating whether the operation was successful (#MSG_OK), or why it failed otherwise.
1162  */
1163 MSG_error_t MSG_task_get(m_task_t * task, m_channel_t channel)
1164 {
1165   XBT_WARN("DEPRECATED! Now use MSG_task_receive");
1166   return MSG_task_get_with_timeout(task, channel, -1);
1167 }
1168
1169 /** \ingroup msg_deprecated_functions
1170  * \brief Listen on a channel and wait for receiving a task with a timeout.
1171  *
1172  * It takes three parameters.
1173  * \param task a memory location for storing a #m_task_t. It will
1174  hold a task when this function will return. Thus \a task should not
1175  be equal to \c NULL and \a *task should be equal to \c NULL. If one of
1176  those two condition does not hold, there will be a warning message.
1177  * \param channel the channel on which the process should be
1178  listening. This value has to be >=0 and < than the maximal
1179  number of channels fixed with MSG_set_channel_number().
1180  * \param max_duration the maximum time to wait for a task before giving
1181  up. In such a case, #MSG_TRANSFER_FAILURE will be returned, \a task
1182  will not be modified and will still be
1183  equal to \c NULL when returning.
1184  * \return a #MSG_error_t indicating whether the operation was successful (#MSG_OK), or why it failed otherwise.
1185  */
1186 MSG_error_t
1187 MSG_task_get_with_timeout(m_task_t * task, m_channel_t channel,
1188                           double max_duration)
1189 {
1190   XBT_WARN("DEPRECATED! Now use MSG_task_receive_with_timeout");
1191   return MSG_task_get_ext(task, channel, max_duration, NULL);
1192 }
1193
1194 MSG_error_t
1195 MSG_task_get_ext(m_task_t * task, m_channel_t channel, double timeout,
1196                  m_host_t host)
1197 {
1198   XBT_WARN("DEPRECATED! Now use MSG_task_receive_ext");
1199   xbt_assert((channel >= 0)
1200               && (channel < msg_global->max_channel), "Invalid channel %d",
1201               channel);
1202
1203   return
1204       MSG_mailbox_get_task_ext(MSG_mailbox_get_by_channel
1205                                (MSG_host_self(), channel), task, host,
1206                                timeout);
1207 }
1208
1209 #endif