Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
d03fabbd0c8b384e27656ab32b46ba96ac0f6a0e
[simgrid.git] / src / simix / smx_network.c
1 /* Copyright (c) 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/log.h"
9 #include "mc/mc.h"
10 #include "xbt/dict.h"
11
12 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(simix_network, simix,
13                                 "Logging specific to SIMIX (network)");
14
15 static xbt_dict_t rdv_points = NULL;
16 unsigned long int smx_total_comms = 0;
17
18 static void SIMIX_waitany_req_remove_from_actions(smx_req_t req);
19 static void SIMIX_comm_copy_data(smx_action_t comm);
20 static smx_action_t SIMIX_comm_new(e_smx_comm_type_t type);
21 static XBT_INLINE void SIMIX_rdv_push(smx_rdv_t rdv, smx_action_t comm);
22 static XBT_INLINE void SIMIX_rdv_remove(smx_rdv_t rdv, smx_action_t comm);
23 static smx_action_t SIMIX_rdv_get_request(smx_rdv_t rdv, e_smx_comm_type_t type,
24                                           int (*match_fun)(void *, void *), void *);
25 static void SIMIX_rdv_free(void *data);
26
27 void SIMIX_network_init(void)
28 {
29   rdv_points = xbt_dict_new();
30 }
31
32 void SIMIX_network_exit(void)
33 {
34   xbt_dict_free(&rdv_points);
35 }
36
37 /******************************************************************************/
38 /*                           Rendez-Vous Points                               */
39 /******************************************************************************/
40
41 smx_rdv_t SIMIX_rdv_create(const char *name)
42 {
43   /* two processes may have pushed the same rdv_create request at the same time */
44   smx_rdv_t rdv = name ? xbt_dict_get_or_null(rdv_points, name) : NULL;
45
46   if (!rdv) {
47     rdv = xbt_new0(s_smx_rvpoint_t, 1);
48     rdv->name = name ? xbt_strdup(name) : NULL;
49     rdv->comm_fifo = xbt_fifo_new();
50
51     if (rdv->name)
52       xbt_dict_set(rdv_points, rdv->name, rdv, SIMIX_rdv_free);
53   }
54   return rdv;
55 }
56
57 void SIMIX_rdv_destroy(smx_rdv_t rdv)
58 {
59   if (rdv->name)
60     xbt_dict_remove(rdv_points, rdv->name);
61 }
62
63 void SIMIX_rdv_free(void *data)
64 {
65   smx_rdv_t rdv = (smx_rdv_t) data;
66   if (rdv->name)
67     xbt_free(rdv->name);
68   xbt_fifo_free(rdv->comm_fifo);
69   xbt_free(rdv);  
70 }
71
72 smx_rdv_t SIMIX_rdv_get_by_name(const char *name)
73 {
74   return xbt_dict_get_or_null(rdv_points, name);
75 }
76
77 int SIMIX_rdv_comm_count_by_host(smx_rdv_t rdv, smx_host_t host)
78 {
79   smx_action_t comm = NULL;
80   xbt_fifo_item_t item = NULL;
81   int count = 0;
82
83   xbt_fifo_foreach(rdv->comm_fifo, item, comm, smx_action_t) {
84     if (comm->comm.src_proc->smx_host == host)
85       count++;
86   }
87
88   return count;
89 }
90
91 smx_action_t SIMIX_rdv_get_head(smx_rdv_t rdv)
92 {
93   return xbt_fifo_get_item_content(xbt_fifo_get_first_item(rdv->comm_fifo));
94 }
95
96 /**
97  *  \brief Push a communication request into a rendez-vous point
98  *  \param rdv The rendez-vous point
99  *  \param comm The communication request
100  */
101 static XBT_INLINE void SIMIX_rdv_push(smx_rdv_t rdv, smx_action_t comm)
102 {
103   xbt_fifo_push(rdv->comm_fifo, comm);
104   comm->comm.rdv = rdv;
105 }
106
107 /**
108  *  \brief Remove a communication request from a rendez-vous point
109  *  \param rdv The rendez-vous point
110  *  \param comm The communication request
111  */
112 static XBT_INLINE void SIMIX_rdv_remove(smx_rdv_t rdv, smx_action_t comm)
113 {
114   xbt_fifo_remove(rdv->comm_fifo, comm);
115   comm->comm.rdv = NULL;
116 }
117
118 /**
119  *  \brief Wrapper to SIMIX_rdv_get_request
120  */
121 smx_action_t SIMIX_comm_get_send_match(smx_rdv_t rdv, int (*match_fun)(void*, void*), void* data) {
122    return SIMIX_rdv_get_request(rdv, SIMIX_COMM_SEND, match_fun, data);
123 }
124
125 /**
126  *  \brief Checks if there is a communication action queued in a rendez-vous matching our needs
127  *  \param type The type of communication we are looking for (comm_send, comm_recv)
128  *  \return The communication action if found, NULL otherwise
129  */
130 smx_action_t SIMIX_rdv_get_request(smx_rdv_t rdv, e_smx_comm_type_t type,
131                                    int (*match_fun)(void *, void *), void *data)
132 {
133   // FIXME rewrite this function by using SIMIX_rdv_has_send/recv_match
134   smx_action_t action;
135   xbt_fifo_item_t item;
136   void* req_data = NULL;
137
138   xbt_fifo_foreach(rdv->comm_fifo, item, action, smx_action_t){
139     if (action->comm.type == SIMIX_COMM_SEND) {
140       req_data = action->comm.src_data;
141     } else if (action->comm.type == SIMIX_COMM_RECEIVE) {
142       req_data = action->comm.dst_data;
143     }
144     if (action->comm.type == type && (!match_fun || match_fun(data, req_data))) {
145       XBT_DEBUG("Found a matching communication action %p", action);
146       xbt_fifo_remove_item(rdv->comm_fifo, item);
147       xbt_fifo_free_item(item);
148       action->comm.refcount++;
149       action->comm.rdv = NULL;
150       return action;
151     }
152     XBT_DEBUG("Sorry, communication action %p does not match our needs:"
153            " its type is %d but we are looking for a comm of type %d",
154            action, action->comm.type, type);
155   }
156   XBT_DEBUG("No matching communication action found");
157   return NULL;
158 }
159
160 /**
161  *  \brief Checks if there is a send communication action
162  *  queued in a rendez-vous matching our needs.
163  *  \return 1 if found, 0 otherwise
164  */
165 int SIMIX_comm_has_send_match(smx_rdv_t rdv, int (*match_fun)(void*, void*), void* data) {
166
167   smx_action_t action;
168   xbt_fifo_item_t item;
169
170   xbt_fifo_foreach(rdv->comm_fifo, item, action, smx_action_t){
171     if (action->comm.type == SIMIX_COMM_SEND
172         && (!match_fun || match_fun(data, action->comm.src_data))) {
173       XBT_DEBUG("Found a matching communication action %p", action);
174       return 1;
175     }
176   }
177   XBT_DEBUG("No matching communication action found");
178   return 0;
179 }
180
181 /**
182  *  \brief Checks if there is a recv communication action
183  *  queued in a rendez-vous matching our needs.
184  *  \return 1 if found, 0 otherwise
185  */
186 int SIMIX_comm_has_recv_match(smx_rdv_t rdv, int (*match_fun)(void*, void*), void* data) {
187
188   smx_action_t action;
189   xbt_fifo_item_t item;
190
191   xbt_fifo_foreach(rdv->comm_fifo, item, action, smx_action_t){
192     if (action->comm.type == SIMIX_COMM_RECEIVE
193         && (!match_fun || match_fun(data, action->comm.dst_data))) {
194       XBT_DEBUG("Found a matching communication action %p", action);
195       return 1;
196     }
197   }
198   XBT_DEBUG("No matching communication action found");
199   return 0;
200 }
201
202 /******************************************************************************/
203 /*                            Comunication Actions                            */
204 /******************************************************************************/
205
206 /**
207  *  \brief Creates a new comunicate action
208  *  \param type The type of request (comm_send, comm_recv)
209  *  \return The new comunicate action
210  */
211 smx_action_t SIMIX_comm_new(e_smx_comm_type_t type)
212 {
213   smx_action_t act;
214
215   /* alloc structures */
216   act = xbt_mallocator_get(simix_global->action_mallocator);
217   act->type = SIMIX_ACTION_COMMUNICATE;
218   act->state = SIMIX_WAITING;
219
220   /* set communication */
221   act->comm.type = type;
222   act->comm.refcount = 1;
223
224 #ifdef HAVE_LATENCY_BOUND_TRACKING
225   //initialize with unknown value
226   act->latency_limited = -1;
227 #endif
228
229 #ifdef HAVE_TRACING
230   act->category = NULL;
231 #endif
232
233   XBT_DEBUG("Create communicate action %p", act);
234   ++smx_total_comms;
235
236   return act;
237 }
238
239 /**
240  *  \brief Destroy a communicate action
241  *  \param action The communicate action to be destroyed
242  */
243 void SIMIX_comm_destroy(smx_action_t action)
244 {
245   XBT_DEBUG("Destroy action %p (refcount:%d)", action, action->comm.refcount);
246
247   if (action->comm.refcount <= 0)
248     xbt_die("the refcount of comm %p is already 0 before decreasing it. "
249             "That's a bug!", action);
250
251   action->comm.refcount--;
252   if (action->comm.refcount > 0)
253     return;
254   XBT_DEBUG("Really free communication %p; refcount is now %d", action,
255         action->comm.refcount);
256
257 #ifdef HAVE_LATENCY_BOUND_TRACKING
258     action->latency_limited = SIMIX_comm_is_latency_bounded( action ) ;
259 #endif
260
261   xbt_free(action->name);
262   SIMIX_comm_destroy_internal_actions(action);
263
264   if (action->comm.detached && action->state != SIMIX_DONE) {
265     /* the communication has failed and was detached:
266      * we have to free the buffer */
267     ((void_f_pvoid_t) action->comm.src_data)(action->comm.src_buff);
268   }
269
270   xbt_mallocator_release(simix_global->action_mallocator, action);
271 }
272
273 void SIMIX_comm_destroy_internal_actions(smx_action_t action)
274 {
275   if (action->comm.surf_comm){
276 #ifdef HAVE_LATENCY_BOUND_TRACKING
277     action->latency_limited = SIMIX_comm_is_latency_bounded(action);
278 #endif
279     action->comm.surf_comm->model_type->action_unref(action->comm.surf_comm);
280     action->comm.surf_comm = NULL;
281   }
282
283   if (action->comm.src_timeout){
284     action->comm.src_timeout->model_type->action_unref(action->comm.src_timeout);
285     action->comm.src_timeout = NULL;
286   }
287
288   if (action->comm.dst_timeout){
289     action->comm.dst_timeout->model_type->action_unref(action->comm.dst_timeout);
290     action->comm.dst_timeout = NULL;
291   }
292 }
293
294 smx_action_t SIMIX_comm_isend(smx_process_t src_proc, smx_rdv_t rdv,
295                               double task_size, double rate,
296                               void *src_buff, size_t src_buff_size,
297                               int (*match_fun)(void *, void *), void *data,
298                               int detached)
299 {
300   smx_action_t action;
301
302   /* Look for communication request matching our needs.
303      If it is not found then create it and push it into the rendez-vous point */
304   action = SIMIX_rdv_get_request(rdv, SIMIX_COMM_RECEIVE, match_fun, data);
305
306   if (!action) {
307     action = SIMIX_comm_new(SIMIX_COMM_SEND);
308     SIMIX_rdv_push(rdv, action);
309   } else {
310     action->state = SIMIX_READY;
311     action->comm.type = SIMIX_COMM_READY;
312   }
313
314   /* If the communication action is detached then decrease the refcount
315    * by one, so it will be eliminated by the receivers destroy call */
316   if (detached) {
317     action->comm.detached = 1;
318     action->comm.refcount--;
319   }
320
321   /* Setup the communication request */
322   action->comm.src_proc = src_proc;
323   action->comm.task_size = task_size;
324   action->comm.rate = rate;
325   action->comm.src_buff = src_buff;
326   action->comm.src_buff_size = src_buff_size;
327   action->comm.src_data = data;
328
329   if (MC_IS_ENABLED) {
330     action->state = SIMIX_RUNNING;
331     return action;
332   }
333
334   SIMIX_comm_start(action);
335   return action;
336 }
337
338 smx_action_t SIMIX_comm_irecv(smx_process_t dst_proc, smx_rdv_t rdv,
339                       void *dst_buff, size_t *dst_buff_size,
340                       int (*match_fun)(void *, void *), void *data)
341 {
342   smx_action_t action;
343
344   /* Look for communication request matching our needs.
345    * If it is not found then create it and push it into the rendez-vous point
346    */
347   action = SIMIX_rdv_get_request(rdv, SIMIX_COMM_SEND, match_fun, data);
348
349   if (!action) {
350     action = SIMIX_comm_new(SIMIX_COMM_RECEIVE);
351     SIMIX_rdv_push(rdv, action);
352   } else {
353     action->state = SIMIX_READY;
354     action->comm.type = SIMIX_COMM_READY;
355   }
356
357   /* Setup communication request */
358   action->comm.dst_proc = dst_proc;
359   action->comm.dst_buff = dst_buff;
360   action->comm.dst_buff_size = dst_buff_size;
361   action->comm.dst_data = data;
362
363   if (MC_IS_ENABLED) {
364     action->state = SIMIX_RUNNING;
365     return action;
366   }
367
368   SIMIX_comm_start(action);
369   return action;
370 }
371
372 void SIMIX_pre_comm_wait(smx_req_t req, smx_action_t action, double timeout, int idx)
373 {
374   /* the request may be a wait, a send or a recv */
375   surf_action_t sleep;
376
377   /* Associate this request to the action */
378   xbt_fifo_push(action->request_list, req);
379   req->issuer->waiting_action = action;
380
381   if (MC_IS_ENABLED) {
382     if (idx == 0) {
383       action->state = SIMIX_DONE;
384     } else {
385       /* If we reached this point, the wait request must have a timeout */
386       /* Otherwise it shouldn't be enabled and executed by the MC */
387       if (timeout == -1)
388         THROW_IMPOSSIBLE;
389
390       if (action->comm.src_proc == req->issuer)
391         action->state = SIMIX_SRC_TIMEOUT;
392       else
393         action->state = SIMIX_DST_TIMEOUT;
394     }
395
396     SIMIX_comm_finish(action);
397     return;
398   }
399
400   /* If the action has already finish perform the error handling, */
401   /* otherwise set up a waiting timeout on the right side         */
402   if (action->state != SIMIX_WAITING && action->state != SIMIX_RUNNING) {
403     SIMIX_comm_finish(action);
404   } else { /* if (timeout >= 0) { we need a surf sleep action even when there is no timeout, otherwise surf won't tell us when the host fails */
405     sleep = surf_workstation_model->extension.workstation.sleep(req->issuer->smx_host->host, timeout);
406     surf_workstation_model->action_data_set(sleep, action);
407
408     if (req->issuer == action->comm.src_proc)
409       action->comm.src_timeout = sleep;
410     else
411       action->comm.dst_timeout = sleep;
412   }
413 }
414
415 void SIMIX_pre_comm_test(smx_req_t req)
416 {
417   smx_action_t action = req->comm_test.comm;
418
419   if(MC_IS_ENABLED){
420     req->comm_test.result = action->comm.src_proc && action->comm.dst_proc;
421     if(req->comm_test.result){
422       action->state = SIMIX_DONE;
423       xbt_fifo_push(action->request_list, req);
424       SIMIX_comm_finish(action);
425     }else{
426       SIMIX_request_answer(req);
427     }
428     return;
429   }
430
431   req->comm_test.result = (action->state != SIMIX_WAITING && action->state != SIMIX_RUNNING);
432   if (req->comm_test.result) {
433     xbt_fifo_push(action->request_list, req);
434     SIMIX_comm_finish(action);
435   } else {
436     SIMIX_request_answer(req);
437   }
438 }
439
440 void SIMIX_pre_comm_testany(smx_req_t req, int idx)
441 {
442   unsigned int cursor;
443   smx_action_t action;
444   xbt_dynar_t actions = req->comm_testany.comms;
445   req->comm_testany.result = -1;
446
447   if (MC_IS_ENABLED){
448     if(idx == -1){
449       SIMIX_request_answer(req);
450     }else{
451       action = xbt_dynar_get_as(actions, idx, smx_action_t);
452       req->comm_testany.result = idx;
453       xbt_fifo_push(action->request_list, req);
454       action->state = SIMIX_DONE;
455       SIMIX_comm_finish(action);
456     }
457     return;
458   }
459
460   xbt_dynar_foreach(req->comm_testany.comms,cursor,action) {
461     if (action->state != SIMIX_WAITING && action->state != SIMIX_RUNNING) {
462       req->comm_testany.result = cursor;
463       xbt_fifo_push(action->request_list, req);
464       SIMIX_comm_finish(action);
465       return;
466     }
467   }
468   SIMIX_request_answer(req);
469 }
470
471 void SIMIX_pre_comm_waitany(smx_req_t req, int idx)
472 {
473   smx_action_t action;
474   unsigned int cursor = 0;
475   xbt_dynar_t actions = req->comm_waitany.comms;
476
477   if (MC_IS_ENABLED){
478     action = xbt_dynar_get_as(actions, idx, smx_action_t);
479     xbt_fifo_push(action->request_list, req);
480     req->comm_waitany.result = idx;
481     action->state = SIMIX_DONE;
482     SIMIX_comm_finish(action);
483     return;
484   }
485
486   xbt_dynar_foreach(actions, cursor, action){
487     /* Associate this request to the action */
488     xbt_fifo_push(action->request_list, req);
489     if (action->state != SIMIX_WAITING && action->state != SIMIX_RUNNING){
490       SIMIX_comm_finish(action);
491       break;
492     }
493   }
494 }
495
496 void SIMIX_waitany_req_remove_from_actions(smx_req_t req)
497 {
498   smx_action_t action;
499   unsigned int cursor = 0;
500   xbt_dynar_t actions = req->comm_waitany.comms;
501
502   xbt_dynar_foreach(actions, cursor, action){
503     xbt_fifo_remove(action->request_list, req);
504   }
505 }
506
507 /**
508  *  \brief Start the simulation of a communication request
509  *  \param action The communication action
510  */
511
512 XBT_INLINE void SIMIX_comm_start(smx_action_t action)
513 {
514   /* If both the sender and the receiver are already there, start the communication */
515   if (action->state == SIMIX_READY) {
516     smx_host_t sender = action->comm.src_proc->smx_host;
517     smx_host_t receiver = action->comm.dst_proc->smx_host;
518
519     XBT_DEBUG("Starting communication %p from '%s' to '%s'", action,
520            SIMIX_host_get_name(sender), SIMIX_host_get_name(receiver));
521
522     action->comm.surf_comm = surf_workstation_model->extension.workstation.
523         communicate(sender->host, receiver->host, action->comm.task_size, action->comm.rate);
524
525     surf_workstation_model->action_data_set(action->comm.surf_comm, action);
526
527     action->state = SIMIX_RUNNING;
528
529     /* If a link is failed, detect it immediately */
530     if (surf_workstation_model->action_state_get(action->comm.surf_comm) == SURF_ACTION_FAILED) {
531       XBT_DEBUG("Communication from '%s' to '%s' failed to start because of a link failure",
532           SIMIX_host_get_name(sender), SIMIX_host_get_name(receiver));
533       action->state = SIMIX_LINK_FAILURE;
534       SIMIX_comm_destroy_internal_actions(action);
535     }
536
537     /* If any of the process is suspend, create the action but stop its execution,
538        it will be restarted when the sender process resume */
539     if (SIMIX_process_is_suspended(action->comm.src_proc) ||
540         SIMIX_process_is_suspended(action->comm.dst_proc)) {
541       /* FIXME: check what should happen with the action state */
542       surf_workstation_model->suspend(action->comm.surf_comm);
543     }
544   }
545 }
546
547 void SIMIX_comm_finish(smx_action_t action)
548 {
549   unsigned int destroy_count = 0;
550   smx_req_t req;
551
552   while ((req = xbt_fifo_shift(action->request_list))) {
553
554     /* If a waitany request is waiting for this action to finish, then remove
555        it from the other actions in the waitany list. Afterwards, get the
556        position of the actual action in the waitany request's actions dynar and
557        return it as the result of the call */
558     if (req->call == REQ_COMM_WAITANY) {
559       SIMIX_waitany_req_remove_from_actions(req);
560       if (!MC_IS_ENABLED)
561         req->comm_waitany.result = xbt_dynar_search(req->comm_waitany.comms, &action);
562     }
563
564     /* If the action is still in a rendez-vous point then remove from it */
565     if (action->comm.rdv)
566       SIMIX_rdv_remove(action->comm.rdv, action);
567
568     XBT_DEBUG("SIMIX_comm_finish: action state = %d", action->state);
569
570     /* Check out for errors */
571     switch (action->state) {
572
573       case SIMIX_DONE:
574         XBT_DEBUG("Communication %p complete!", action);
575         SIMIX_comm_copy_data(action);
576         break;
577
578       case SIMIX_SRC_TIMEOUT:
579         TRY {
580           THROWF(timeout_error, 0, "Communication timeouted because of sender");
581         }
582         CATCH(req->issuer->running_ctx->exception) {
583           req->issuer->doexception = 1;
584         }
585         break;
586
587       case SIMIX_DST_TIMEOUT:
588         TRY {
589           THROWF(timeout_error, 0, "Communication timeouted because of receiver");
590         }
591         CATCH(req->issuer->running_ctx->exception) {
592           req->issuer->doexception = 1;
593         }
594         break;
595
596       case SIMIX_SRC_HOST_FAILURE:
597         TRY {
598           if (req->issuer == action->comm.src_proc)
599             THROWF(host_error, 0, "Host failed");
600           else
601             THROWF(network_error, 0, "Remote peer failed");
602         }
603         CATCH(req->issuer->running_ctx->exception) {
604           req->issuer->doexception = 1;
605         }
606         break;
607
608       case SIMIX_DST_HOST_FAILURE:
609         TRY {
610           if (req->issuer == action->comm.dst_proc)
611             THROWF(host_error, 0, "Host failed");
612           else
613             THROWF(network_error, 0, "Remote peer failed");
614         }
615         CATCH(req->issuer->running_ctx->exception) {
616           req->issuer->doexception = 1;
617         }
618         break;
619
620       case SIMIX_LINK_FAILURE:
621         TRY {
622           XBT_DEBUG("Link failure in action %p between '%s' and '%s': posting an exception to the issuer: %s (%p)",
623               action, action->comm.src_proc->smx_host->name, action->comm.dst_proc->smx_host->name,
624               req->issuer->name, req->issuer);
625           THROWF(network_error, 0, "Link failure");
626         }
627         CATCH(req->issuer->running_ctx->exception) {
628           req->issuer->doexception = 1;
629         }
630         break;
631
632       default:
633         THROW_IMPOSSIBLE;
634     }
635
636     /* if there is an exception during a waitany or a testany, indicate the position of the failed communication */
637     if (req->issuer->doexception) {
638       if (req->call == REQ_COMM_WAITANY) {
639         req->issuer->running_ctx->exception.value = xbt_dynar_search(req->comm_waitany.comms, &action);
640       }
641       else if (req->call == REQ_COMM_TESTANY) {
642         req->issuer->running_ctx->exception.value = xbt_dynar_search(req->comm_testany.comms, &action);
643       }
644     }
645
646     req->issuer->waiting_action = NULL;
647     SIMIX_request_answer(req);
648     destroy_count++;
649   }
650
651   while (destroy_count-- > 0)
652     SIMIX_comm_destroy(action);
653 }
654
655 void SIMIX_post_comm(smx_action_t action)
656 {
657   /* Update action state */
658   if (action->comm.src_timeout &&
659      surf_workstation_model->action_state_get(action->comm.src_timeout) == SURF_ACTION_DONE)
660      action->state = SIMIX_SRC_TIMEOUT;
661   else if (action->comm.dst_timeout &&
662           surf_workstation_model->action_state_get(action->comm.dst_timeout) == SURF_ACTION_DONE)
663      action->state = SIMIX_DST_TIMEOUT;
664   else if (action->comm.src_timeout &&
665           surf_workstation_model->action_state_get(action->comm.src_timeout) == SURF_ACTION_FAILED)
666      action->state = SIMIX_SRC_HOST_FAILURE;
667   else if (action->comm.dst_timeout &&
668           surf_workstation_model->action_state_get(action->comm.dst_timeout) == SURF_ACTION_FAILED)
669      action->state = SIMIX_DST_HOST_FAILURE;
670   else if (action->comm.surf_comm &&
671           surf_workstation_model->action_state_get(action->comm.surf_comm) == SURF_ACTION_FAILED)
672      action->state = SIMIX_LINK_FAILURE;
673   else
674     action->state = SIMIX_DONE;
675
676   XBT_DEBUG("SIMIX_post_comm: action state = %d", action->state);
677
678   /* After this point the surf actions associated with the simix communicate
679      action are no longer needed, thus we delete them. */
680   SIMIX_comm_destroy_internal_actions(action);
681
682   /* If there are requests associated with the action, then answer them */
683   if (xbt_fifo_size(action->request_list))
684     SIMIX_comm_finish(action);
685 }
686
687 void SIMIX_comm_cancel(smx_action_t action)
688 {
689   /* If the action is a waiting state means that it is still in a rdv */
690   /* so remove from it and delete it */
691   if (action->state == SIMIX_WAITING) {
692     SIMIX_rdv_remove(action->comm.rdv, action);
693     action->state = SIMIX_FAILED;
694   } else {
695     /* When running the MC there are no surf actions */
696     if(!MC_IS_ENABLED)
697       surf_workstation_model->action_cancel(action->comm.surf_comm);
698   }
699 }
700
701 void SIMIX_comm_suspend(smx_action_t action)
702 {
703   /*FIXME: shall we suspend also the timeout actions? */
704   surf_workstation_model->suspend(action->comm.surf_comm);
705 }
706
707 void SIMIX_comm_resume(smx_action_t action)
708 {
709   /*FIXME: check what happen with the timeouts */
710   surf_workstation_model->resume(action->comm.surf_comm);
711 }
712
713
714 /************* Action Getters **************/
715
716 /**
717  *  \brief get the amount remaining from the communication
718  *  \param action The communication
719  */
720 double SIMIX_comm_get_remains(smx_action_t action)
721 {
722   double remains;
723
724   switch (action->state) {
725
726     case SIMIX_RUNNING:
727       remains = surf_workstation_model->get_remains(action->comm.surf_comm);
728       break;
729
730     case SIMIX_WAITING:
731     case SIMIX_READY:
732       remains = 0; /*FIXME: check what should be returned */
733       break;
734
735     default:
736       remains = 0; /*FIXME: is this correct? */
737       break;
738   }
739   return remains;
740 }
741
742 e_smx_state_t SIMIX_comm_get_state(smx_action_t action)
743 {
744   return action->state;
745 }
746
747 /**
748  *  \brief Return the user data associated to the sender of the communication
749  *  \param action The communication
750  *  \return the user data
751  */
752 void* SIMIX_comm_get_src_data(smx_action_t action)
753 {
754   return action->comm.src_data;
755 }
756
757 /**
758  *  \brief Return the user data associated to the receiver of the communication
759  *  \param action The communication
760  *  \return the user data
761  */
762 void* SIMIX_comm_get_dst_data(smx_action_t action)
763 {
764   return action->comm.dst_data;
765 }
766
767 smx_process_t SIMIX_comm_get_src_proc(smx_action_t action)
768 {
769   return action->comm.src_proc;
770 }
771
772 smx_process_t SIMIX_comm_get_dst_proc(smx_action_t action)
773 {
774   return action->comm.dst_proc;
775 }
776
777 #ifdef HAVE_LATENCY_BOUND_TRACKING
778 /**
779  *  \brief verify if communication is latency bounded
780  *  \param comm The communication
781  */
782 XBT_INLINE int SIMIX_comm_is_latency_bounded(smx_action_t action)
783 {
784   if (action->comm.surf_comm){
785       XBT_DEBUG("Getting latency limited for surf_action (%p)", action->comm.surf_comm);
786       action->latency_limited = surf_workstation_model->get_latency_limited(action->comm.surf_comm);
787       XBT_DEBUG("Action limited is %d", action->latency_limited);
788   }
789   return action->latency_limited;
790 }
791 #endif
792
793 /******************************************************************************/
794 /*                    SIMIX_comm_copy_data callbacks                       */
795 /******************************************************************************/
796 static void (*SIMIX_comm_copy_data_callback) (smx_action_t, size_t) =
797     &SIMIX_comm_copy_pointer_callback;
798
799 void
800 SIMIX_comm_set_copy_data_callback(void (*callback) (smx_action_t, size_t))
801 {
802   SIMIX_comm_copy_data_callback = callback;
803 }
804
805 void SIMIX_comm_copy_pointer_callback(smx_action_t comm, size_t buff_size)
806 {
807   xbt_assert((buff_size == sizeof(void *)),
808               "Cannot copy %zu bytes: must be sizeof(void*)", buff_size);
809   *(void **) (comm->comm.dst_buff) = comm->comm.src_buff;
810 }
811
812 void SIMIX_comm_copy_buffer_callback(smx_action_t comm, size_t buff_size)
813 {
814   memcpy(comm->comm.dst_buff, comm->comm.src_buff, buff_size);
815 }
816
817 /**
818  *  \brief Copy the communication data from the sender's buffer to the receiver's one
819  *  \param comm The communication
820  */
821 void SIMIX_comm_copy_data(smx_action_t comm)
822 {
823   size_t buff_size = comm->comm.src_buff_size;
824   /* If there is no data to be copy then return */
825   if (!comm->comm.src_buff || !comm->comm.dst_buff || comm->comm.copied == 1)
826     return;
827
828   XBT_DEBUG("Copying comm %p data from %s (%p) -> %s (%p) (%zu bytes)",
829          comm,
830          comm->comm.src_proc->smx_host->name, comm->comm.src_buff,
831          comm->comm.dst_proc->smx_host->name, comm->comm.dst_buff, buff_size);
832
833   /* Copy at most dst_buff_size bytes of the message to receiver's buffer */
834   if (comm->comm.dst_buff_size)
835     buff_size = MIN(buff_size, *(comm->comm.dst_buff_size));
836
837   /* Update the receiver's buffer size to the copied amount */
838   if (comm->comm.dst_buff_size)
839     *comm->comm.dst_buff_size = buff_size;
840
841   if (buff_size == 0)
842     return;
843
844   (*SIMIX_comm_copy_data_callback) (comm, buff_size);
845
846   /* Set the copied flag so we copy data only once */
847   /* (this function might be called from both communication ends) */
848   comm->comm.copied = 1;
849 }