Logo AND Algorithmique Numérique Distribuée

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