Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Return action state on SIMIX_req_host_execution_wait().
[simgrid.git] / src / msg / gos.c
1 /* Copyright (c) 2004, 2005, 2006, 2007, 2008, 2009, 2010. The SimGrid Team.
2  * All rights reserved.                                                     */
3
4 /* This program is free software; you can redistribute it and/or modify it
5  * under the terms of the license (GNU LGPL) which comes with this package. */
6
7 #include "private.h"
8 #include "xbt/sysdep.h"
9 #include "mc/mc.h"
10 #include "xbt/log.h"
11 #include "mailbox.h"
12
13
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_gos, msg,
15                                 "Logging specific to MSG (gos)");
16
17 /** \ingroup msg_gos_functions
18  *
19  * \brief Return the last value returned by a MSG function (except
20  * MSG_get_errno...).
21  */
22 MSG_error_t MSG_get_errno(void)
23 {
24   return PROCESS_GET_ERRNO();
25 }
26
27 /** \ingroup msg_gos_functions
28  * \brief Executes a task and waits for its termination.
29  *
30  * This function is used for describing the behavior of an agent. It
31  * takes only one parameter.
32  * \param task a #m_task_t to execute on the location on which the
33  agent is running.
34  * \return #MSG_FATAL if \a task is not properly initialized and
35  * #MSG_OK otherwise.
36  */
37 MSG_error_t MSG_task_execute(m_task_t task)
38 {
39   simdata_task_t simdata = NULL;
40   m_process_t self = MSG_process_self();
41   e_smx_state_t comp_state;
42   CHECK_HOST();
43
44   simdata = task->simdata;
45
46   xbt_assert0(simdata->host_nb == 0,
47               "This is a parallel task. Go to hell.");
48
49 #ifdef HAVE_TRACING
50   TRACE_msg_task_execute_start(task);
51 #endif
52
53   xbt_assert1((!simdata->compute) && (task->simdata->isused == 0),
54               "This task is executed somewhere else. Go fix your code! %d",
55               task->simdata->isused);
56
57   DEBUG1("Computing on %s", MSG_process_self()->simdata->m_host->name);
58
59   if (simdata->computation_amount == 0) {
60 #ifdef HAVE_TRACING
61     TRACE_msg_task_execute_end(task);
62 #endif
63     return MSG_OK;
64   }
65   simdata->isused=1;
66   simdata->compute =
67       SIMIX_req_host_execute(task->name, SIMIX_host_self(),
68                            simdata->computation_amount,
69                            simdata->priority);
70 #ifdef HAVE_TRACING
71   SIMIX_req_set_category(simdata->compute, task->category);
72 #endif
73
74   self->simdata->waiting_action = simdata->compute;
75   comp_state = SIMIX_req_host_execution_wait(simdata->compute);
76   self->simdata->waiting_action = NULL;
77
78   simdata->isused=0;
79
80   DEBUG2("Execution task '%s' finished in state %d", task->name, comp_state);
81   if (comp_state == SIMIX_DONE) {
82     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
83     SIMIX_req_host_execution_destroy(task->simdata->compute);
84     simdata->computation_amount = 0.0;
85     simdata->comm = NULL;
86     simdata->compute = NULL;
87 #ifdef HAVE_TRACING
88     TRACE_msg_task_execute_end(task);
89 #endif
90     MSG_RETURN(MSG_OK);
91   } else if (SIMIX_req_host_get_state(SIMIX_host_self()) == 0) {
92     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
93     SIMIX_req_host_execution_destroy(task->simdata->compute);
94     simdata->comm = NULL;
95     simdata->compute = NULL;
96 #ifdef HAVE_TRACING
97     TRACE_msg_task_execute_end(task);
98 #endif
99     MSG_RETURN(MSG_HOST_FAILURE);
100   } else {
101     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
102     SIMIX_req_host_execution_destroy(task->simdata->compute);
103     simdata->comm = NULL;
104     simdata->compute = NULL;
105 #ifdef HAVE_TRACING
106     TRACE_msg_task_execute_end(task);
107 #endif
108     MSG_RETURN(MSG_TASK_CANCELLED);
109   }
110 }
111
112 /** \ingroup m_task_management
113  * \brief Creates a new #m_task_t (a parallel one....).
114  *
115  * A constructor for #m_task_t taking six arguments and returning the
116  corresponding object.
117  * \param name a name for the object. It is for user-level information
118  and can be NULL.
119  * \param host_nb the number of hosts implied in the parallel task.
120  * \param host_list an array of \p host_nb m_host_t.
121  * \param computation_amount an array of \p host_nb
122  doubles. computation_amount[i] is the total number of operations
123  that have to be performed on host_list[i].
124  * \param communication_amount an array of \p host_nb* \p host_nb doubles.
125  * \param data a pointer to any data may want to attach to the new
126  object.  It is for user-level information and can be NULL. It can
127  be retrieved with the function \ref MSG_task_get_data.
128  * \see m_task_t
129  * \return The new corresponding object.
130  */
131 m_task_t
132 MSG_parallel_task_create(const char *name, int host_nb,
133                          const m_host_t * host_list,
134                          double *computation_amount,
135                          double *communication_amount, void *data)
136 {
137   int i;
138   simdata_task_t simdata = xbt_new0(s_simdata_task_t, 1);
139   m_task_t task = xbt_new0(s_m_task_t, 1);
140   task->simdata = simdata;
141
142   /* Task structure */
143   task->name = xbt_strdup(name);
144   task->data = data;
145
146   /* Simulator Data */
147   simdata->computation_amount = 0;
148   simdata->message_size = 0;
149   simdata->compute = NULL;
150   simdata->comm = NULL;
151   simdata->rate = -1.0;
152   simdata->isused = 0;
153   simdata->sender = NULL;
154   simdata->receiver = NULL;
155   simdata->source = NULL;
156
157   simdata->host_nb = host_nb;
158   simdata->host_list = xbt_new0(smx_host_t, host_nb);
159   simdata->comp_amount = computation_amount;
160   simdata->comm_amount = communication_amount;
161
162   for (i = 0; i < host_nb; i++)
163     simdata->host_list[i] = host_list[i]->simdata->smx_host;
164
165   return task;
166 }
167
168 MSG_error_t MSG_parallel_task_execute(m_task_t task)
169 {
170   simdata_task_t simdata = NULL;
171   m_process_t self = MSG_process_self();
172   CHECK_HOST();
173
174   simdata = task->simdata;
175
176   xbt_assert0((!simdata->compute)
177               && (task->simdata->isused == 0),
178               "This task is executed somewhere else. Go fix your code!");
179
180   xbt_assert0(simdata->host_nb,
181               "This is not a parallel task. Go to hell.");
182
183   DEBUG1("Parallel computing on %s", MSG_process_self()->simdata->m_host->name);
184
185   simdata->isused=1;
186
187   simdata->compute =
188       SIMIX_req_host_parallel_execute(task->name, simdata->host_nb,
189                                   simdata->host_list,
190                                   simdata->comp_amount,
191                                   simdata->comm_amount, 1.0, -1.0);
192   DEBUG1("Parallel execution action created: %p", simdata->compute);
193
194   self->simdata->waiting_action = simdata->compute;
195   SIMIX_req_host_execution_wait(simdata->compute);
196   self->simdata->waiting_action = NULL;
197
198   DEBUG2("Finished waiting for execution of action %p, state = %d", simdata->compute, SIMIX_req_host_execution_get_state(task->simdata->compute));
199
200   simdata->isused=0;
201
202   if (SIMIX_req_host_execution_get_state(task->simdata->compute) == SIMIX_DONE) {
203     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
204     SIMIX_req_host_execution_destroy(task->simdata->compute);
205     simdata->computation_amount = 0.0;
206     simdata->comm = NULL;
207     simdata->compute = NULL;
208     MSG_RETURN(MSG_OK);
209   } else if (SIMIX_req_host_get_state(SIMIX_host_self()) == 0) {
210     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
211     SIMIX_req_host_execution_destroy(task->simdata->compute);
212     simdata->comm = NULL;
213     simdata->compute = NULL;
214     MSG_RETURN(MSG_HOST_FAILURE);
215   } else {
216     /* action ended, set comm and compute = NULL, the actions is already destroyed in the main function */
217     SIMIX_req_host_execution_destroy(task->simdata->compute);
218     simdata->comm = NULL;
219     simdata->compute = NULL;
220     MSG_RETURN(MSG_TASK_CANCELLED);
221   }
222 }
223
224
225 /** \ingroup msg_gos_functions
226  * \brief Sleep for the specified number of seconds
227  *
228  * Makes the current process sleep until \a time seconds have elapsed.
229  *
230  * \param nb_sec a number of second
231  */
232 MSG_error_t MSG_process_sleep(double nb_sec)
233 {
234   e_smx_state_t state;
235   /*m_process_t proc = MSG_process_self();*/
236
237 #ifdef HAVE_TRACING
238   TRACE_msg_process_sleep_in(MSG_process_self());
239 #endif
240
241   /* create action to sleep */
242   state = SIMIX_req_process_sleep(nb_sec);
243
244   /*proc->simdata->waiting_action = act_sleep;
245
246   FIXME: check if not setting the waiting_action breaks something on msg
247   
248   proc->simdata->waiting_action = NULL;*/
249   
250   if (state == SIMIX_DONE) {
251     if (SIMIX_req_host_get_state(SIMIX_host_self()) == SURF_RESOURCE_OFF) {
252 #ifdef HAVE_TRACING
253       TRACE_msg_process_sleep_out(MSG_process_self());
254 #endif
255       MSG_RETURN(MSG_HOST_FAILURE);
256     }
257   } else {
258 #ifdef HAVE_TRACING
259     TRACE_msg_process_sleep_out(MSG_process_self());
260 #endif
261     MSG_RETURN(MSG_HOST_FAILURE);
262   }
263 #ifdef HAVE_TRACING
264   TRACE_msg_process_sleep_out(MSG_process_self());
265 #endif
266   MSG_RETURN(MSG_OK);
267 }
268
269 /** \ingroup msg_gos_functions
270  * \brief Listen on \a channel and waits for receiving a task from \a host.
271  *
272  * It takes three parameters.
273  * \param task a memory location for storing a #m_task_t. It will
274  hold a task when this function will return. Thus \a task should not
275  be equal to \c NULL and \a *task should be equal to \c NULL. If one of
276  those two condition does not hold, there will be a warning message.
277  * \param channel the channel on which the agent should be
278  listening. This value has to be >=0 and < than the maximal
279  number of channels fixed with MSG_set_channel_number().
280  * \param host the host that is to be watched.
281  * \return #MSG_FATAL if \a task is equal to \c NULL, #MSG_WARNING
282  if \a *task is not equal to \c NULL, and #MSG_OK otherwise.
283  */
284 MSG_error_t
285 MSG_task_get_from_host(m_task_t * task, m_channel_t channel, m_host_t host)
286 {
287   return MSG_task_get_ext(task, channel, -1, host);
288 }
289
290 /** \ingroup msg_gos_functions
291  * \brief Listen on a channel and wait for receiving a task.
292  *
293  * It takes two parameters.
294  * \param task a memory location for storing a #m_task_t. It will
295  hold a task when this function will return. Thus \a task should not
296  be equal to \c NULL and \a *task should be equal to \c NULL. If one of
297  those two condition does not hold, there will be a warning message.
298  * \param channel the channel on which the agent should be
299  listening. This value has to be >=0 and < than the maximal
300  number of channels fixed with MSG_set_channel_number().
301  * \return #MSG_FATAL if \a task is equal to \c NULL, #MSG_WARNING
302  * if \a *task is not equal to \c NULL, and #MSG_OK otherwise.
303  */
304 MSG_error_t MSG_task_get(m_task_t * task, m_channel_t channel)
305 {
306   return MSG_task_get_with_timeout(task, channel, -1);
307 }
308
309 /** \ingroup msg_gos_functions
310  * \brief Listen on a channel and wait for receiving a task with a timeout.
311  *
312  * It takes three parameters.
313  * \param task a memory location for storing a #m_task_t. It will
314  hold a task when this function will return. Thus \a task should not
315  be equal to \c NULL and \a *task should be equal to \c NULL. If one of
316  those two condition does not hold, there will be a warning message.
317  * \param channel the channel on which the agent should be
318  listening. This value has to be >=0 and < than the maximal
319  number of channels fixed with MSG_set_channel_number().
320  * \param max_duration the maximum time to wait for a task before giving
321  up. In such a case, #MSG_TRANSFER_FAILURE will be returned, \a task
322  will not be modified and will still be
323  equal to \c NULL when returning.
324  * \return #MSG_FATAL if \a task is equal to \c NULL, #MSG_WARNING
325  if \a *task is not equal to \c NULL, and #MSG_OK otherwise.
326  */
327 MSG_error_t
328 MSG_task_get_with_timeout(m_task_t * task, m_channel_t channel,
329                           double max_duration)
330 {
331   return MSG_task_get_ext(task, channel, max_duration, NULL);
332 }
333
334 /** \defgroup msg_gos_functions MSG Operating System Functions
335  *  \brief This section describes the functions that can be used
336  *  by an agent for handling some task.
337  */
338
339 MSG_error_t
340 MSG_task_get_ext(m_task_t * task, m_channel_t channel, double timeout,
341                  m_host_t host)
342 {
343   xbt_assert1((channel >= 0)
344               && (channel < msg_global->max_channel), "Invalid channel %d",
345               channel);
346
347   return
348       MSG_mailbox_get_task_ext(MSG_mailbox_get_by_channel
349                                (MSG_host_self(), channel), task, host,
350                                timeout);
351 }
352
353 MSG_error_t
354 MSG_task_receive_from_host(m_task_t * task, const char *alias,
355                            m_host_t host)
356 {
357   return MSG_task_receive_ext(task, alias, -1, host);
358 }
359
360 MSG_error_t MSG_task_receive(m_task_t * task, const char *alias)
361 {
362   return MSG_task_receive_with_timeout(task, alias, -1);
363 }
364
365 MSG_error_t
366 MSG_task_receive_with_timeout(m_task_t * task, const char *alias,
367                               double timeout)
368 {
369   return MSG_task_receive_ext(task, alias, timeout, NULL);
370 }
371
372 MSG_error_t
373 MSG_task_receive_ext(m_task_t * task, const char *alias, double timeout,
374                      m_host_t host)
375 {
376   DEBUG1
377       ("MSG_task_receive_ext: Trying to receive a message on mailbox '%s'",
378        alias);
379   return MSG_mailbox_get_task_ext(MSG_mailbox_get_by_alias(alias), task,
380                                   host, timeout);
381 }
382
383 /** \ingroup msg_gos_functions
384  * \brief Send a task on a channel.
385  *
386  * This function takes two parameter.
387  * \param task a #m_task_t to send on another location.
388  * \param alias the channel on which the agent should put this
389  task. This value has to be >=0 and < than the maximal number of
390  channels fixed with MSG_set_channel_number().
391  * \return the msg_comm_t communication.
392  */
393 msg_comm_t MSG_task_isend(m_task_t task, const char *alias)
394 {
395   simdata_task_t t_simdata = NULL;
396   m_process_t process = MSG_process_self();
397   msg_mailbox_t mailbox = MSG_mailbox_get_by_alias(alias);
398
399   CHECK_HOST();
400
401   /* FIXME: these functions are not tracable */
402
403   /* Prepare the task to send */
404   t_simdata = task->simdata;
405   t_simdata->sender = process;
406   t_simdata->source = MSG_host_self();
407
408   xbt_assert0(t_simdata->isused == 0,
409               "This task is still being used somewhere else. You cannot send it now. Go fix your code!");
410
411   t_simdata->isused=1;
412   msg_global->sent_msg++;
413
414   /* Send it by calling SIMIX network layer */
415   t_simdata->comm =
416     SIMIX_req_comm_isend(mailbox, t_simdata->message_size,
417                          t_simdata->rate, task, sizeof(void *), NULL, NULL);
418   return t_simdata->comm;
419 }
420
421 /** \ingroup msg_gos_functions
422  * \brief Listen on a channel for receiving a task from an asynchronous communication.
423  *
424  * It takes two parameters.
425  * \param task a memory location for storing a #m_task_t.
426  * \param alias the channel on which the agent should be
427  listening. This value has to be >=0 and < than the maximal
428  number of channels fixed with MSG_set_channel_number().
429  * \return the msg_comm_t communication.
430  */
431 msg_comm_t MSG_task_irecv(m_task_t * task, const char *alias)
432 {
433   smx_rdv_t rdv = MSG_mailbox_get_by_alias(alias);
434
435   CHECK_HOST();
436
437   /* FIXME: these functions are not tracable */
438
439   /* Sanity check */
440   xbt_assert0(task, "Null pointer for the task storage");
441
442   if (*task)
443     CRITICAL0
444         ("MSG_task_get() was asked to write in a non empty task struct.");
445
446   /* Try to receive it by calling SIMIX network layer */
447   return SIMIX_req_comm_irecv(rdv, task, NULL, NULL, NULL);
448 }
449
450 /** \ingroup msg_gos_functions
451  * \brief Returns whether a communication is finished.
452  * \param comm the communication to test
453  * \return TRUE if the communication is finished
454  * (but it may have failed, use MSG_comm_get_status() to know its status)
455  * or FALSE if the communication is not finished yet
456  * If the status is FALSE, don't forget to use MSG_process_sleep() after the test.
457  */
458 int MSG_comm_test(msg_comm_t comm)
459 {
460   xbt_ex_t e;
461   int finished = 0;
462   TRY {
463     finished = SIMIX_req_comm_test(comm);
464   }
465   CATCH(e) {
466     switch (e.category) {
467
468       case host_error:
469       case network_error:
470       case timeout_error:
471         finished = 1;
472         break;
473
474       default:
475         RETHROW;
476     }
477     xbt_ex_free(e);
478   }
479   return finished;
480 }
481
482 /** \ingroup msg_gos_functions
483  * \brief This function checks if a communication is finished
484  * \param comms a vector of communications
485  * \return the position of the finished communication if any
486  * (but it may have failed, use MSG_comm_get_status() to know its status),
487  * or -1 if none is finished
488  */
489 int MSG_comm_testany(xbt_dynar_t comms)
490 {
491   xbt_ex_t e;
492   int finished_index = -1;
493   TRY {
494     finished_index = SIMIX_req_comm_testany(comms);
495   }
496   CATCH(e) {
497     switch (e.category) {
498
499       case host_error:
500       case network_error:
501       case timeout_error:
502         finished_index = e.value;
503         break;
504
505       default:
506         RETHROW;
507     }
508     xbt_ex_free(e);
509   }
510   return finished_index;
511 }
512
513 /** \ingroup msg_gos_functions
514  * \brief After received TRUE to MSG_comm_test(), the communication should be destroyed.
515  *
516  * It takes one parameter.
517  * \param comm the communication to destroy.
518  */
519 void MSG_comm_destroy(msg_comm_t comm)
520 {
521   if (SIMIX_req_comm_get_src_proc(comm) != SIMIX_process_self()
522       && MSG_comm_get_status(comm) == MSG_OK) {
523     m_task_t task;
524     task = (m_task_t) SIMIX_req_comm_get_src_buff(comm);
525     task->simdata->isused=0;
526   }
527   SIMIX_req_comm_destroy(comm);
528 }
529
530 /** \ingroup msg_gos_functions
531  * \brief Wait for the completion of a communication.
532  *
533  * It takes two parameters.
534  * \param comm the communication to wait.
535  * \param timeout Wait until the communication terminates or the timeout occurs
536  * \return MSG_error_t
537  */
538 MSG_error_t MSG_comm_wait(msg_comm_t comm, double timeout)
539 {
540   xbt_ex_t e;
541   MSG_error_t res = MSG_OK;
542   TRY {
543     SIMIX_req_comm_wait(comm, timeout);
544
545     if (SIMIX_req_comm_get_src_proc(comm) != SIMIX_process_self()) {
546       m_task_t task;
547       task = (m_task_t) SIMIX_req_comm_get_src_buff(comm);
548       task->simdata->isused=0;
549     }
550
551     /* FIXME: these functions are not tracable */
552   }
553   CATCH(e) {
554     switch (e.category) {
555     case host_error:
556       res = MSG_HOST_FAILURE;
557       break;
558     case network_error:
559       res = MSG_TRANSFER_FAILURE;
560       break;
561     case timeout_error:
562       res = MSG_TIMEOUT;
563       break;
564     default:
565       RETHROW;
566     }
567     xbt_ex_free(e);
568   }
569   return res;
570 }
571
572 /** \ingroup msg_gos_functions
573 * \brief This function is called by a sender and permit to wait for each communication
574 *
575 * It takes three parameters.
576 * \param comm a vector of communication
577 * \param nb_elem is the size of the comm vector
578 * \param timeout for each call of  MSG_comm_wait
579 */
580 void MSG_comm_waitall(msg_comm_t * comm, int nb_elem, double timeout)
581 {
582   int i = 0;
583   for (i = 0; i < nb_elem; i++) {
584     MSG_comm_wait(comm[i], timeout);
585   }
586 }
587
588 /** \ingroup msg_gos_functions
589 * \brief This function wait for the first completed communication
590 *
591 * It takes on parameter.
592 * \param comms a vector of communication
593 * \return the position of the completed communication from the xbt_dynar_t.
594 */
595 int MSG_comm_waitany(xbt_dynar_t comms)
596 {
597   xbt_ex_t e;
598   int finished_index = -1;
599   TRY {
600     finished_index = SIMIX_req_comm_waitany(comms);
601   }
602   CATCH(e) {
603     switch (e.category) {
604
605       case host_error:
606       case network_error:
607       case timeout_error:
608         finished_index = e.value;
609       default:
610         RETHROW;
611     }
612     xbt_ex_free(e);
613   }
614   return finished_index;
615 }
616
617 /**
618  * \ingroup msg_gos_functions
619  * \brief Returns the error (if any) that occured during a finished communication.
620  * \param comm a finished communication
621  * \return the status of the communication, or MSG_OK if the communication
622  * was successfully completed
623  */
624 MSG_error_t MSG_comm_get_status(msg_comm_t comm) {
625
626   MSG_error_t result;
627   e_smx_state_t smx_state = SIMIX_req_comm_get_state(comm);
628
629   switch (smx_state) {
630
631     case SIMIX_CANCELED:
632       result = MSG_TASK_CANCELLED;
633       break;
634
635     case SIMIX_FAILED:
636     case SIMIX_SRC_HOST_FAILURE:
637     case SIMIX_DST_HOST_FAILURE:
638       result = MSG_HOST_FAILURE;
639       break;
640
641     case SIMIX_LINK_FAILURE:
642       result = MSG_TRANSFER_FAILURE;
643       break;
644
645     case SIMIX_SRC_TIMEOUT:
646     case SIMIX_DST_TIMEOUT:
647       result = MSG_TIMEOUT;
648       break;
649
650     default:
651       result = MSG_OK;
652       break;
653   }
654   return result;
655 }
656
657 m_task_t MSG_comm_get_task(msg_comm_t comm)
658 {
659   xbt_assert0(comm, "Invalid parameters");
660   return (m_task_t) SIMIX_req_comm_get_src_buff(comm);
661 }
662
663 /** \ingroup msg_gos_functions
664  * \brief Put a task on a channel of an host and waits for the end of the
665  * transmission.
666  *
667  * This function is used for describing the behavior of an agent. It
668  * takes three parameter.
669  * \param task a #m_task_t to send on another location. This task
670  will not be usable anymore when the function will return. There is
671  no automatic task duplication and you have to save your parameters
672  before calling this function. Tasks are unique and once it has been
673  sent to another location, you should not access it anymore. You do
674  not need to call MSG_task_destroy() but to avoid using, as an
675  effect of inattention, this task anymore, you definitely should
676  renitialize it with #MSG_TASK_UNINITIALIZED. Note that this task
677  can be transfered iff it has been correctly created with
678  MSG_task_create().
679  * \param dest the destination of the message
680  * \param channel the channel on which the agent should put this
681  task. This value has to be >=0 and < than the maximal number of
682  channels fixed with MSG_set_channel_number().
683  * \return #MSG_FATAL if \a task is not properly initialized and
684  * #MSG_OK otherwise. Returns #MSG_HOST_FAILURE if the host on which
685  * this function was called was shut down. Returns
686  * #MSG_TRANSFER_FAILURE if the transfer could not be properly done
687  * (network failure, dest failure)
688  */
689 MSG_error_t MSG_task_put(m_task_t task, m_host_t dest, m_channel_t channel)
690 {
691   return MSG_task_put_with_timeout(task, dest, channel, -1.0);
692 }
693
694 /** \ingroup msg_gos_functions
695  * \brief Does exactly the same as MSG_task_put but with a bounded transmition
696  * rate.
697  *
698  * \sa MSG_task_put
699  */
700 MSG_error_t
701 MSG_task_put_bounded(m_task_t task, m_host_t dest, m_channel_t channel,
702                      double maxrate)
703 {
704   task->simdata->rate = maxrate;
705   return MSG_task_put(task, dest, channel);
706 }
707
708 /** \ingroup msg_gos_functions \brief Put a task on a channel of an
709  * host (with a timeout on the waiting of the destination host) and
710  * waits for the end of the transmission.
711  *
712  * This function is used for describing the behavior of an agent. It
713  * takes four parameter.
714  * \param task a #m_task_t to send on another location. This task
715  will not be usable anymore when the function will return. There is
716  no automatic task duplication and you have to save your parameters
717  before calling this function. Tasks are unique and once it has been
718  sent to another location, you should not access it anymore. You do
719  not need to call MSG_task_destroy() but to avoid using, as an
720  effect of inattention, this task anymore, you definitely should
721  renitialize it with #MSG_TASK_UNINITIALIZED. Note that this task
722  can be transfered iff it has been correctly created with
723  MSG_task_create().
724  * \param dest the destination of the message
725  * \param channel the channel on which the agent should put this
726  task. This value has to be >=0 and < than the maximal number of
727  channels fixed with MSG_set_channel_number().
728  * \param timeout the maximum time to wait for a task before giving
729  up. In such a case, #MSG_TRANSFER_FAILURE will be returned, \a task
730  will not be modified
731  * \return #MSG_FATAL if \a task is not properly initialized and
732 #MSG_OK otherwise. Returns #MSG_HOST_FAILURE if the host on which
733 this function was called was shut down. Returns
734 #MSG_TRANSFER_FAILURE if the transfer could not be properly done
735 (network failure, dest failure, timeout...)
736  */
737 MSG_error_t
738 MSG_task_put_with_timeout(m_task_t task, m_host_t dest,
739                           m_channel_t channel, double timeout)
740 {
741   xbt_assert1((channel >= 0)
742               && (channel < msg_global->max_channel), "Invalid channel %d",
743               channel);
744
745   DEBUG1("MSG_task_put_with_timout: Trying to send a task to '%s'", dest->name);
746   return
747       MSG_mailbox_put_with_timeout(MSG_mailbox_get_by_channel
748                                    (dest, channel), task, timeout);
749 }
750
751 MSG_error_t MSG_task_send(m_task_t task, const char *alias)
752 {
753   DEBUG1("MSG_task_send: Trying to send a message on mailbox '%s'", alias);
754   return MSG_task_send_with_timeout(task, alias, -1);
755 }
756
757
758 MSG_error_t
759 MSG_task_send_bounded(m_task_t task, const char *alias, double maxrate)
760 {
761   task->simdata->rate = maxrate;
762   return MSG_task_send(task, alias);
763 }
764
765
766 MSG_error_t
767 MSG_task_send_with_timeout(m_task_t task, const char *alias,
768                            double timeout)
769 {
770   return MSG_mailbox_put_with_timeout(MSG_mailbox_get_by_alias(alias),
771                                       task, timeout);
772 }
773
774 int MSG_task_listen(const char *alias)
775 {
776   CHECK_HOST();
777
778   return !MSG_mailbox_is_empty(MSG_mailbox_get_by_alias(alias));
779 }
780
781 /** \ingroup msg_gos_functions
782  * \brief Test whether there is a pending communication on a channel.
783  *
784  * It takes one parameter.
785  * \param channel the channel on which the agent should be
786  listening. This value has to be >=0 and < than the maximal
787  number of channels fixed with MSG_set_channel_number().
788  * \return 1 if there is a pending communication and 0 otherwise
789  */
790 int MSG_task_Iprobe(m_channel_t channel)
791 {
792   xbt_assert1((channel >= 0)
793               && (channel < msg_global->max_channel), "Invalid channel %d",
794               channel);
795
796   CHECK_HOST();
797
798   return
799       !MSG_mailbox_is_empty(MSG_mailbox_get_by_channel
800                             (MSG_host_self(), channel));
801 }
802
803 /** \ingroup msg_gos_functions
804
805  * \brief Return the number of tasks waiting to be received on a \a
806  channel and sent by \a host.
807  *
808  * It takes two parameters.
809  * \param channel the channel on which the agent should be
810  listening. This value has to be >=0 and < than the maximal
811  number of channels fixed with MSG_set_channel_number().
812  * \param host the host that is to be watched.
813  * \return the number of tasks waiting to be received on \a channel
814  and sent by \a host.
815  */
816 int MSG_task_probe_from_host(int channel, m_host_t host)
817 {
818   xbt_assert1((channel >= 0)
819               && (channel < msg_global->max_channel), "Invalid channel %d",
820               channel);
821
822   CHECK_HOST();
823
824   return
825       MSG_mailbox_get_count_host_waiting_tasks(MSG_mailbox_get_by_channel
826                                                (MSG_host_self(), channel),
827                                                host);
828
829 }
830
831 int MSG_task_listen_from_host(const char *alias, m_host_t host)
832 {
833   CHECK_HOST();
834
835   return
836       MSG_mailbox_get_count_host_waiting_tasks(MSG_mailbox_get_by_alias
837                                                (alias), host);
838 }
839
840 /** \ingroup msg_gos_functions
841  * \brief Test whether there is a pending communication on a channel, and who sent it.
842  *
843  * It takes one parameter.
844  * \param channel the channel on which the agent should be
845  listening. This value has to be >=0 and < than the maximal
846  number of channels fixed with MSG_set_channel_number().
847  * \return -1 if there is no pending communication and the PID of the process who sent it otherwise
848  */
849 int MSG_task_probe_from(m_channel_t channel)
850 {
851   m_task_t task;
852
853   CHECK_HOST();
854
855   xbt_assert1((channel >= 0)
856               && (channel < msg_global->max_channel), "Invalid channel %d",
857               channel);
858
859   if (NULL ==
860       (task =
861        MSG_mailbox_get_head(MSG_mailbox_get_by_channel
862                             (MSG_host_self(), channel))))
863     return -1;
864
865   return MSG_process_get_PID(task->simdata->sender);
866 }
867
868 int MSG_task_listen_from(const char *alias)
869 {
870   m_task_t task;
871
872   CHECK_HOST();
873
874   if (NULL ==
875       (task = MSG_mailbox_get_head(MSG_mailbox_get_by_alias(alias))))
876     return -1;
877
878   return MSG_process_get_PID(task->simdata->sender);
879 }