Logo AND Algorithmique Numérique Distribuée

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