Logo AND Algorithmique Numérique Distribuée

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