Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Added round trip time contraint to the SDP program, this parameter
[simgrid.git] / src / gras / DataDesc / ddt_exchange.c
1 /* $Id$ */
2
3 /* ddt_exchange - send/recv data described                                  */
4
5 /* Copyright (c) 2003 Olivier Aumage.                                       */
6 /* Copyright (c) 2003, 2004, 2005 Martin Quinson.                           */
7 /* All rights reserved.                                                     */
8
9 /* This program is free software; you can redistribute it and/or modify it
10  * under the terms of the license (GNU LGPL) which comes with this package. */
11
12 #include "xbt/ex.h"
13 #include "gras/DataDesc/datadesc_private.h"
14 #include "gras/Transport/transport_interface.h" /* gras_trp_send/recv */
15
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(gras_ddt_exchange,gras_ddt,
17                                  "Sending data over the network");
18 const char *gras_datadesc_cat_names[9] = { 
19   "undefined", 
20   "scalar", "struct", "union", "ref", "array", "ignored",
21   "invalid"};
22
23 static gras_datadesc_type_t int_type = NULL;
24 static gras_datadesc_type_t pointer_type = NULL;    
25
26 static XBT_INLINE void
27 gras_dd_send_int(gras_socket_t sock,int *i, int stable) {
28
29   if (!int_type) {
30     int_type = gras_datadesc_by_name("int");
31      xbt_assert(int_type);  
32   }
33    
34   DEBUG1("send_int(%d)",*i);
35   gras_trp_send(sock, (char*)i, int_type->size[GRAS_THISARCH], stable);
36 }
37
38 static XBT_INLINE void
39 gras_dd_recv_int(gras_socket_t sock, int r_arch, int *i) {
40
41   if (!int_type) {
42      int_type = gras_datadesc_by_name("int");
43      xbt_assert(int_type);
44   }
45
46   if (int_type->size[GRAS_THISARCH] >= int_type->size[r_arch]) {
47     gras_trp_recv(sock, (char*)i, int_type->size[r_arch]);
48     if (r_arch != GRAS_THISARCH)
49       gras_dd_convert_elm(int_type,1,r_arch, i,i);
50   } else {
51     void *ptr = xbt_malloc(int_type->size[r_arch]);
52
53     gras_trp_recv(sock, (char*)ptr, int_type->size[r_arch]);
54     if (r_arch != GRAS_THISARCH)
55       gras_dd_convert_elm(int_type,1,r_arch, ptr,i);
56     free(ptr);
57   }
58   DEBUG1("recv_int(%d)",*i);
59 }
60
61 /*
62  * Note: here we suppose that the remote NULL is a sequence 
63  *       of 'length' bytes set to 0.
64  * FIXME: Check in configure?
65  */
66 static XBT_INLINE int 
67 gras_dd_is_r_null(char **r_ptr, long int length) {
68   int i;
69
70   for (i=0; i<length; i++) {
71     if ( ((unsigned char*)r_ptr) [i]) {
72       return 0;
73     }
74   }
75
76   return 1;
77 }
78
79 static XBT_INLINE void
80 gras_dd_alloc_ref(xbt_dict_t  refs,
81                   long int     size,
82                   char       **r_ref,
83                   long int     r_len, /* pointer_type->size[r_arch] */
84                   char       **l_ref,
85                   int          detect_cycle) {
86   char *l_data = NULL;
87
88   xbt_assert1(size>0,"Cannot allocate %ld bytes!", size);
89   l_data = xbt_malloc((size_t)size);
90
91   *l_ref = l_data;
92   DEBUG5("alloc_ref: l_data=%p, &l_data=%p; r_ref=%p; *r_ref=%p, r_len=%ld",
93          (void*)l_data,(void*)&l_data,
94          (void*)r_ref, (void*)(r_ref?*r_ref:NULL), r_len);
95   if (detect_cycle && r_ref && !gras_dd_is_r_null( r_ref, r_len)) {
96     void *ptr = xbt_malloc(sizeof(void *));
97
98     memcpy(ptr,l_ref, sizeof(void *));
99
100     DEBUG2("Insert l_ref=%p under r_ref=%p",*(void**)ptr, *(void**)r_ref);
101      
102     if (detect_cycle)
103        xbt_dict_set_ext(refs,(const char *) r_ref, r_len, ptr, xbt_free_f);
104   }
105 }
106
107 static int
108 gras_datadesc_copy_rec(gras_cbps_t           state,
109                        xbt_dict_t            refs,
110                        gras_datadesc_type_t  type, 
111                        char                 *src,
112                        char                 *dst,
113                        int                   subsize,
114                        int                   detect_cycle) {
115
116
117   xbt_ex_t             e;
118   int                  cpt;
119   gras_datadesc_type_t sub_type; /* type on which we recurse */
120   int count = 0;
121
122   VERB4("Copy a %s (%s) from %p to %p", 
123         type->name, gras_datadesc_cat_names[type->category_code],
124         src,dst);       
125    
126   if (type->send) {
127     type->send(type,state,src);
128   }
129
130   switch (type->category_code) {
131   case e_gras_datadesc_type_cat_scalar:
132     memcpy(dst,src,type->size[GRAS_THISARCH]);
133     count += type->size[GRAS_THISARCH];
134     break;
135
136   case e_gras_datadesc_type_cat_struct: {
137     gras_dd_cat_struct_t struct_data;
138     gras_dd_cat_field_t  field;
139     char                *field_src;
140     char                *field_dst;
141     
142     struct_data = type->category.struct_data;
143     xbt_assert1(struct_data.closed,
144       "Please call gras_datadesc_declare_struct_close on %s before copying it",
145                 type->name);
146     VERB1(">> Copy all fields of the structure %s",type->name);
147     xbt_dynar_foreach(struct_data.fields, cpt, field) {
148       field_src = src + field->offset[GRAS_THISARCH];
149       field_dst = dst + field->offset[GRAS_THISARCH];
150       
151       sub_type = field->type;
152       
153       if (field->send)
154         field->send(type,state,field_src);
155       
156       DEBUG1("Copy field %s",field->name);
157       count += gras_datadesc_copy_rec(state,refs,sub_type, field_src, field_dst, 0,
158                                       detect_cycle || sub_type->cycle);
159        
160        if (XBT_LOG_ISENABLED(gras_ddt_exchange,xbt_log_priority_verbose)) {
161           if (sub_type == gras_datadesc_by_name("unsigned int")) {
162              VERB2("Copied value for field '%s': %d (type: unsigned int)",field->name, *(unsigned int*)field_dst);
163           } else if (sub_type == gras_datadesc_by_name("int")) {
164              VERB2("Copied value for field '%s': %d (type: int)",field->name, *(int*)field_dst);
165              
166           } else if (sub_type == gras_datadesc_by_name("unsigned long int")) {
167              VERB2("Copied value for field '%s': %ld (type: unsigned long int)",field->name, *(unsigned long int*)field_dst);
168           } else if (sub_type == gras_datadesc_by_name("long int")) {
169              VERB2("Copied value for field '%s': %ld (type: long int)",field->name, *(long int*)field_dst);
170
171           } else if (sub_type == gras_datadesc_by_name("string")) {
172              VERB2("Copied value for field '%s': '%s' (type: string)", field->name, *(char**)field_dst);         
173           } else {
174              VERB1("Copied a value for field '%s' (type not scalar?)", field->name);
175           }
176        }
177       
178     }
179     VERB1("<< Copied all fields of the structure %s", type->name);
180     
181     break;
182   }
183
184   case e_gras_datadesc_type_cat_union: {
185     gras_dd_cat_union_t union_data;
186     gras_dd_cat_field_t field=NULL;
187     int                 field_num;
188     
189     union_data = type->category.union_data;
190     
191     xbt_assert1(union_data.closed,
192                 "Please call gras_datadesc_declare_union_close on %s before copying it",
193                 type->name);
194     /* retrieve the field number */
195     field_num = union_data.selector(type, state, src);
196     
197     xbt_assert1(field_num > 0,
198                 "union field selector of %s gave a negative value", 
199                 type->name);
200     
201     xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
202          "union field selector of %s returned %d but there is only %lu fields",
203                  type->name, field_num, xbt_dynar_length(union_data.fields));
204     
205     /* Copy the content */
206     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
207     sub_type = field->type;
208     
209     if (field->send)
210       field->send(type,state,src);
211     
212     count += gras_datadesc_copy_rec(state,refs, sub_type, src, dst,0,
213                                     detect_cycle || sub_type->cycle);
214           
215     break;
216   }
217     
218   case e_gras_datadesc_type_cat_ref: {
219     gras_dd_cat_ref_t      ref_data;
220     char                 **o_ref=NULL;
221     char                 **n_ref=NULL;
222     int                    reference_is_to_cpy;
223     
224     ref_data = type->category.ref_data;
225     
226     /* Detect the referenced type */
227     sub_type = ref_data.type;
228     if (sub_type == NULL) {
229       sub_type = (*ref_data.selector)(type,state,src);
230     }
231     
232     /* Send the pointed data only if not already sent */
233     if (*(void**)src == NULL) {
234       VERB0("Not copying NULL referenced data");
235       *(void**)dst = NULL;
236       break;
237     }
238     o_ref=(char**)src;
239
240     reference_is_to_cpy = 0;
241     TRY {
242       if (detect_cycle) {
243         /* return ignored. Just checking whether it's known or not */
244         n_ref=xbt_dict_get_ext(refs,(char*)o_ref, sizeof(char*));
245       } else {
246         reference_is_to_cpy = 1;
247       }
248     } CATCH(e) {
249       if (e.category != not_found_error)
250         RETHROW;
251       reference_is_to_cpy = 1;
252       xbt_ex_free(e);
253     }
254
255     if (reference_is_to_cpy) {
256       int subsubcount = 0;
257       void *l_referenced=NULL;
258        VERB2("Copy a ref to '%s' referenced at %p",sub_type->name, (void*)*o_ref);
259        
260        if (!pointer_type) { 
261          pointer_type = gras_datadesc_by_name("data pointer");
262          xbt_assert(pointer_type);
263        }
264
265        if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
266          /* Damn. Reference to a dynamic array. Allocating the space for it 
267             is more complicated */
268          gras_dd_cat_array_t array_data = sub_type->category.array_data;
269          gras_datadesc_type_t subsub_type;
270          
271          subsub_type = array_data.type;
272          subsubcount = array_data.fixed_size;
273          if (subsubcount == 0)
274            subsubcount = array_data.dynamic_size(subsub_type,state,*o_ref);
275          
276          gras_dd_alloc_ref(refs,
277                            subsub_type->size[GRAS_THISARCH] * subsubcount, 
278                            o_ref,pointer_type->size[GRAS_THISARCH], 
279                            (char**)&l_referenced,
280                            detect_cycle);
281        } else {
282          gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
283                            o_ref,pointer_type->size[GRAS_THISARCH], 
284                            (char**)&l_referenced,
285                            detect_cycle);
286        }
287        
288        count += gras_datadesc_copy_rec(state,refs, sub_type,
289                                        *o_ref,(char*)l_referenced, subsubcount,
290                                        detect_cycle || sub_type->cycle);
291                                
292        *(void**)dst=l_referenced;
293        VERB3("'%s' previously referenced at %p now at %p",
294              sub_type->name, *(void**)o_ref, l_referenced);
295        
296     } else {
297       VERB2("NOT copying data previously referenced @%p (already done, @%p now)",
298             *(void**)o_ref, *(void**)n_ref);
299       
300       *(void**)dst=*n_ref;
301       
302     } 
303     break;
304   }
305
306   case e_gras_datadesc_type_cat_array: {
307     gras_dd_cat_array_t    array_data;
308     long int               array_count;
309     char                  *src_ptr=src;
310     char                  *dst_ptr=dst;
311     long int               elm_size;
312     
313     array_data = type->category.array_data;
314     
315     /* determine and send the element count */
316     array_count = array_data.fixed_size;
317     if (array_count == 0)
318       array_count = subsize;
319     if (array_count == 0) {
320       array_count = array_data.dynamic_size(type,state,src);
321       xbt_assert1(array_count >=0,
322                    "Invalid (negative) array size for type %s",type->name);
323     }
324     
325     /* send the content */
326     sub_type = array_data.type;
327     elm_size = sub_type->aligned_size[GRAS_THISARCH];
328     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
329       VERB1("Array of %ld scalars, copy it in one shot",array_count);
330       memcpy(dst, src, sub_type->aligned_size[GRAS_THISARCH] * array_count);
331       count += sub_type->aligned_size[GRAS_THISARCH] * array_count;
332     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
333                sub_type->category.array_data.fixed_size > 0 &&
334                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
335        
336       VERB1("Array of %ld fixed array of scalars, copy it in one shot",
337             array_count);
338       memcpy(dst,src,sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
339                      * array_count * sub_type->category.array_data.fixed_size);
340       count += sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
341                * array_count * sub_type->category.array_data.fixed_size;
342        
343     } else {
344       VERB1("Array of %ld stuff, copy it in one after the other",array_count);
345       for (cpt=0; cpt<array_count; cpt++) {
346         VERB2("Copy the %dth stuff out of %ld",cpt,array_count);
347         count += gras_datadesc_copy_rec(state,refs, sub_type, src_ptr, dst_ptr, 0,
348                                         detect_cycle || sub_type->cycle);
349         src_ptr += elm_size;
350         dst_ptr += elm_size;
351       }
352     }
353     break;
354   }
355
356   default:
357     xbt_assert0(0, "Invalid type");
358   }
359    
360   return count;
361 }
362 /**
363  * gras_datadesc_copy:
364  *
365  * Copy the data pointed by src and described by type 
366  * to a new location, and store a pointer to it in dst.
367  *
368  */
369 int gras_datadesc_copy(gras_datadesc_type_t type, 
370                        void *src, void *dst) {
371   xbt_ex_t e;
372   static gras_cbps_t state=NULL;
373   static xbt_dict_t  refs=NULL; /* all references already sent */
374   int size=0;
375  
376   xbt_assert0(type,"called with NULL type descriptor");
377
378   if (!state) {
379     state = gras_cbps_new();
380     refs = xbt_dict_new();
381   }
382   
383   TRY {
384     size = gras_datadesc_copy_rec(state,refs,type,(char*)src,(char*)dst,0, 
385                                   type->cycle);
386   } CLEANUP {
387     xbt_dict_reset(refs);
388     gras_cbps_reset(state);
389   } CATCH(e) {
390     RETHROW;
391   }
392   return size;
393 }
394
395 /***
396  *** Direct use functions
397  ***/
398
399 static void
400 gras_datadesc_send_rec(gras_socket_t         sock,
401                        gras_cbps_t           state,
402                        xbt_dict_t            refs,
403                        gras_datadesc_type_t  type, 
404                        char                 *data,
405                        int                   detect_cycle) {
406
407   xbt_ex_t             e;
408   int                  cpt;
409   gras_datadesc_type_t sub_type; /* type on which we recurse */
410   
411   VERB2("Send a %s (%s)", 
412         type->name, gras_datadesc_cat_names[type->category_code]);
413
414   if (!strcmp(type->name,"string"))
415     VERB1("value: '%s'",*(char**)data);
416
417   if (type->send) {
418     type->send(type,state,data);
419     DEBUG0("Run the emission callback");
420   }
421
422   switch (type->category_code) {
423   case e_gras_datadesc_type_cat_scalar:
424     gras_trp_send(sock, data, type->size[GRAS_THISARCH], 1);
425     break;
426
427   case e_gras_datadesc_type_cat_struct: {
428     gras_dd_cat_struct_t struct_data;
429     gras_dd_cat_field_t  field;
430     char                *field_data;
431     
432     struct_data = type->category.struct_data;
433     xbt_assert1(struct_data.closed,
434       "Please call gras_datadesc_declare_struct_close on %s before sending it",
435                 type->name);
436     VERB1(">> Send all fields of the structure %s",type->name);
437     xbt_dynar_foreach(struct_data.fields, cpt, field) {
438       field_data = data;
439       field_data += field->offset[GRAS_THISARCH];
440       
441       sub_type = field->type;
442       
443       if (field->send) {
444         DEBUG1("Run the emission callback of field %s", field->name);
445         field->send(type,state,field_data);
446       }
447       
448       VERB1("Send field %s",field->name);
449       gras_datadesc_send_rec(sock,state,refs,sub_type, field_data, 
450                              detect_cycle || sub_type->cycle);
451       
452     }
453     VERB1("<< Sent all fields of the structure %s", type->name);
454     
455     break;
456   }
457
458   case e_gras_datadesc_type_cat_union: {
459     gras_dd_cat_union_t union_data;
460     gras_dd_cat_field_t field=NULL;
461     int                 field_num;
462     
463     union_data = type->category.union_data;
464     
465     xbt_assert1(union_data.closed,
466                 "Please call gras_datadesc_declare_union_close on %s before sending it",
467                 type->name);
468     /* retrieve the field number */
469     field_num = union_data.selector(type, state, data);
470     
471     xbt_assert1(field_num > 0,
472                  "union field selector of %s gave a negative value", 
473                  type->name);
474     
475     xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
476          "union field selector of %s returned %d but there is only %lu fields",
477                  type->name, field_num, xbt_dynar_length(union_data.fields));
478
479     /* Send the field number */
480     gras_dd_send_int(sock, &field_num, 0 /* not stable */);
481     
482     /* Send the content */
483     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
484     sub_type = field->type;
485     
486     if (field->send)
487       field->send(type,state,data);
488     
489     gras_datadesc_send_rec(sock,state,refs, sub_type, data, 
490                            detect_cycle || sub_type->cycle);
491           
492     break;
493   }
494     
495   case e_gras_datadesc_type_cat_ref: {
496     gras_dd_cat_ref_t      ref_data;
497     void                 **ref=(void**)data;
498     int                    reference_is_to_send;
499     
500     ref_data = type->category.ref_data;
501     
502     /* Detect the referenced type and send it to peer if needed */
503     sub_type = ref_data.type;
504     if (sub_type == NULL) {
505       sub_type = (*ref_data.selector)(type,state,data);
506       gras_dd_send_int(sock, (int*) &(sub_type->code),1 /*stable*/);
507     }
508     
509     /* Send the actual value of the pointer for cycle handling */
510     if (!pointer_type) {
511       pointer_type = gras_datadesc_by_name("data pointer");
512       xbt_assert(pointer_type);
513     }
514      
515     gras_trp_send(sock, (char*)data,
516                   pointer_type->size[GRAS_THISARCH], 1 /*stable*/);
517     
518     /* Send the pointed data only if not already sent */
519     if (*(void**)data == NULL) {
520       VERB0("Not sending NULL referenced data");
521       break;
522     }
523
524     reference_is_to_send = 0;
525     TRY {
526       if (detect_cycle)
527         /* return ignored. Just checking whether it's known or not */
528         xbt_dict_get_ext(refs,(char*)ref, sizeof(char*));
529       else 
530         reference_is_to_send = 1;
531     } CATCH(e) {
532       if (e.category != not_found_error)
533         RETHROW;
534       reference_is_to_send = 1;
535       xbt_ex_free(e);
536     }
537
538     if (reference_is_to_send) {
539        VERB1("Sending data referenced at %p", (void*)*ref);
540        if (detect_cycle)
541          xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
542        gras_datadesc_send_rec(sock,state,refs, sub_type, *ref, 
543                               detect_cycle || sub_type->cycle);
544           
545     } else {
546        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
547     } 
548     
549     break;
550   }
551
552   case e_gras_datadesc_type_cat_array: {
553     gras_dd_cat_array_t    array_data;
554     int                    count;
555     char                  *ptr=data;
556     long int               elm_size;
557     
558     array_data = type->category.array_data;
559     
560     /* determine and send the element count */
561     count = array_data.fixed_size;
562     if (count == 0) {
563       count = array_data.dynamic_size(type,state,data);
564       xbt_assert1(count >=0,
565                    "Invalid (negative) array size for type %s",type->name);
566       gras_dd_send_int(sock, &count, 0/*non-stable*/);
567     }
568     
569     /* send the content */
570     sub_type = array_data.type;
571     elm_size = sub_type->aligned_size[GRAS_THISARCH];
572     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
573       VERB1("Array of %d scalars, send it in one shot",count);
574       gras_trp_send(sock, data, 
575                     sub_type->aligned_size[GRAS_THISARCH] * count,
576                     0 /* not stable */);
577     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
578                sub_type->category.array_data.fixed_size > 0 &&
579                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
580        
581       VERB1("Array of %d fixed array of scalars, send it in one shot",count);
582       gras_trp_send(sock, data, 
583                     sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
584                     * count * sub_type->category.array_data.fixed_size,
585                     0 /* not stable */);
586        
587     } else {
588       for (cpt=0; cpt<count; cpt++) {
589         gras_datadesc_send_rec(sock,state,refs, sub_type, ptr, 
590                                detect_cycle || sub_type->cycle);
591         ptr += elm_size;
592       }
593     }
594     break;
595   }
596
597   default:
598     xbt_assert0(0, "Invalid type");
599   }
600 }
601
602 /**
603  * gras_datadesc_send:
604  *
605  * Copy the data pointed by src and described by type to the socket
606  *
607  */
608 void gras_datadesc_send(gras_socket_t        sock, 
609                         gras_datadesc_type_t type, 
610                         void *src) {
611
612   xbt_ex_t e;
613   static gras_cbps_t state=NULL;
614   static xbt_dict_t  refs=NULL; /* all references already sent */
615  
616   xbt_assert0(type,"called with NULL type descriptor");
617
618   if (!state) {
619     state = gras_cbps_new();
620     refs = xbt_dict_new();
621   }
622    
623   TRY {
624     gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
625   } CLEANUP {
626     xbt_dict_reset(refs);
627     gras_cbps_reset(state);
628   } CATCH(e) {
629     RETHROW;
630   }
631 }
632
633 /**
634  * gras_datadesc_recv_rec:
635  *
636  * Do the data reception job recursively.
637  *
638  * subsize used only to deal with vicious case of reference to dynamic array.
639  *  This size is needed at the reference reception level (to allocate enough 
640  * space) and at the array reception level (to fill enough room). 
641  * 
642  * Having this size passed as an argument of the recursive function is a crude
643  * hack, but I was told that working code is sometimes better than neat one ;)
644  */
645 static void
646 gras_datadesc_recv_rec(gras_socket_t         sock, 
647                        gras_cbps_t           state,
648                        xbt_dict_t           refs,
649                        gras_datadesc_type_t  type,
650                        int                   r_arch,
651                        char                **r_data,
652                        long int              r_lgr,
653                        char                 *l_data,
654                        int                   subsize,
655                        int                   detect_cycle) {
656
657   int                  cpt;
658   gras_datadesc_type_t sub_type;
659   xbt_ex_t e;
660
661   VERB2("Recv a %s @%p", type->name, (void*)l_data);
662   xbt_assert(l_data);
663
664   switch (type->category_code) {
665   case e_gras_datadesc_type_cat_scalar:
666     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
667       gras_trp_recv(sock, (char*)l_data, type->size[r_arch]);
668       if (r_arch != GRAS_THISARCH)
669         gras_dd_convert_elm(type,1,r_arch, l_data,l_data);
670     } else {
671       void *ptr = xbt_malloc(type->size[r_arch]);
672
673       gras_trp_recv(sock, (char*)ptr, type->size[r_arch]);
674       if (r_arch != GRAS_THISARCH)
675         gras_dd_convert_elm(type,1,r_arch, ptr,l_data);
676       free(ptr);
677     }
678     break;
679
680   case e_gras_datadesc_type_cat_struct: {
681     gras_dd_cat_struct_t struct_data;
682     gras_dd_cat_field_t  field;
683
684     struct_data = type->category.struct_data;
685
686     xbt_assert1(struct_data.closed,
687                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
688                 type->name);
689     VERB1(">> Receive all fields of the structure %s",type->name);
690     xbt_dynar_foreach(struct_data.fields, cpt, field) {
691       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
692
693       sub_type = field->type;
694
695       gras_datadesc_recv_rec(sock,state,refs, sub_type,
696                              r_arch,NULL,0,
697                              field_data,-1, 
698                              detect_cycle || sub_type->cycle);
699        
700       if (field->recv) {
701         DEBUG1("Run the reception callback of field %s", field->name);
702         field->recv(type,state,(void*)l_data);
703       }
704     
705     }
706     VERB1("<< Received all fields of the structure %s", type->name);
707     
708     break;
709   }
710
711   case e_gras_datadesc_type_cat_union: {
712     gras_dd_cat_union_t union_data;
713     gras_dd_cat_field_t field=NULL;
714     int                 field_num;
715
716     union_data = type->category.union_data;
717
718     xbt_assert1(union_data.closed,
719                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
720                 type->name);
721     /* retrieve the field number */
722     gras_dd_recv_int(sock, r_arch, &field_num);
723     if (field_num < 0)
724       THROW1(mismatch_error,0,
725              "Received union field for %s is negative", type->name);
726     if (field_num > xbt_dynar_length(union_data.fields)) 
727       THROW3(mismatch_error,0,
728              "Received union field for %s is said to be #%d but there is only %lu fields",
729              type->name, field_num, xbt_dynar_length(union_data.fields));
730     
731     /* Recv the content */
732     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
733     sub_type = field->type;
734     
735     gras_datadesc_recv_rec(sock,state,refs, sub_type,
736                            r_arch,NULL,0,
737                            l_data,-1,
738                            detect_cycle || sub_type->cycle);
739     if (field->recv)
740        field->recv(type,state,l_data);
741
742     break;
743   }
744
745   case e_gras_datadesc_type_cat_ref: {
746     char             **r_ref = NULL;
747     char             **l_ref = NULL;
748     gras_dd_cat_ref_t  ref_data;
749     int reference_is_to_recv = 0;
750     
751     ref_data = type->category.ref_data;
752
753     /* Get the referenced type locally or from peer */
754     sub_type = ref_data.type;
755     if (sub_type == NULL) {
756       int ref_code;
757       gras_dd_recv_int(sock, r_arch, &ref_code);
758       sub_type = gras_datadesc_by_id(ref_code);
759     }
760
761     /* Get the actual value of the pointer for cycle handling */
762     if (!pointer_type) {
763       pointer_type = gras_datadesc_by_name("data pointer");
764       xbt_assert(pointer_type);
765     }
766
767     r_ref = xbt_malloc(pointer_type->size[r_arch]);
768
769     gras_trp_recv(sock, (char*)r_ref,
770                   pointer_type->size[r_arch]);
771
772     /* Receive the pointed data only if not already sent */
773     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
774       VERB1("Not receiving data remotely referenced @%p since it's NULL",
775             *(void **)r_ref);
776       *(void**)l_data = NULL;
777       free(r_ref);
778       break;
779     }
780          
781     reference_is_to_recv = 0;
782     TRY {
783       if (detect_cycle) {
784         l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
785       } else {
786         reference_is_to_recv = 1;
787       }
788     } CATCH(e) {
789       if (e.category != not_found_error)
790         RETHROW;
791       reference_is_to_recv = 1;
792       xbt_ex_free(e);
793     }
794
795     if (reference_is_to_recv) {
796       int subsubcount = 0;
797       void *l_referenced=NULL;
798
799       VERB2("Receiving a ref to '%s', remotely @%p",
800             sub_type->name, *(void**)r_ref);
801       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
802         /* Damn. Reference to a dynamic array. Allocating the space for it 
803            is more complicated */
804         gras_dd_cat_array_t array_data = sub_type->category.array_data;
805         gras_datadesc_type_t subsub_type;
806
807         subsubcount = array_data.fixed_size;
808         if (subsubcount == 0)
809           gras_dd_recv_int(sock, r_arch, &subsubcount);
810
811         subsub_type = array_data.type;
812
813
814         gras_dd_alloc_ref(refs,
815                           subsub_type->size[GRAS_THISARCH] * subsubcount, 
816                           r_ref,pointer_type->size[r_arch], 
817                           (char**)&l_referenced,
818                           detect_cycle);
819       } else {
820         gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
821                           r_ref,pointer_type->size[r_arch], 
822                           (char**)&l_referenced,
823                           detect_cycle);
824       }
825
826       gras_datadesc_recv_rec(sock,state,refs, sub_type,
827                              r_arch,r_ref,pointer_type->size[r_arch],
828                              (char*)l_referenced, subsubcount,
829                              detect_cycle || sub_type->cycle);
830                                
831       *(void**)l_data=l_referenced;
832       VERB3("'%s' remotely referenced at %p locally at %p",
833             sub_type->name, *(void**)r_ref, l_referenced);
834       
835     } else {
836       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
837             *(void**)r_ref, *(void**)l_ref);
838
839       *(void**)l_data=*l_ref;
840
841     } 
842     free(r_ref);
843     break;
844   }
845
846   case e_gras_datadesc_type_cat_array: {
847     gras_dd_cat_array_t    array_data;
848     int       count;
849     char     *ptr;
850     long int  elm_size;
851
852     array_data = type->category.array_data;
853     /* determine element count locally, or from caller, or from peer */
854     count = array_data.fixed_size;
855     if (count == 0)
856       count = subsize;
857     if (count == 0)
858       gras_dd_recv_int(sock, r_arch, &count);
859     if (count == 0)
860       THROW1(mismatch_error,0,
861              "Invalid (=0) array size for type %s",type->name);
862
863     /* receive the content */
864     sub_type = array_data.type;
865     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
866       VERB1("Array of %d scalars, get it in one shoot", count);
867       if (sub_type->aligned_size[GRAS_THISARCH] >= 
868           sub_type->aligned_size[r_arch]) {
869         gras_trp_recv(sock, (char*)l_data, 
870                       sub_type->aligned_size[r_arch] * count);
871         if (r_arch != GRAS_THISARCH)
872           gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data);
873       } else {
874         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
875
876         gras_trp_recv(sock, (char*)ptr, 
877                       sub_type->size[r_arch] * count);
878         if (r_arch != GRAS_THISARCH)
879           gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data);
880         free(ptr);
881       }
882     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
883                sub_type->category.array_data.fixed_size > 0 &&
884                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
885       gras_datadesc_type_t subsub_type;
886       array_data = sub_type->category.array_data;
887       subsub_type = array_data.type;
888        
889       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
890       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
891           subsub_type->aligned_size[r_arch]) {
892         gras_trp_recv(sock, (char*)l_data, 
893                       subsub_type->aligned_size[r_arch] * count * 
894                       array_data.fixed_size);
895         if (r_arch != GRAS_THISARCH)
896           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data);
897       } else {
898         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
899
900         gras_trp_recv(sock, (char*)ptr, 
901                       subsub_type->size[r_arch] * count*array_data.fixed_size);
902         if (r_arch != GRAS_THISARCH)
903           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data);
904         free(ptr);
905       }
906       
907        
908     } else {
909       /* not scalar content, get it recursively (may contain pointers) */
910       elm_size = sub_type->aligned_size[GRAS_THISARCH];
911       VERB2("Receive a %d-long array of %s",count, sub_type->name);
912
913       ptr = l_data;
914       for (cpt=0; cpt<count; cpt++) {
915         gras_datadesc_recv_rec(sock,state,refs, sub_type,
916                                r_arch, NULL, 0, ptr,-1,
917                                detect_cycle || sub_type->cycle);
918                                    
919         ptr += elm_size;
920       }
921     }
922     break;
923   }
924         
925   default:
926     xbt_assert0(0, "Invalid type");
927   }
928   
929   if (type->recv)
930     type->recv(type,state,l_data);
931
932   if (!strcmp(type->name,"string"))
933     VERB1("value: '%s'",*(char**)l_data);
934
935 }
936
937 /**
938  * gras_datadesc_recv:
939  *
940  * Get an instance of the datatype described by @type from the @socket, 
941  * and store a pointer to it in @dst
942  *
943  */
944 void
945 gras_datadesc_recv(gras_socket_t         sock, 
946                    gras_datadesc_type_t  type,
947                    int                   r_arch,
948                    void                 *dst) {
949
950   xbt_ex_t e;
951   static gras_cbps_t state=NULL; /* callback persistent state */
952   static xbt_dict_t  refs=NULL;  /* all references already sent */
953
954   if (!state) {
955     state = gras_cbps_new();
956     refs = xbt_dict_new();
957   }
958    
959   xbt_assert0(type,"called with NULL type descriptor");
960   TRY {
961     gras_datadesc_recv_rec(sock, state, refs, type, 
962                            r_arch, NULL, 0,
963                            (char *) dst,-1, 
964                            type->cycle);
965   } CLEANUP {
966     xbt_dict_reset(refs);
967     gras_cbps_reset(state);
968   } CATCH(e) {
969     RETHROW;
970   }
971 }
972