Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
137787b15f9c3d9c94c78e9cdc56778d30804e90
[simgrid.git] / src / msg / msg_gos.cpp
1 /* Copyright (c) 2004-2015. 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 "msg_private.h"
8 #include "mc/mc.h"
9 #include "xbt/log.h"
10 #include "xbt/sysdep.h"
11
12 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(msg_gos, msg,
13                                 "Logging specific to MSG (gos)");
14
15 /** \ingroup msg_task_usage
16  * \brief Executes a task and waits for its termination.
17  *
18  * This function is used for describing the behavior of a process. It
19  * takes only one parameter.
20  * \param task a #msg_task_t to execute on the location on which the process is running.
21  * \return #MSG_OK if the task was successfully completed, #MSG_TASK_CANCELED
22  * or #MSG_HOST_FAILURE otherwise
23  */
24 msg_error_t MSG_task_execute(msg_task_t task)
25 {
26   /* TODO: add this to other locations */
27   msg_host_t host = MSG_process_get_host(MSG_process_self());
28   MSG_host_add_task(host, task);
29
30   msg_error_t ret = MSG_parallel_task_execute(task);
31
32   MSG_host_del_task(host, task);
33
34   return ret;
35 }
36
37 /** \ingroup msg_task_usage
38  * \brief Executes a parallel task and waits for its termination.
39  *
40  * \param task a #msg_task_t to execute on the location on which the process is running.
41  *
42  * \return #MSG_OK if the task was successfully completed, #MSG_TASK_CANCELED
43  * or #MSG_HOST_FAILURE otherwise
44  */
45 msg_error_t MSG_parallel_task_execute(msg_task_t task)
46 {
47   xbt_ex_t e;
48   simdata_task_t simdata = task->simdata;
49   msg_process_t self = SIMIX_process_self();
50   simdata_process_t p_simdata = (simdata_process_t) SIMIX_process_self_get_data(self);
51   e_smx_state_t comp_state;
52   msg_error_t status = MSG_OK;
53
54   TRACE_msg_task_execute_start(task);
55
56   xbt_assert((!simdata->compute) && (task->simdata->isused == 0),
57              "This task is executed somewhere else. Go fix your code! %d",
58              task->simdata->isused!=NULL);
59
60   XBT_DEBUG("Computing on %s", MSG_process_get_name(MSG_process_self()));
61
62   if (simdata->flops_amount == 0 && !simdata->host_nb) {
63     TRACE_msg_task_execute_end(task);
64     return MSG_OK;
65   }
66
67
68   TRY {
69     if (msg_global->debug_multiple_use)
70       MSG_BT(simdata->isused, "Using Backtrace");
71     else
72       simdata->isused = (void*)1;
73
74     if (simdata->host_nb > 0) {
75       simdata->compute = simcall_execution_parallel_start(task->name,
76                                                        simdata->host_nb,
77                                                        simdata->host_list,
78                                                        simdata->flops_parallel_amount,
79                                                        simdata->bytes_parallel_amount,
80                                                        1.0, -1.0);
81       XBT_DEBUG("Parallel execution action created: %p", simdata->compute);
82     } else {
83       unsigned long affinity_mask = (unsigned long)(uintptr_t) xbt_dict_get_or_null_ext(simdata->affinity_mask_db, (char *) p_simdata->m_host, sizeof(msg_host_t));
84       XBT_DEBUG("execute %s@%s with affinity(0x%04lx)", MSG_task_get_name(task), MSG_host_get_name(p_simdata->m_host), affinity_mask);
85
86       simdata->compute = simcall_execution_start(task->name,
87                                               simdata->flops_amount,
88                                               simdata->priority,
89                                               simdata->bound,
90                                               affinity_mask
91                                               );
92
93     }
94     simcall_set_category(simdata->compute, task->category);
95     p_simdata->waiting_action = simdata->compute;
96     comp_state = simcall_execution_wait(simdata->compute);
97
98     p_simdata->waiting_action = NULL;
99
100     if (msg_global->debug_multiple_use && simdata->isused!=0)
101       xbt_ex_free(*(xbt_ex_t*)simdata->isused);
102     simdata->isused = 0;
103
104     XBT_DEBUG("Execution task '%s' finished in state %d",
105               task->name, (int)comp_state);
106   }
107   CATCH(e) {
108     switch (e.category) {
109     case cancel_error:
110       status = MSG_TASK_CANCELED;
111       break;
112     case host_error:
113       status = MSG_HOST_FAILURE;
114       break;
115     default:
116       RETHROW;
117     }
118     xbt_ex_free(e);
119   }
120   /* action ended, set comm and compute = NULL, the actions is already destroyed
121    * in the main function */
122   simdata->flops_amount = 0.0;
123   simdata->comm = NULL;
124   simdata->compute = NULL;
125   TRACE_msg_task_execute_end(task);
126
127   MSG_RETURN(status);
128 }
129
130
131 /** \ingroup msg_task_usage
132  * \brief Sleep for the specified number of seconds
133  *
134  * Makes the current process sleep until \a time seconds have elapsed.
135  *
136  * \param nb_sec a number of second
137  */
138 msg_error_t MSG_process_sleep(double nb_sec)
139 {
140   xbt_ex_t e;
141   msg_error_t status = MSG_OK;
142   /*msg_process_t proc = MSG_process_self();*/
143
144   TRACE_msg_process_sleep_in(MSG_process_self());
145
146   TRY {
147     simcall_process_sleep(nb_sec);
148   }
149   CATCH(e) {
150     switch (e.category) {
151     case cancel_error:
152       XBT_DEBUG("According to the JAVA API, a sleep call should only deal with HostFailureException, WTF here ?"); 
153       // adsein: MSG_TASK_CANCELED is assigned when someone kills the process that made the sleep, this is not
154       // correct. For instance, when the node is turned off, the error should be MSG_HOST_FAILURE, which is by the way
155       // and according to the JAVA document, the only exception that can be triggered by MSG_Process_sleep call.
156       // To avoid possible impacts in the code, I just raised a host_failure exception for the moment in the JAVA code
157       // and did not change anythings at the C level.
158       // See comment in the jmsg_process.c file, function JNIEXPORT void JNICALL Java_org_simgrid_msg_Process_sleep(JNIEnv *env, jclass cls, jlong jmillis, jint jnanos) 
159       status = MSG_TASK_CANCELED;
160       break;
161     default:
162       RETHROW;
163     }
164     xbt_ex_free(e);
165   }
166
167   TRACE_msg_process_sleep_out(MSG_process_self());
168   MSG_RETURN(status);
169 }
170
171 /** \ingroup msg_task_usage
172  * \brief Receives a task from a mailbox.
173  *
174  * This is a blocking function, the execution flow will be blocked
175  * until the task is received. See #MSG_task_irecv
176  * for receiving tasks asynchronously.
177  *
178  * \param task a memory location for storing a #msg_task_t.
179  * \param alias name of the mailbox to receive the task from
180  *
181  * \return Returns
182  * #MSG_OK if the task was successfully received,
183  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE otherwise.
184  */
185 msg_error_t MSG_task_receive(msg_task_t * task, const char *alias)
186 {
187   return MSG_task_receive_with_timeout(task, alias, -1);
188 }
189
190 /** \ingroup msg_task_usage
191  * \brief Receives a task from a mailbox at a given rate.
192  *
193  * \param task a memory location for storing a #msg_task_t.
194  * \param alias name of the mailbox to receive the task from
195  *  \param rate limit the reception to rate bandwidth
196  *
197  * \return Returns
198  * #MSG_OK if the task was successfully received,
199  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE otherwise.
200  */
201 msg_error_t MSG_task_receive_bounded(msg_task_t * task, const char *alias,
202                                      double rate)
203 {
204   return MSG_task_receive_with_timeout_bounded(task, alias, -1, rate);
205 }
206
207 /** \ingroup msg_task_usage
208  * \brief Receives a task from a mailbox with a given timeout.
209  *
210  * This is a blocking function with a timeout, the execution flow will be blocked
211  * until the task is received or the timeout is achieved. See #MSG_task_irecv
212  * for receiving tasks asynchronously.  You can provide a -1 timeout
213  * to obtain an infinite timeout.
214  *
215  * \param task a memory location for storing a #msg_task_t.
216  * \param alias name of the mailbox to receive the task from
217  * \param timeout is the maximum wait time for completion (if -1, this call is the same as #MSG_task_receive)
218  *
219  * \return Returns
220  * #MSG_OK if the task was successfully received,
221  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
222  */
223 msg_error_t
224 MSG_task_receive_with_timeout(msg_task_t * task, const char *alias,
225                               double timeout)
226 {
227   return MSG_task_receive_ext(task, alias, timeout, NULL);
228 }
229
230 /** \ingroup msg_task_usage
231  * \brief Receives a task from a mailbox with a given timeout and at a given rate.
232  *
233  * \param task a memory location for storing a #msg_task_t.
234  * \param alias name of the mailbox to receive the task from
235  * \param timeout is the maximum wait time for completion (if -1, this call is the same as #MSG_task_receive)
236  *  \param rate limit the reception to rate bandwidth
237  *
238  * \return Returns
239  * #MSG_OK if the task was successfully received,
240  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
241  */
242 msg_error_t
243 MSG_task_receive_with_timeout_bounded(msg_task_t * task, const char *alias,
244                                       double timeout,double rate)
245 {
246   return MSG_task_receive_ext_bounded(task, alias, timeout, NULL, rate);
247 }
248
249 /** \ingroup msg_task_usage
250  * \brief Receives a task from a mailbox from a specific host with a given timeout.
251  *
252  * This is a blocking function with a timeout, the execution flow will be blocked
253  * until the task is received or the timeout is achieved. See #MSG_task_irecv
254  * for receiving tasks asynchronously. You can provide a -1 timeout
255  * to obtain an infinite timeout.
256  *
257  * \param task a memory location for storing a #msg_task_t.
258  * \param alias name of the mailbox to receive the task from
259  * \param timeout is the maximum wait time for completion (provide -1 for no timeout)
260  * \param host a #msg_host_t host from where the task was sent
261  *
262  * \return Returns
263  * #MSG_OK if the task was successfully received,
264 * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
265  */
266 msg_error_t
267 MSG_task_receive_ext(msg_task_t * task, const char *alias, double timeout,
268                      msg_host_t host)
269 {
270   xbt_ex_t e;
271   msg_error_t ret = MSG_OK;
272   XBT_DEBUG
273       ("MSG_task_receive_ext: Trying to receive a message on mailbox '%s'",
274        alias);
275   TRY {
276     ret = MSG_mailbox_get_task_ext(MSG_mailbox_get_by_alias(alias), task,
277                                    host, timeout);
278   }
279   CATCH(e) {
280     switch (e.category) {
281     case cancel_error:          /* may be thrown by MSG_mailbox_get_by_alias */
282       ret = MSG_HOST_FAILURE;
283       break;
284     default:
285       RETHROW;
286     }
287     xbt_ex_free(e);
288   }
289   return ret;
290 }
291
292 /** \ingroup msg_task_usage
293  * \brief Receives a task from a mailbox from a specific host with a given timeout
294  *  and at a given rate.
295  *
296  * \param task a memory location for storing a #msg_task_t.
297  * \param alias name of the mailbox to receive the task from
298  * \param timeout is the maximum wait time for completion (provide -1 for no timeout)
299  * \param host a #msg_host_t host from where the task was sent
300  * \param rate limit the reception to rate bandwidth
301  *
302  * \return Returns
303  * #MSG_OK if the task was successfully received,
304 * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
305  */
306 msg_error_t
307 MSG_task_receive_ext_bounded(msg_task_t * task, const char *alias, double timeout,
308                              msg_host_t host, double rate)
309 {
310   XBT_DEBUG
311       ("MSG_task_receive_ext: Trying to receive a message on mailbox '%s'",
312        alias);
313   return MSG_mailbox_get_task_ext_bounded(MSG_mailbox_get_by_alias(alias), task,
314                                           host, timeout, rate);
315 }
316
317 /* Internal function used to factorize code between
318  * MSG_task_isend_with_matching() and MSG_task_dsend().
319  */
320 static XBT_INLINE
321 msg_comm_t MSG_task_isend_internal(msg_task_t task, const char *alias,
322                                    int (*match_fun)(void*,void*, smx_synchro_t),
323                                    void *match_data, void_f_pvoid_t cleanup,
324                                    int detached)
325 {
326   simdata_task_t t_simdata = NULL;
327   msg_process_t process = MSG_process_self();
328   msg_mailbox_t mailbox = MSG_mailbox_get_by_alias(alias);
329   int call_end = TRACE_msg_task_put_start(task);
330
331   /* Prepare the task to send */
332   t_simdata = task->simdata;
333   t_simdata->sender = process;
334   t_simdata->source = ((simdata_process_t) SIMIX_process_self_get_data(process))->m_host;
335
336   if (t_simdata->isused != 0) {
337     if (msg_global->debug_multiple_use){
338       XBT_ERROR("This task is already used in there:");
339       xbt_backtrace_display((xbt_ex_t*) t_simdata->isused);
340       XBT_ERROR("And you try to reuse it from here:");
341       xbt_backtrace_display_current();
342     } else {
343       xbt_assert(t_simdata->isused == 0,
344                  "This task is still being used somewhere else. You cannot send it now. Go fix your code! (use --cfg=msg/debug_multiple_use:on to get the backtrace of the other process)");
345     }
346   }
347
348   if (msg_global->debug_multiple_use)
349     MSG_BT(t_simdata->isused, "Using Backtrace");
350   else
351     t_simdata->isused = (void*)1;
352   t_simdata->comm = NULL;
353   msg_global->sent_msg++;
354
355   /* Send it by calling SIMIX network layer */
356   smx_synchro_t act = simcall_comm_isend(SIMIX_process_self(), mailbox, t_simdata->bytes_amount,
357                                         t_simdata->rate, task, sizeof(void *),
358                                         match_fun, cleanup, NULL, match_data,detached);
359   t_simdata->comm = act; /* FIXME: is the field t_simdata->comm still useful? */
360
361   msg_comm_t comm;
362   if (detached) {
363     comm = NULL;
364   } else {
365     comm = xbt_new0(s_msg_comm_t, 1);
366     comm->task_sent = task;
367     comm->task_received = NULL;
368     comm->status = MSG_OK;
369     comm->s_comm = act;
370   }
371
372   if (TRACE_is_enabled())
373     simcall_set_category(act, task->category);
374   if (call_end)
375     TRACE_msg_task_put_end();
376
377   return comm;
378 }
379
380
381 /** \ingroup msg_task_usage
382  * \brief Sends a task on a mailbox.
383  *
384  * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test()
385  * to end the communication.
386  *
387  * \param task a #msg_task_t to send on another location.
388  * \param alias name of the mailbox to sent the task to
389  * \return the msg_comm_t communication created
390  */
391 msg_comm_t MSG_task_isend(msg_task_t task, const char *alias)
392 {
393   return MSG_task_isend_internal(task, alias, NULL, NULL, NULL, 0);
394 }
395
396 /** \ingroup msg_task_usage
397  * \brief Sends a task on a mailbox with a maximum rate
398  *
399  * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test()
400  * to end the communication. The maxrate parameter allows the application
401  * to limit the bandwidth utilization of network links when sending the task.
402  *
403  * \param task a #msg_task_t to send on another location.
404  * \param alias name of the mailbox to sent the task to
405  * \param maxrate the maximum communication rate for sending this task .
406  * \return the msg_comm_t communication created
407  */
408 msg_comm_t MSG_task_isend_bounded(msg_task_t task, const char *alias,
409                                   double maxrate)
410 {
411   task->simdata->rate = maxrate;
412   return MSG_task_isend_internal(task, alias, NULL, NULL, NULL, 0);
413 }
414
415
416 /** \ingroup msg_task_usage
417  * \brief Sends a task on a mailbox, with support for matching requests
418  *
419  * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test()
420  * to end the communication.
421  *
422  * \param task a #msg_task_t to send on another location.
423  * \param alias name of the mailbox to sent the task to
424  * \param match_fun boolean function which parameters are:
425  *        - match_data_provided_here
426  *        - match_data_provided_by_other_side_if_any
427  *        - the_smx_synchro_describing_the_other_side
428  * \param match_data user provided data passed to match_fun
429  * \return the msg_comm_t communication created
430  */
431 msg_comm_t MSG_task_isend_with_matching(msg_task_t task, const char *alias,
432                                         int (*match_fun)(void*, void*,
433                                                          smx_synchro_t),
434                                         void *match_data)
435 {
436   return MSG_task_isend_internal(task, alias, match_fun, match_data, NULL, 0);
437 }
438
439 /** \ingroup msg_task_usage
440  * \brief Sends a task on a mailbox.
441  *
442  * This is a non blocking detached send function.
443  * Think of it as a best effort send. Keep in mind that the third parameter
444  * is only called if the communication fails. If the communication does work,
445  * it is responsibility of the receiver code to free anything related to
446  * the task, as usual. More details on this can be obtained on
447  * <a href="http://lists.gforge.inria.fr/pipermail/simgrid-user/2011-November/002649.html">this thread</a>
448  * in the SimGrid-user mailing list archive.
449  *
450  * \param task a #msg_task_t to send on another location.
451  * \param alias name of the mailbox to sent the task to
452  * \param cleanup a function to destroy the task if the
453  * communication fails, e.g. MSG_task_destroy
454  * (if NULL, no function will be called)
455  */
456 void MSG_task_dsend(msg_task_t task, const char *alias, void_f_pvoid_t cleanup)
457 {
458   MSG_task_isend_internal(task, alias, NULL, NULL, cleanup, 1);
459 }
460
461 /** \ingroup msg_task_usage
462  * \brief Sends a task on a mailbox with a maximal rate.
463  *
464  * This is a non blocking detached send function.
465  * Think of it as a best effort send. Keep in mind that the third parameter
466  * is only called if the communication fails. If the communication does work,
467  * it is responsibility of the receiver code to free anything related to
468  * the task, as usual. More details on this can be obtained on
469  * <a href="http://lists.gforge.inria.fr/pipermail/simgrid-user/2011-November/002649.html">this thread</a>
470  * in the SimGrid-user mailing list archive.
471  *
472  * \param task a #msg_task_t to send on another location.
473  * \param alias name of the mailbox to sent the task to
474  * \param cleanup a function to destroy the task if the
475  * communication fails, e.g. MSG_task_destroy
476  * (if NULL, no function will be called)
477  * \param maxrate the maximum communication rate for sending this task
478  *
479  */
480 void MSG_task_dsend_bounded(msg_task_t task, const char *alias,
481                             void_f_pvoid_t cleanup, double maxrate)
482 {
483   task->simdata->rate = maxrate;
484   MSG_task_dsend(task, alias, cleanup);
485 }
486
487 /** \ingroup msg_task_usage
488  * \brief Starts listening for receiving a task from an asynchronous communication.
489  *
490  * This is a non blocking function: use MSG_comm_wait() or MSG_comm_test()
491  * to end the communication.
492  *
493  * \param task a memory location for storing a #msg_task_t. has to be valid until the end of the communication.
494  * \param name of the mailbox to receive the task on
495  * \return the msg_comm_t communication created
496  */
497 msg_comm_t MSG_task_irecv(msg_task_t *task, const char *name)
498 {
499   return MSG_task_irecv_bounded(task, name, -1.0);
500 }
501
502 /** \ingroup msg_task_usage
503  * \brief Starts listening for receiving a task from an asynchronous communication
504  * at a given rate.
505  *
506  * \param task a memory location for storing a #msg_task_t. has to be valid until the end of the communication.
507  * \param name of the mailbox to receive the task on
508  * \param rate limit the bandwidth to the given rate
509  * \return the msg_comm_t communication created
510  */
511 msg_comm_t MSG_task_irecv_bounded(msg_task_t *task, const char *name,
512                                   double rate)
513 {
514   smx_rdv_t rdv = MSG_mailbox_get_by_alias(name);
515
516   /* FIXME: these functions are not traceable */
517
518   /* Sanity check */
519   xbt_assert(task, "Null pointer for the task storage");
520
521   if (*task)
522     XBT_CRITICAL
523         ("MSG_task_irecv() was asked to write in a non empty task struct.");
524
525   /* Try to receive it by calling SIMIX network layer */
526   msg_comm_t comm = xbt_new0(s_msg_comm_t, 1);
527   comm->task_sent = NULL;
528   comm->task_received = task;
529   comm->status = MSG_OK;
530   comm->s_comm = simcall_comm_irecv(MSG_process_self(), rdv, task, NULL, NULL, NULL, NULL, rate);
531
532   return comm;
533 }
534
535 /** \ingroup msg_task_usage
536  * \brief Checks whether a communication is done, and if yes, finalizes it.
537  * \param comm the communication to test
538  * \return TRUE if the communication is finished
539  * (but it may have failed, use MSG_comm_get_status() to know its status)
540  * or FALSE if the communication is not finished yet
541  * If the status is FALSE, don't forget to use MSG_process_sleep() after the test.
542  */
543 int MSG_comm_test(msg_comm_t comm)
544 {
545   xbt_ex_t e;
546   int finished = 0;
547
548   TRY {
549     finished = simcall_comm_test(comm->s_comm);
550
551     if (finished && comm->task_received != NULL) {
552       /* I am the receiver */
553       if (msg_global->debug_multiple_use && (*comm->task_received)->simdata->isused!=0)
554         xbt_ex_free(*(xbt_ex_t*)(*comm->task_received)->simdata->isused);
555       (*comm->task_received)->simdata->isused = 0;
556     }
557   }
558   CATCH(e) {
559     switch (e.category) {
560       case network_error:
561         comm->status = MSG_TRANSFER_FAILURE;
562         finished = 1;
563         break;
564
565       case timeout_error:
566         comm->status = MSG_TIMEOUT;
567         finished = 1;
568         break;
569
570       default:
571         RETHROW;
572     }
573     xbt_ex_free(e);
574   }
575
576   return finished;
577 }
578
579 /** \ingroup msg_task_usage
580  * \brief This function checks if a communication is finished.
581  * \param comms a vector of communications
582  * \return the position of the finished communication if any
583  * (but it may have failed, use MSG_comm_get_status() to know its status),
584  * or -1 if none is finished
585  */
586 int MSG_comm_testany(xbt_dynar_t comms)
587 {
588   xbt_ex_t e;
589   int finished_index = -1;
590
591   /* create the equivalent dynar with SIMIX objects */
592   xbt_dynar_t s_comms = xbt_dynar_new(sizeof(smx_synchro_t), NULL);
593   msg_comm_t comm;
594   unsigned int cursor;
595   xbt_dynar_foreach(comms, cursor, comm) {
596     xbt_dynar_push(s_comms, &comm->s_comm);
597   }
598
599   msg_error_t status = MSG_OK;
600   TRY {
601     finished_index = simcall_comm_testany(s_comms);
602   }
603   CATCH(e) {
604     switch (e.category) {
605       case network_error:
606         finished_index = e.value;
607         status = MSG_TRANSFER_FAILURE;
608         break;
609
610       case timeout_error:
611         finished_index = e.value;
612         status = MSG_TIMEOUT;
613         break;
614
615       default:
616         RETHROW;
617     }
618     xbt_ex_free(e);
619   }
620   xbt_dynar_free(&s_comms);
621
622   if (finished_index != -1) {
623     comm = xbt_dynar_get_as(comms, finished_index, msg_comm_t);
624     /* the communication is finished */
625     comm->status = status;
626
627     if (status == MSG_OK && comm->task_received != NULL) {
628       /* I am the receiver */
629       if (msg_global->debug_multiple_use && (*comm->task_received)->simdata->isused!=0)
630         xbt_ex_free(*(xbt_ex_t*)(*comm->task_received)->simdata->isused);
631       (*comm->task_received)->simdata->isused = 0;
632     }
633   }
634
635   return finished_index;
636 }
637
638 /** \ingroup msg_task_usage
639  * \brief Destroys a communication.
640  * \param comm the communication to destroy.
641  */
642 void MSG_comm_destroy(msg_comm_t comm)
643 {
644   xbt_free(comm);
645 }
646
647 /** \ingroup msg_task_usage
648  * \brief Wait for the completion of a communication.
649  *
650  * It takes two parameters.
651  * \param comm the communication to wait.
652  * \param timeout Wait until the communication terminates or the timeout
653  * occurs. You can provide a -1 timeout to obtain an infinite timeout.
654  * \return msg_error_t
655  */
656 msg_error_t MSG_comm_wait(msg_comm_t comm, double timeout)
657 {
658   xbt_ex_t e;
659   TRY {
660     simcall_comm_wait(comm->s_comm, timeout);
661
662     if (comm->task_received != NULL) {
663       /* I am the receiver */
664       if (msg_global->debug_multiple_use && (*comm->task_received)->simdata->isused!=0)
665         xbt_ex_free(*(xbt_ex_t*)(*comm->task_received)->simdata->isused);
666       (*comm->task_received)->simdata->isused = 0;
667     }
668
669     /* FIXME: these functions are not traceable */
670   }
671   CATCH(e) {
672     switch (e.category) {
673     case network_error:
674       comm->status = MSG_TRANSFER_FAILURE;
675       break;
676     case timeout_error:
677       comm->status = MSG_TIMEOUT;
678       break;
679     default:
680       RETHROW;
681     }
682     xbt_ex_free(e);
683   }
684
685   return comm->status;
686 }
687
688 /** \ingroup msg_task_usage
689 * \brief This function is called by a sender and permit to wait for each communication
690 *
691 * \param comm a vector of communication
692 * \param nb_elem is the size of the comm vector
693 * \param timeout for each call of MSG_comm_wait
694 */
695 void MSG_comm_waitall(msg_comm_t * comm, int nb_elem, double timeout)
696 {
697   int i = 0;
698   for (i = 0; i < nb_elem; i++) {
699     MSG_comm_wait(comm[i], timeout);
700   }
701 }
702
703 /** \ingroup msg_task_usage
704  * \brief This function waits for the first communication finished in a list.
705  * \param comms a vector of communications
706  * \return the position of the first finished communication
707  * (but it may have failed, use MSG_comm_get_status() to know its status)
708  */
709 int MSG_comm_waitany(xbt_dynar_t comms)
710 {
711   xbt_ex_t e;
712   int finished_index = -1;
713
714   /* create the equivalent dynar with SIMIX objects */
715   xbt_dynar_t s_comms = xbt_dynar_new(sizeof(smx_synchro_t), NULL);
716   msg_comm_t comm;
717   unsigned int cursor;
718   xbt_dynar_foreach(comms, cursor, comm) {
719     xbt_dynar_push(s_comms, &comm->s_comm);
720   }
721
722   msg_error_t status = MSG_OK;
723   TRY {
724     finished_index = simcall_comm_waitany(s_comms);
725   }
726   CATCH(e) {
727     switch (e.category) {
728       case network_error:
729         finished_index = e.value;
730         status = MSG_TRANSFER_FAILURE;
731         break;
732
733       case timeout_error:
734         finished_index = e.value;
735         status = MSG_TIMEOUT;
736         break;
737
738       default:
739         RETHROW;
740     }
741     xbt_ex_free(e);
742   }
743
744   xbt_assert(finished_index != -1, "WaitAny returned -1");
745   xbt_dynar_free(&s_comms);
746
747   comm = xbt_dynar_get_as(comms, finished_index, msg_comm_t);
748   /* the communication is finished */
749   comm->status = status;
750
751   if (comm->task_received != NULL) {
752     /* I am the receiver */
753     if (msg_global->debug_multiple_use && (*comm->task_received)->simdata->isused!=0)
754       xbt_ex_free(*(xbt_ex_t*)(*comm->task_received)->simdata->isused);
755     (*comm->task_received)->simdata->isused = 0;
756   }
757
758   return finished_index;
759 }
760
761 /**
762  * \ingroup msg_task_usage
763  * \brief Returns the error (if any) that occured during a finished communication.
764  * \param comm a finished communication
765  * \return the status of the communication, or #MSG_OK if no error occured
766  * during the communication
767  */
768 msg_error_t MSG_comm_get_status(msg_comm_t comm) {
769
770   return comm->status;
771 }
772
773 /** \ingroup msg_task_usage
774  * \brief Get a task (#msg_task_t) from a communication
775  *
776  * \param comm the communication where to get the task
777  * \return the task from the communication
778  */
779 msg_task_t MSG_comm_get_task(msg_comm_t comm)
780 {
781   xbt_assert(comm, "Invalid parameter");
782
783   return comm->task_received ? *comm->task_received : comm->task_sent;
784 }
785
786 /**
787  * \brief This function is called by SIMIX in kernel mode to copy the data of a comm.
788  * \param comm the comm
789  * \param buff the data copied
790  * \param buff_size size of the buffer
791  */
792 void MSG_comm_copy_data_from_SIMIX(smx_synchro_t comm, void* buff, size_t buff_size) {
793
794   // copy the task
795   SIMIX_comm_copy_pointer_callback(comm, buff, buff_size);
796
797   // notify the user callback if any
798   if (msg_global->task_copy_callback) {
799     msg_task_t task = (msg_task_t) buff;
800     msg_global->task_copy_callback(task,
801         simcall_comm_get_src_proc(comm), simcall_comm_get_dst_proc(comm));
802   }
803 }
804
805 /** \ingroup msg_task_usage
806  * \brief Sends a task to a mailbox
807  *
808  * This is a blocking function, the execution flow will be blocked
809  * until the task is sent (and received in the other side if #MSG_task_receive is used).
810  * See #MSG_task_isend for sending tasks asynchronously.
811  *
812  * \param task the task to be sent
813  * \param alias the mailbox name to where the task is sent
814  *
815  * \return Returns #MSG_OK if the task was successfully sent,
816  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE otherwise.
817  */
818 msg_error_t MSG_task_send(msg_task_t task, const char *alias)
819 {
820   XBT_DEBUG("MSG_task_send: Trying to send a message on mailbox '%s'", alias);
821   return MSG_task_send_with_timeout(task, alias, -1);
822 }
823
824 /** \ingroup msg_task_usage
825  * \brief Sends a task to a mailbox with a maximum rate
826  *
827  * This is a blocking function, the execution flow will be blocked
828  * until the task is sent. The maxrate parameter allows the application
829  * to limit the bandwidth utilization of network links when sending the task.
830  *
831  * \param task the task to be sent
832  * \param alias the mailbox name to where the task is sent
833  * \param maxrate the maximum communication rate for sending this task
834  *
835  * \return Returns #MSG_OK if the task was successfully sent,
836  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE otherwise.
837  */
838 msg_error_t
839 MSG_task_send_bounded(msg_task_t task, const char *alias, double maxrate)
840 {
841   task->simdata->rate = maxrate;
842   return MSG_task_send(task, alias);
843 }
844
845 /** \ingroup msg_task_usage
846  * \brief Sends a task to a mailbox with a timeout
847  *
848  * This is a blocking function, the execution flow will be blocked
849  * until the task is sent or the timeout is achieved.
850  *
851  * \param task the task to be sent
852  * \param alias the mailbox name to where the task is sent
853  * \param timeout is the maximum wait time for completion (if -1, this call is the same as #MSG_task_send)
854  *
855  * \return Returns #MSG_OK if the task was successfully sent,
856  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
857  */
858 msg_error_t
859 MSG_task_send_with_timeout(msg_task_t task, const char *alias,
860                            double timeout)
861 {
862   return MSG_mailbox_put_with_timeout(MSG_mailbox_get_by_alias(alias),
863                                       task, timeout);
864 }
865
866 /** \ingroup msg_task_usage
867  * \brief Sends a task to a mailbox with a timeout and with a maximum rate
868  *
869  * This is a blocking function, the execution flow will be blocked
870  * until the task is sent or the timeout is achieved.
871  *
872  * \param task the task to be sent
873  * \param alias the mailbox name to where the task is sent
874  * \param timeout is the maximum wait time for completion (if -1, this call is the same as #MSG_task_send)
875  * \param maxrate the maximum communication rate for sending this task
876  *
877  * \return Returns #MSG_OK if the task was successfully sent,
878  * #MSG_HOST_FAILURE, or #MSG_TRANSFER_FAILURE, or #MSG_TIMEOUT otherwise.
879  */
880 msg_error_t
881 MSG_task_send_with_timeout_bounded(msg_task_t task, const char *alias,
882                            double timeout, double maxrate)
883 {
884   task->simdata->rate = maxrate;
885   return MSG_mailbox_put_with_timeout(MSG_mailbox_get_by_alias(alias),
886                                       task, timeout);
887 }
888
889 /** \ingroup msg_task_usage
890  * \brief Check if there is a communication going on in a mailbox.
891  *
892  * \param alias the name of the mailbox to be considered
893  *
894  * \return Returns 1 if there is a communication, 0 otherwise
895  */
896 int MSG_task_listen(const char *alias)
897 {
898   return !MSG_mailbox_is_empty(MSG_mailbox_get_by_alias(alias));
899 }
900
901 /** \ingroup msg_task_usage
902  * \brief Check the number of communication actions of a given host pending in a mailbox.
903  *
904  * \param alias the name of the mailbox to be considered
905  * \param host the host to check for communication
906  *
907  * \return Returns the number of pending communication actions of the host in the
908  * given mailbox, 0 if there is no pending communication actions.
909  *
910  */
911 int MSG_task_listen_from_host(const char *alias, msg_host_t host)
912 {
913   return
914       MSG_mailbox_get_count_host_waiting_tasks(MSG_mailbox_get_by_alias
915                                                (alias), host);
916 }
917
918 /** \ingroup msg_task_usage
919  * \brief Look if there is a communication on a mailbox and return the
920  * PID of the sender process.
921  *
922  * \param alias the name of the mailbox to be considered
923  *
924  * \return Returns the PID of sender process,
925  * -1 if there is no communication in the mailbox.
926  */
927 int MSG_task_listen_from(const char *alias)
928 {
929   msg_task_t task;
930
931   if (NULL ==
932       (task = MSG_mailbox_get_head(MSG_mailbox_get_by_alias(alias))))
933     return -1;
934
935   return MSG_process_get_PID(task->simdata->sender);
936 }
937
938 /** \ingroup msg_task_usage
939  * \brief Sets the tracing category of a task.
940  *
941  * This function should be called after the creation of
942  * a MSG task, to define the category of that task. The
943  * first parameter task must contain a task that was
944  * created with the function #MSG_task_create. The second
945  * parameter category must contain a category that was
946  * previously declared with the function #TRACE_category
947  * (or with #TRACE_category_with_color).
948  *
949  * See \ref tracing for details on how to trace
950  * the (categorized) resource utilization.
951  *
952  * \param task the task that is going to be categorized
953  * \param category the name of the category to be associated to the task
954  *
955  * \see MSG_task_get_category, TRACE_category, TRACE_category_with_color
956  */
957 void MSG_task_set_category (msg_task_t task, const char *category)
958 {
959   TRACE_msg_set_task_category (task, category);
960 }
961
962 /** \ingroup msg_task_usage
963  *
964  * \brief Gets the current tracing category of a task.
965  *
966  * \param task the task to be considered
967  *
968  * \see MSG_task_set_category
969  *
970  * \return Returns the name of the tracing category of the given task, NULL otherwise
971  */
972 const char *MSG_task_get_category (msg_task_t task)
973 {
974   return task->category;
975 }
976
977 /**
978  * \brief Returns the value of a given AS or router property
979  *
980  * \param asr the name of a router or AS
981  * \param name a property name
982  * \return value of a property (or NULL if property not set)
983  */
984 const char *MSG_as_router_get_property_value(const char* asr, const char *name)
985 {
986   return (char*) xbt_dict_get_or_null(
987     MSG_as_router_get_properties(asr), name);
988 }
989
990 /**
991  * \brief Returns a xbt_dict_t consisting of the list of properties assigned to
992  * a the AS or router
993  *
994  * \param asr the name of a router or AS
995  * \return a dict containing the properties
996  */
997 xbt_dict_t MSG_as_router_get_properties(const char* asr)
998 {
999   return (simcall_asr_get_properties(asr));
1000 }
1001
1002 /**
1003  * \brief Change the value of a given AS or router
1004  *
1005  * \param asr the name of a router or AS
1006  * \param name a property name
1007  * \param value what to change the property to
1008  * \param free_ctn the freeing function to use to kill the value on need
1009  */
1010 void MSG_as_router_set_property_value(const char* asr, const char *name, char *value,void_f_pvoid_t free_ctn) {
1011   xbt_dict_set(MSG_as_router_get_properties(asr), name, value,free_ctn);
1012 }