Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Fix remaining memory leaks in MSG
[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 void SIMIX_comm_remove_from_processes(smx_action_t action);
22 static XBT_INLINE void SIMIX_rdv_push(smx_rdv_t rdv, smx_action_t comm);
23 static XBT_INLINE void SIMIX_rdv_remove(smx_rdv_t rdv, smx_action_t comm);
24 static smx_action_t SIMIX_rdv_get_request(smx_rdv_t rdv, e_smx_comm_type_t type,
25                                           int (*match_fun)(void *, void *), void *);
26 static void SIMIX_rdv_free(void *data);
27
28 void SIMIX_network_init(void)
29 {
30   rdv_points = xbt_dict_new();
31 }
32
33 void SIMIX_network_exit(void)
34 {
35   xbt_dict_free(&rdv_points);
36 }
37
38 /******************************************************************************/
39 /*                           Rendez-Vous Points                               */
40 /******************************************************************************/
41
42 smx_rdv_t SIMIX_rdv_create(const char *name)
43 {
44   /* two processes may have pushed the same rdv_create request at the same time */
45   smx_rdv_t rdv = name ? xbt_dict_get_or_null(rdv_points, name) : NULL;
46
47   if (!rdv) {
48     rdv = xbt_new0(s_smx_rvpoint_t, 1);
49     rdv->name = name ? xbt_strdup(name) : NULL;
50     rdv->comm_fifo = xbt_fifo_new();
51
52     if (rdv->name)
53       xbt_dict_set(rdv_points, rdv->name, rdv, SIMIX_rdv_free);
54   }
55   return rdv;
56 }
57
58 void SIMIX_rdv_destroy(smx_rdv_t rdv)
59 {
60   if (rdv->name)
61     xbt_dict_remove(rdv_points, rdv->name);
62 }
63
64 void SIMIX_rdv_free(void *data)
65 {
66   smx_rdv_t rdv = (smx_rdv_t) data;
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   xbt_fifo_push(src_proc->comms, action);
314
315   /* if the communication action is detached then decrease the refcount
316    * by one, so it will be eliminated by the receiver's destroy call */
317   if (detached) {
318     action->comm.detached = 1;
319     action->comm.refcount--;
320   }
321
322   /* Setup the communication request */
323   action->comm.src_proc = src_proc;
324   action->comm.task_size = task_size;
325   action->comm.rate = rate;
326   action->comm.src_buff = src_buff;
327   action->comm.src_buff_size = src_buff_size;
328   action->comm.src_data = data;
329
330   if (MC_IS_ENABLED) {
331     action->state = SIMIX_RUNNING;
332     return action;
333   }
334
335   SIMIX_comm_start(action);
336   return action;
337 }
338
339 smx_action_t SIMIX_comm_irecv(smx_process_t dst_proc, smx_rdv_t rdv,
340                       void *dst_buff, size_t *dst_buff_size,
341                       int (*match_fun)(void *, void *), void *data)
342 {
343   smx_action_t action;
344
345   /* Look for communication request matching our needs.
346    * If it is not found then create it and push it into the rendez-vous point
347    */
348   action = SIMIX_rdv_get_request(rdv, SIMIX_COMM_SEND, match_fun, data);
349
350   if (!action) {
351     action = SIMIX_comm_new(SIMIX_COMM_RECEIVE);
352     SIMIX_rdv_push(rdv, action);
353   } else {
354     action->state = SIMIX_READY;
355     action->comm.type = SIMIX_COMM_READY;
356   }
357   xbt_fifo_push(dst_proc->comms, action);
358
359   /* Setup communication request */
360   action->comm.dst_proc = dst_proc;
361   action->comm.dst_buff = dst_buff;
362   action->comm.dst_buff_size = dst_buff_size;
363   action->comm.dst_data = data;
364
365   if (MC_IS_ENABLED) {
366     action->state = SIMIX_RUNNING;
367     return action;
368   }
369
370   SIMIX_comm_start(action);
371   return action;
372 }
373
374 void SIMIX_pre_comm_wait(smx_req_t req, smx_action_t action, double timeout, int idx)
375 {
376   /* the request may be a wait, a send or a recv */
377   surf_action_t sleep;
378
379   /* Associate this request to the action */
380   xbt_fifo_push(action->request_list, req);
381   req->issuer->waiting_action = action;
382
383   if (MC_IS_ENABLED) {
384     if (idx == 0) {
385       action->state = SIMIX_DONE;
386     } else {
387       /* If we reached this point, the wait request must have a timeout */
388       /* Otherwise it shouldn't be enabled and executed by the MC */
389       if (timeout == -1)
390         THROW_IMPOSSIBLE;
391
392       if (action->comm.src_proc == req->issuer)
393         action->state = SIMIX_SRC_TIMEOUT;
394       else
395         action->state = SIMIX_DST_TIMEOUT;
396     }
397
398     SIMIX_comm_finish(action);
399     return;
400   }
401
402   /* If the action has already finish perform the error handling, */
403   /* otherwise set up a waiting timeout on the right side         */
404   if (action->state != SIMIX_WAITING && action->state != SIMIX_RUNNING) {
405     SIMIX_comm_finish(action);
406   } 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 */
407     sleep = surf_workstation_model->extension.workstation.sleep(req->issuer->smx_host->host, timeout);
408     surf_workstation_model->action_data_set(sleep, action);
409
410     if (req->issuer == action->comm.src_proc)
411       action->comm.src_timeout = sleep;
412     else
413       action->comm.dst_timeout = sleep;
414   }
415 }
416
417 void SIMIX_pre_comm_test(smx_req_t req)
418 {
419   smx_action_t action = req->comm_test.comm;
420
421   if(MC_IS_ENABLED){
422     req->comm_test.result = action->comm.src_proc && action->comm.dst_proc;
423     if(req->comm_test.result){
424       action->state = SIMIX_DONE;
425       xbt_fifo_push(action->request_list, req);
426       SIMIX_comm_finish(action);
427     }else{
428       SIMIX_request_answer(req);
429     }
430     return;
431   }
432
433   req->comm_test.result = (action->state != SIMIX_WAITING && action->state != SIMIX_RUNNING);
434   if (req->comm_test.result) {
435     xbt_fifo_push(action->request_list, req);
436     SIMIX_comm_finish(action);
437   } else {
438     SIMIX_request_answer(req);
439   }
440 }
441
442 void SIMIX_pre_comm_testany(smx_req_t req, int idx)
443 {
444   unsigned int cursor;
445   smx_action_t action;
446   xbt_dynar_t actions = req->comm_testany.comms;
447   req->comm_testany.result = -1;
448
449   if (MC_IS_ENABLED){
450     if(idx == -1){
451       SIMIX_request_answer(req);
452     }else{
453       action = xbt_dynar_get_as(actions, idx, smx_action_t);
454       req->comm_testany.result = idx;
455       xbt_fifo_push(action->request_list, req);
456       action->state = SIMIX_DONE;
457       SIMIX_comm_finish(action);
458     }
459     return;
460   }
461
462   xbt_dynar_foreach(req->comm_testany.comms,cursor,action) {
463     if (action->state != SIMIX_WAITING && action->state != SIMIX_RUNNING) {
464       req->comm_testany.result = cursor;
465       xbt_fifo_push(action->request_list, req);
466       SIMIX_comm_finish(action);
467       return;
468     }
469   }
470   SIMIX_request_answer(req);
471 }
472
473 void SIMIX_pre_comm_waitany(smx_req_t req, int idx)
474 {
475   smx_action_t action;
476   unsigned int cursor = 0;
477   xbt_dynar_t actions = req->comm_waitany.comms;
478
479   if (MC_IS_ENABLED){
480     action = xbt_dynar_get_as(actions, idx, smx_action_t);
481     xbt_fifo_push(action->request_list, req);
482     req->comm_waitany.result = idx;
483     action->state = SIMIX_DONE;
484     SIMIX_comm_finish(action);
485     return;
486   }
487
488   xbt_dynar_foreach(actions, cursor, action){
489     /* Associate this request to the action */
490     xbt_fifo_push(action->request_list, req);
491     if (action->state != SIMIX_WAITING && action->state != SIMIX_RUNNING){
492       SIMIX_comm_finish(action);
493       break;
494     }
495   }
496 }
497
498 void SIMIX_waitany_req_remove_from_actions(smx_req_t req)
499 {
500   smx_action_t action;
501   unsigned int cursor = 0;
502   xbt_dynar_t actions = req->comm_waitany.comms;
503
504   xbt_dynar_foreach(actions, cursor, action){
505     xbt_fifo_remove(action->request_list, req);
506   }
507 }
508
509 /**
510  *  \brief Start the simulation of a communication request
511  *  \param action The communication action
512  */
513
514 XBT_INLINE void SIMIX_comm_start(smx_action_t action)
515 {
516   /* If both the sender and the receiver are already there, start the communication */
517   if (action->state == SIMIX_READY) {
518
519     smx_host_t sender = action->comm.src_proc->smx_host;
520     smx_host_t receiver = action->comm.dst_proc->smx_host;
521
522     XBT_DEBUG("Starting communication %p from '%s' to '%s'", action,
523            SIMIX_host_get_name(sender), SIMIX_host_get_name(receiver));
524
525     action->comm.surf_comm = surf_workstation_model->extension.workstation.
526         communicate(sender->host, receiver->host, action->comm.task_size, action->comm.rate);
527
528     surf_workstation_model->action_data_set(action->comm.surf_comm, action);
529
530     action->state = SIMIX_RUNNING;
531
532     /* If a link is failed, detect it immediately */
533     if (surf_workstation_model->action_state_get(action->comm.surf_comm) == SURF_ACTION_FAILED) {
534       XBT_DEBUG("Communication from '%s' to '%s' failed to start because of a link failure",
535           SIMIX_host_get_name(sender), SIMIX_host_get_name(receiver));
536       action->state = SIMIX_LINK_FAILURE;
537       SIMIX_comm_destroy_internal_actions(action);
538     }
539
540     /* If any of the process is suspend, create the action but stop its execution,
541        it will be restarted when the sender process resume */
542     if (SIMIX_process_is_suspended(action->comm.src_proc) ||
543         SIMIX_process_is_suspended(action->comm.dst_proc)) {
544       /* FIXME: check what should happen with the action state */
545       surf_workstation_model->suspend(action->comm.surf_comm);
546     }
547   }
548 }
549
550 void SIMIX_comm_finish(smx_action_t action)
551 {
552   unsigned int destroy_count = 0;
553   smx_req_t req;
554
555   SIMIX_comm_remove_from_processes(action);
556
557   while ((req = xbt_fifo_shift(action->request_list))) {
558
559     /* If a waitany request is waiting for this action to finish, then remove
560        it from the other actions in the waitany list. Afterwards, get the
561        position of the actual action in the waitany request's actions dynar and
562        return it as the result of the call */
563     if (req->call == REQ_COMM_WAITANY) {
564       SIMIX_waitany_req_remove_from_actions(req);
565       if (!MC_IS_ENABLED)
566         req->comm_waitany.result = xbt_dynar_search(req->comm_waitany.comms, &action);
567     }
568
569     /* If the action is still in a rendez-vous point then remove from it */
570     if (action->comm.rdv)
571       SIMIX_rdv_remove(action->comm.rdv, action);
572
573     XBT_DEBUG("SIMIX_comm_finish: action state = %d", action->state);
574
575     /* Check out for errors */
576     switch (action->state) {
577
578       case SIMIX_DONE:
579         XBT_DEBUG("Communication %p complete!", action);
580         SIMIX_comm_copy_data(action);
581         break;
582
583       case SIMIX_SRC_TIMEOUT:
584         TRY {
585           THROWF(timeout_error, 0, "Communication timeouted because of sender");
586         }
587         CATCH(req->issuer->running_ctx->exception) {
588           req->issuer->doexception = 1;
589         }
590         break;
591
592       case SIMIX_DST_TIMEOUT:
593         TRY {
594           THROWF(timeout_error, 0, "Communication timeouted because of receiver");
595         }
596         CATCH(req->issuer->running_ctx->exception) {
597           req->issuer->doexception = 1;
598         }
599         break;
600
601       case SIMIX_SRC_HOST_FAILURE:
602         TRY {
603           if (req->issuer == action->comm.src_proc)
604             THROWF(host_error, 0, "Host failed");
605           else
606             THROWF(network_error, 0, "Remote peer failed");
607         }
608         CATCH(req->issuer->running_ctx->exception) {
609           req->issuer->doexception = 1;
610         }
611         break;
612
613       case SIMIX_DST_HOST_FAILURE:
614         TRY {
615           if (req->issuer == action->comm.dst_proc)
616             THROWF(host_error, 0, "Host failed");
617           else
618             THROWF(network_error, 0, "Remote peer failed");
619         }
620         CATCH(req->issuer->running_ctx->exception) {
621           req->issuer->doexception = 1;
622         }
623         break;
624
625       case SIMIX_LINK_FAILURE:
626         TRY {
627           XBT_DEBUG("Link failure in action %p between '%s' and '%s': posting an exception to the issuer: %s (%p)",
628               action, action->comm.src_proc->smx_host->name, action->comm.dst_proc->smx_host->name,
629               req->issuer->name, req->issuer);
630           THROWF(network_error, 0, "Link failure");
631         }
632         CATCH(req->issuer->running_ctx->exception) {
633           req->issuer->doexception = 1;
634         }
635         break;
636
637       default:
638         THROW_IMPOSSIBLE;
639     }
640
641     /* if there is an exception during a waitany or a testany, indicate the position of the failed communication */
642     if (req->issuer->doexception) {
643       if (req->call == REQ_COMM_WAITANY) {
644         req->issuer->running_ctx->exception.value = xbt_dynar_search(req->comm_waitany.comms, &action);
645       }
646       else if (req->call == REQ_COMM_TESTANY) {
647         req->issuer->running_ctx->exception.value = xbt_dynar_search(req->comm_testany.comms, &action);
648       }
649     }
650
651     req->issuer->waiting_action = NULL;
652     SIMIX_request_answer(req);
653     destroy_count++;
654   }
655
656   while (destroy_count-- > 0)
657     SIMIX_comm_destroy(action);
658 }
659
660 void SIMIX_post_comm(smx_action_t action)
661 {
662   /* Update action state */
663   if (action->comm.src_timeout &&
664      surf_workstation_model->action_state_get(action->comm.src_timeout) == SURF_ACTION_DONE)
665      action->state = SIMIX_SRC_TIMEOUT;
666   else if (action->comm.dst_timeout &&
667           surf_workstation_model->action_state_get(action->comm.dst_timeout) == SURF_ACTION_DONE)
668      action->state = SIMIX_DST_TIMEOUT;
669   else if (action->comm.src_timeout &&
670           surf_workstation_model->action_state_get(action->comm.src_timeout) == SURF_ACTION_FAILED)
671      action->state = SIMIX_SRC_HOST_FAILURE;
672   else if (action->comm.dst_timeout &&
673           surf_workstation_model->action_state_get(action->comm.dst_timeout) == SURF_ACTION_FAILED)
674      action->state = SIMIX_DST_HOST_FAILURE;
675   else if (action->comm.surf_comm &&
676           surf_workstation_model->action_state_get(action->comm.surf_comm) == SURF_ACTION_FAILED)
677      action->state = SIMIX_LINK_FAILURE;
678   else
679     action->state = SIMIX_DONE;
680
681   XBT_DEBUG("SIMIX_post_comm: comm %p, state %d, src_proc %p, dst_proc %p, detached: %d",
682       action, action->state, action->comm.src_proc, action->comm.dst_proc, action->comm.detached);
683
684   /* destroy the surf actions associated with the Simix communication */
685   SIMIX_comm_destroy_internal_actions(action);
686
687   /* if there are requests associated with the action, then answer them */
688   if (xbt_fifo_size(action->request_list)) {
689     SIMIX_comm_finish(action);
690   }
691   else {
692     SIMIX_comm_remove_from_processes(action);
693   }
694 }
695
696 /**
697  * \brief Removes a communication action from the list of pending communications
698  * of both processes (if they still exist)
699  * \param action a communication action
700  */
701 static void SIMIX_comm_remove_from_processes(smx_action_t action) {
702
703   if (action->comm.src_proc) {
704     xbt_fifo_remove(action->comm.src_proc->comms, action);
705   }
706   if (action->comm.dst_proc) {
707     xbt_fifo_remove(action->comm.dst_proc->comms, action);
708   }
709 }
710
711 void SIMIX_comm_cancel(smx_action_t action)
712 {
713   /* if the action is a waiting state means that it is still in a rdv */
714   /* so remove from it and delete it */
715   if (action->state == SIMIX_WAITING) {
716     SIMIX_rdv_remove(action->comm.rdv, action);
717     action->state = SIMIX_FAILED;
718   }
719   else if (!MC_IS_ENABLED
720       && (action->state == SIMIX_READY || action->state == SIMIX_RUNNING)) {
721
722     /* when running the MC there are no surf actions */
723     surf_workstation_model->action_cancel(action->comm.surf_comm);
724   }
725 }
726
727 void SIMIX_comm_suspend(smx_action_t action)
728 {
729   /*FIXME: shall we suspend also the timeout actions? */
730   surf_workstation_model->suspend(action->comm.surf_comm);
731 }
732
733 void SIMIX_comm_resume(smx_action_t action)
734 {
735   /*FIXME: check what happen with the timeouts */
736   surf_workstation_model->resume(action->comm.surf_comm);
737 }
738
739
740 /************* Action Getters **************/
741
742 /**
743  *  \brief get the amount remaining from the communication
744  *  \param action The communication
745  */
746 double SIMIX_comm_get_remains(smx_action_t action)
747 {
748   double remains;
749
750   if(!action){
751       return 0;
752   }
753
754   switch (action->state) {
755
756     case SIMIX_RUNNING:
757       remains = surf_workstation_model->get_remains(action->comm.surf_comm);
758       break;
759
760     case SIMIX_WAITING:
761     case SIMIX_READY:
762       remains = 0; /*FIXME: check what should be returned */
763       break;
764
765     default:
766       remains = 0; /*FIXME: is this correct? */
767       break;
768   }
769   return remains;
770 }
771
772 e_smx_state_t SIMIX_comm_get_state(smx_action_t action)
773 {
774   return action->state;
775 }
776
777 /**
778  *  \brief Return the user data associated to the sender of the communication
779  *  \param action The communication
780  *  \return the user data
781  */
782 void* SIMIX_comm_get_src_data(smx_action_t action)
783 {
784   return action->comm.src_data;
785 }
786
787 /**
788  *  \brief Return the user data associated to the receiver of the communication
789  *  \param action The communication
790  *  \return the user data
791  */
792 void* SIMIX_comm_get_dst_data(smx_action_t action)
793 {
794   return action->comm.dst_data;
795 }
796
797 smx_process_t SIMIX_comm_get_src_proc(smx_action_t action)
798 {
799   return action->comm.src_proc;
800 }
801
802 smx_process_t SIMIX_comm_get_dst_proc(smx_action_t action)
803 {
804   return action->comm.dst_proc;
805 }
806
807 #ifdef HAVE_LATENCY_BOUND_TRACKING
808 /**
809  *  \brief verify if communication is latency bounded
810  *  \param comm The communication
811  */
812 XBT_INLINE int SIMIX_comm_is_latency_bounded(smx_action_t action)
813 {
814   if(!action){
815       return 0;
816   }
817   if (action->comm.surf_comm){
818       XBT_DEBUG("Getting latency limited for surf_action (%p)", action->comm.surf_comm);
819       action->latency_limited = surf_workstation_model->get_latency_limited(action->comm.surf_comm);
820       XBT_DEBUG("Action limited is %d", action->latency_limited);
821   }
822   return action->latency_limited;
823 }
824 #endif
825
826 /******************************************************************************/
827 /*                    SIMIX_comm_copy_data callbacks                       */
828 /******************************************************************************/
829 static void (*SIMIX_comm_copy_data_callback) (smx_action_t, size_t) =
830     &SIMIX_comm_copy_pointer_callback;
831
832 void
833 SIMIX_comm_set_copy_data_callback(void (*callback) (smx_action_t, size_t))
834 {
835   SIMIX_comm_copy_data_callback = callback;
836 }
837
838 void SIMIX_comm_copy_pointer_callback(smx_action_t comm, size_t buff_size)
839 {
840   xbt_assert((buff_size == sizeof(void *)),
841               "Cannot copy %zu bytes: must be sizeof(void*)", buff_size);
842   *(void **) (comm->comm.dst_buff) = comm->comm.src_buff;
843 }
844
845 void SIMIX_comm_copy_buffer_callback(smx_action_t comm, size_t buff_size)
846 {
847   memcpy(comm->comm.dst_buff, comm->comm.src_buff, buff_size);
848 }
849
850 /**
851  *  \brief Copy the communication data from the sender's buffer to the receiver's one
852  *  \param comm The communication
853  */
854 void SIMIX_comm_copy_data(smx_action_t comm)
855 {
856   size_t buff_size = comm->comm.src_buff_size;
857   /* If there is no data to be copy then return */
858   if (!comm->comm.src_buff || !comm->comm.dst_buff || comm->comm.copied == 1)
859     return;
860
861   XBT_DEBUG("Copying comm %p data from %s (%p) -> %s (%p) (%zu bytes)",
862          comm,
863          comm->comm.src_proc->smx_host->name, comm->comm.src_buff,
864          comm->comm.dst_proc->smx_host->name, comm->comm.dst_buff, buff_size);
865
866   /* Copy at most dst_buff_size bytes of the message to receiver's buffer */
867   if (comm->comm.dst_buff_size)
868     buff_size = MIN(buff_size, *(comm->comm.dst_buff_size));
869
870   /* Update the receiver's buffer size to the copied amount */
871   if (comm->comm.dst_buff_size)
872     *comm->comm.dst_buff_size = buff_size;
873
874   if (buff_size == 0)
875     return;
876
877   (*SIMIX_comm_copy_data_callback) (comm, buff_size);
878
879   /* Set the copied flag so we copy data only once */
880   /* (this function might be called from both communication ends) */
881   comm->comm.copied = 1;
882 }