Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Handle transfer failures in MSG_test, MSG_testany and MSG_waitany
[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
530     /* if there is an exception during a waitany or a testany, indicate the position of the failed communication */
531     if (req->issuer->doexception) {
532       if (req->call == REQ_COMM_WAITANY) {
533         req->issuer->running_ctx->exception.value = xbt_dynar_search(req->comm_waitany.comms, &action);
534       }
535       else if (req->call == REQ_COMM_TESTANY) {
536         req->issuer->running_ctx->exception.value = xbt_dynar_search(req->comm_testany.comms, &action);
537       }
538     }
539
540     req->issuer->waiting_action = NULL;
541     SIMIX_request_answer(req);
542   }
543 }
544
545 void SIMIX_post_comm(smx_action_t action)
546 {
547   /* Update action state */
548   if (action->comm.src_timeout &&
549      surf_workstation_model->action_state_get(action->comm.src_timeout) == SURF_ACTION_DONE)
550      action->state = SIMIX_SRC_TIMEOUT;
551   else if (action->comm.dst_timeout &&
552           surf_workstation_model->action_state_get(action->comm.dst_timeout) == SURF_ACTION_DONE)
553      action->state = SIMIX_DST_TIMEOUT;
554   else if (action->comm.src_timeout &&
555           surf_workstation_model->action_state_get(action->comm.src_timeout) == SURF_ACTION_FAILED)
556      action->state = SIMIX_SRC_HOST_FAILURE;
557   else if (action->comm.dst_timeout &&
558           surf_workstation_model->action_state_get(action->comm.dst_timeout) == SURF_ACTION_FAILED)
559      action->state = SIMIX_DST_HOST_FAILURE;
560   else if (action->comm.surf_comm &&
561           surf_workstation_model->action_state_get(action->comm.surf_comm) == SURF_ACTION_FAILED)
562      action->state = SIMIX_LINK_FAILURE;
563   else
564     action->state = SIMIX_DONE;
565
566   DEBUG1("SIMIX_post_comm: action state = %d", action->state);
567
568   /* After this point the surf actions associated with the simix communicate
569      action are no longer needed, thus we delete them. */
570   SIMIX_comm_destroy_internal_actions(action);
571
572   /* If there are requests associated with the action, then answer them */
573   if (xbt_fifo_size(action->request_list))
574     SIMIX_comm_finish(action);
575 }
576
577 void SIMIX_comm_cancel(smx_action_t action)
578 {
579   /* If the action is a waiting state means that it is still in a rdv */
580   /* so remove from it and delete it */
581   if (action->state == SIMIX_WAITING) {
582     SIMIX_rdv_remove(action->comm.rdv, action);
583     action->state = SIMIX_FAILED;
584   } else {
585     surf_workstation_model->action_cancel(action->comm.surf_comm);
586   }
587 }
588
589 void SIMIX_comm_suspend(smx_action_t action)
590 {
591   /*FIXME: shall we suspend also the timeout actions? */
592   surf_workstation_model->suspend(action->comm.surf_comm);
593 }
594
595 void SIMIX_comm_resume(smx_action_t action)
596 {
597   /*FIXME: check what happen with the timeouts */
598   surf_workstation_model->resume(action->comm.surf_comm);
599 }
600
601
602 /************* Action Getters **************/
603
604 /**
605  *  \brief get the amount remaining from the communication
606  *  \param action The communication
607  */
608 double SIMIX_comm_get_remains(smx_action_t action)
609 {
610   double remains;
611
612   switch (action->state) {
613
614     case SIMIX_RUNNING:
615       remains = surf_workstation_model->get_remains(action->comm.surf_comm);
616       break;
617
618     case SIMIX_WAITING:
619     case SIMIX_READY:
620       remains = 0; /*FIXME: check what should be returned */
621       break;
622
623     default:
624       remains = 0; /*FIXME: is this correct? */
625       break;
626   }
627   return remains;
628 }
629
630 e_smx_state_t SIMIX_comm_get_state(smx_action_t action)
631 {
632   return action->state;
633 }
634
635 /**
636  *  \brief Return the user data associated to the sender of the communication
637  *  \param action The communication
638  *  \return the user data
639  */
640 void* SIMIX_comm_get_src_data(smx_action_t action)
641 {
642   return action->comm.src_data;
643 }
644
645 /**
646  *  \brief Return the user data associated to the receiver of the communication
647  *  \param action The communication
648  *  \return the user data
649  */
650 void* SIMIX_comm_get_dst_data(smx_action_t action)
651 {
652   return action->comm.dst_data;
653 }
654
655 void* SIMIX_comm_get_src_buff(smx_action_t action)
656 {
657   return action->comm.src_buff;
658 }
659
660 void* SIMIX_comm_get_dst_buff(smx_action_t action)
661 {
662   return action->comm.dst_buff;
663 }
664
665 size_t SIMIX_comm_get_src_buff_size(smx_action_t action)
666 {
667   return action->comm.src_buff_size;
668 }
669
670 size_t SIMIX_comm_get_dst_buff_size(smx_action_t action)
671 {
672   size_t buff_size;
673
674   if (action->comm.dst_buff_size)
675     buff_size = *(action->comm.dst_buff_size);
676   else
677     buff_size = 0;
678
679   return buff_size;
680 }
681
682 smx_process_t SIMIX_comm_get_src_proc(smx_action_t action)
683 {
684   return action->comm.src_proc;
685 }
686
687 smx_process_t SIMIX_comm_get_dst_proc(smx_action_t action)
688 {
689   return action->comm.dst_proc;
690 }
691
692 #ifdef HAVE_LATENCY_BOUND_TRACKING
693 /**
694  *  \brief verify if communication is latency bounded
695  *  \param comm The communication
696  */
697 XBT_INLINE int SIMIX_comm_is_latency_bounded(smx_action_t action)
698 {
699   if (action->comm.surf_comm){
700       DEBUG1("Getting latency limited for surf_action (%p)", action->comm.surf_comm);
701       action->latency_limited = surf_workstation_model->get_latency_limited(action->comm.surf_comm);
702       DEBUG1("Action limited is %d", action->latency_limited);
703   }
704   return action->latency_limited;
705 }
706 #endif
707
708 /******************************************************************************/
709 /*                    SIMIX_comm_copy_data callbacks                       */
710 /******************************************************************************/
711 static void (*SIMIX_comm_copy_data_callback) (smx_action_t, size_t) =
712     &SIMIX_comm_copy_pointer_callback;
713
714 void
715 SIMIX_comm_set_copy_data_callback(void (*callback) (smx_action_t, size_t))
716 {
717   SIMIX_comm_copy_data_callback = callback;
718 }
719
720 void SIMIX_comm_copy_pointer_callback(smx_action_t comm, size_t buff_size)
721 {
722   xbt_assert1((buff_size == sizeof(void *)),
723               "Cannot copy %zu bytes: must be sizeof(void*)", buff_size);
724   *(void **) (comm->comm.dst_buff) = comm->comm.src_buff;
725 }
726
727 void SIMIX_comm_copy_buffer_callback(smx_action_t comm, size_t buff_size)
728 {
729   memcpy(comm->comm.dst_buff, comm->comm.src_buff, buff_size);
730 }
731
732 /**
733  *  \brief Copy the communication data from the sender's buffer to the receiver's one
734  *  \param comm The communication
735  */
736 void SIMIX_comm_copy_data(smx_action_t comm)
737 {
738   size_t buff_size = comm->comm.src_buff_size;
739   /* If there is no data to be copy then return */
740   if (!comm->comm.src_buff || !comm->comm.dst_buff || comm->comm.copied == 1)
741     return;
742
743   DEBUG6("Copying comm %p data from %s (%p) -> %s (%p) (%zu bytes)",
744          comm,
745          comm->comm.src_proc->smx_host->name, comm->comm.src_buff,
746          comm->comm.dst_proc->smx_host->name, comm->comm.dst_buff, buff_size);
747
748   /* Copy at most dst_buff_size bytes of the message to receiver's buffer */
749   if (comm->comm.dst_buff_size)
750     buff_size = MIN(buff_size, *(comm->comm.dst_buff_size));
751
752   /* Update the receiver's buffer size to the copied amount */
753   if (comm->comm.dst_buff_size)
754     *comm->comm.dst_buff_size = buff_size;
755
756   if (buff_size == 0)
757     return;
758
759   (*SIMIX_comm_copy_data_callback) (comm, buff_size);
760
761   /* Set the copied flag so we copy data only once */
762   /* (this function might be called from both communication ends) */
763   comm->comm.copied = 1;
764 }