Logo AND Algorithmique Numérique Distribuée

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