Logo AND Algorithmique Numérique Distribuée

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