Logo AND Algorithmique Numérique Distribuée

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