Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
18f0caabf5976e721da5403c2b496319cb73ec7a
[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, free);
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   xbt_dict_t  refs; /* all references already sent */
374   int size=0;
375  
376   xbt_assert0(type,"called with NULL type descriptor");
377
378   refs = xbt_dict_new();
379   if (!state)
380     state = gras_cbps_new();
381   
382   TRY {
383     size = gras_datadesc_copy_rec(state,refs,type,(char*)src,(char*)dst,0, 
384                                   type->cycle);
385   } CLEANUP {
386     xbt_dict_free(&refs);
387     gras_cbps_reset(state);
388   } CATCH(e) {
389     RETHROW;
390   }
391   return size;
392 }
393
394 /***
395  *** Direct use functions
396  ***/
397
398 static void
399 gras_datadesc_send_rec(gras_socket_t         sock,
400                        gras_cbps_t           state,
401                        xbt_dict_t            refs,
402                        gras_datadesc_type_t  type, 
403                        char                 *data,
404                        int                   detect_cycle) {
405
406   xbt_ex_t             e;
407   int                  cpt;
408   gras_datadesc_type_t sub_type; /* type on which we recurse */
409   
410   VERB2("Send a %s (%s)", 
411         type->name, gras_datadesc_cat_names[type->category_code]);
412
413   if (!strcmp(type->name,"string"))
414     VERB1("value: '%s'",*(char**)data);
415
416   if (type->send) {
417     type->send(type,state,data);
418     DEBUG0("Run the emission callback");
419   }
420
421   switch (type->category_code) {
422   case e_gras_datadesc_type_cat_scalar:
423     gras_trp_send(sock, data, type->size[GRAS_THISARCH], 1);
424     break;
425
426   case e_gras_datadesc_type_cat_struct: {
427     gras_dd_cat_struct_t struct_data;
428     gras_dd_cat_field_t  field;
429     char                *field_data;
430     
431     struct_data = type->category.struct_data;
432     xbt_assert1(struct_data.closed,
433       "Please call gras_datadesc_declare_struct_close on %s before sending it",
434                 type->name);
435     VERB1(">> Send all fields of the structure %s",type->name);
436     xbt_dynar_foreach(struct_data.fields, cpt, field) {
437       field_data = data;
438       field_data += field->offset[GRAS_THISARCH];
439       
440       sub_type = field->type;
441       
442       if (field->send) {
443         DEBUG1("Run the emission callback of field %s", field->name);
444         field->send(type,state,field_data);
445       }
446       
447       VERB1("Send field %s",field->name);
448       gras_datadesc_send_rec(sock,state,refs,sub_type, field_data, 
449                              detect_cycle || sub_type->cycle);
450       
451     }
452     VERB1("<< Sent all fields of the structure %s", type->name);
453     
454     break;
455   }
456
457   case e_gras_datadesc_type_cat_union: {
458     gras_dd_cat_union_t union_data;
459     gras_dd_cat_field_t field=NULL;
460     int                 field_num;
461     
462     union_data = type->category.union_data;
463     
464     xbt_assert1(union_data.closed,
465                 "Please call gras_datadesc_declare_union_close on %s before sending it",
466                 type->name);
467     /* retrieve the field number */
468     field_num = union_data.selector(type, state, data);
469     
470     xbt_assert1(field_num > 0,
471                  "union field selector of %s gave a negative value", 
472                  type->name);
473     
474     xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
475          "union field selector of %s returned %d but there is only %lu fields",
476                  type->name, field_num, xbt_dynar_length(union_data.fields));
477
478     /* Send the field number */
479     gras_dd_send_int(sock, &field_num, 0 /* not stable */);
480     
481     /* Send the content */
482     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
483     sub_type = field->type;
484     
485     if (field->send)
486       field->send(type,state,data);
487     
488     gras_datadesc_send_rec(sock,state,refs, sub_type, data, 
489                            detect_cycle || sub_type->cycle);
490           
491     break;
492   }
493     
494   case e_gras_datadesc_type_cat_ref: {
495     gras_dd_cat_ref_t      ref_data;
496     void                 **ref=(void**)data;
497     int                    reference_is_to_send;
498     
499     ref_data = type->category.ref_data;
500     
501     /* Detect the referenced type and send it to peer if needed */
502     sub_type = ref_data.type;
503     if (sub_type == NULL) {
504       sub_type = (*ref_data.selector)(type,state,data);
505       gras_dd_send_int(sock, (int*) &(sub_type->code),1 /*stable*/);
506     }
507     
508     /* Send the actual value of the pointer for cycle handling */
509     if (!pointer_type) {
510       pointer_type = gras_datadesc_by_name("data pointer");
511       xbt_assert(pointer_type);
512     }
513      
514     gras_trp_send(sock, (char*)data,
515                   pointer_type->size[GRAS_THISARCH], 1 /*stable*/);
516     
517     /* Send the pointed data only if not already sent */
518     if (*(void**)data == NULL) {
519       VERB0("Not sending NULL referenced data");
520       break;
521     }
522
523     reference_is_to_send = 0;
524     TRY {
525       if (detect_cycle)
526         /* return ignored. Just checking whether it's known or not */
527         xbt_dict_get_ext(refs,(char*)ref, sizeof(char*));
528       else 
529         reference_is_to_send = 1;
530     } CATCH(e) {
531       if (e.category != not_found_error)
532         RETHROW;
533       reference_is_to_send = 1;
534       xbt_ex_free(e);
535     }
536
537     if (reference_is_to_send) {
538        VERB1("Sending data referenced at %p", (void*)*ref);
539        if (detect_cycle)
540          xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
541        gras_datadesc_send_rec(sock,state,refs, sub_type, *ref, 
542                               detect_cycle || sub_type->cycle);
543           
544     } else {
545        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
546     } 
547     
548     break;
549   }
550
551   case e_gras_datadesc_type_cat_array: {
552     gras_dd_cat_array_t    array_data;
553     int                    count;
554     char                  *ptr=data;
555     long int               elm_size;
556     
557     array_data = type->category.array_data;
558     
559     /* determine and send the element count */
560     count = array_data.fixed_size;
561     if (count == 0) {
562       count = array_data.dynamic_size(type,state,data);
563       xbt_assert1(count >=0,
564                    "Invalid (negative) array size for type %s",type->name);
565       gras_dd_send_int(sock, &count, 0/*non-stable*/);
566     }
567     
568     /* send the content */
569     sub_type = array_data.type;
570     elm_size = sub_type->aligned_size[GRAS_THISARCH];
571     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
572       VERB1("Array of %d scalars, send it in one shot",count);
573       gras_trp_send(sock, data, 
574                     sub_type->aligned_size[GRAS_THISARCH] * count,
575                     0 /* not stable */);
576     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
577                sub_type->category.array_data.fixed_size > 0 &&
578                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
579        
580       VERB1("Array of %d fixed array of scalars, send it in one shot",count);
581       gras_trp_send(sock, data, 
582                     sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
583                     * count * sub_type->category.array_data.fixed_size,
584                     0 /* not stable */);
585        
586     } else {
587       for (cpt=0; cpt<count; cpt++) {
588         gras_datadesc_send_rec(sock,state,refs, sub_type, ptr, 
589                                detect_cycle || sub_type->cycle);
590         ptr += elm_size;
591       }
592     }
593     break;
594   }
595
596   default:
597     xbt_assert0(0, "Invalid type");
598   }
599 }
600
601 /**
602  * gras_datadesc_send:
603  *
604  * Copy the data pointed by src and described by type to the socket
605  *
606  */
607 void gras_datadesc_send(gras_socket_t        sock, 
608                         gras_datadesc_type_t type, 
609                         void *src) {
610
611   xbt_ex_t e;
612   static gras_cbps_t state=NULL;
613   xbt_dict_t  refs; /* all references already sent */
614  
615   xbt_assert0(type,"called with NULL type descriptor");
616
617   refs = xbt_dict_new();
618   if (!state)
619     state = gras_cbps_new();
620   
621   TRY {
622     gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
623   } CLEANUP {
624     xbt_dict_free(&refs);
625     gras_cbps_reset(state);
626   } CATCH(e) {
627     RETHROW;
628   }
629 }
630
631 /**
632  * gras_datadesc_recv_rec:
633  *
634  * Do the data reception job recursively.
635  *
636  * subsize used only to deal with vicious case of reference to dynamic array.
637  *  This size is needed at the reference reception level (to allocate enough 
638  * space) and at the array reception level (to fill enough room). 
639  * 
640  * Having this size passed as an argument of the recursive function is a crude
641  * hack, but I was told that working code is sometimes better than neat one ;)
642  */
643 static void
644 gras_datadesc_recv_rec(gras_socket_t         sock, 
645                        gras_cbps_t           state,
646                        xbt_dict_t           refs,
647                        gras_datadesc_type_t  type,
648                        int                   r_arch,
649                        char                **r_data,
650                        long int              r_lgr,
651                        char                 *l_data,
652                        int                   subsize,
653                        int                   detect_cycle) {
654
655   int                  cpt;
656   gras_datadesc_type_t sub_type;
657   xbt_ex_t e;
658
659   VERB2("Recv a %s @%p", type->name, (void*)l_data);
660   xbt_assert(l_data);
661
662   switch (type->category_code) {
663   case e_gras_datadesc_type_cat_scalar:
664     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
665       gras_trp_recv(sock, (char*)l_data, type->size[r_arch]);
666       if (r_arch != GRAS_THISARCH)
667         gras_dd_convert_elm(type,1,r_arch, l_data,l_data);
668     } else {
669       void *ptr = xbt_malloc(type->size[r_arch]);
670
671       gras_trp_recv(sock, (char*)ptr, type->size[r_arch]);
672       if (r_arch != GRAS_THISARCH)
673         gras_dd_convert_elm(type,1,r_arch, ptr,l_data);
674       free(ptr);
675     }
676     break;
677
678   case e_gras_datadesc_type_cat_struct: {
679     gras_dd_cat_struct_t struct_data;
680     gras_dd_cat_field_t  field;
681
682     struct_data = type->category.struct_data;
683
684     xbt_assert1(struct_data.closed,
685                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
686                 type->name);
687     VERB1(">> Receive all fields of the structure %s",type->name);
688     xbt_dynar_foreach(struct_data.fields, cpt, field) {
689       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
690
691       sub_type = field->type;
692
693       gras_datadesc_recv_rec(sock,state,refs, sub_type,
694                              r_arch,NULL,0,
695                              field_data,-1, 
696                              detect_cycle || sub_type->cycle);
697        
698       if (field->recv) {
699         DEBUG1("Run the reception callback of field %s", field->name);
700         field->recv(type,state,(void*)l_data);
701       }
702     
703     }
704     VERB1("<< Received all fields of the structure %s", type->name);
705     
706     break;
707   }
708
709   case e_gras_datadesc_type_cat_union: {
710     gras_dd_cat_union_t union_data;
711     gras_dd_cat_field_t field=NULL;
712     int                 field_num;
713
714     union_data = type->category.union_data;
715
716     xbt_assert1(union_data.closed,
717                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
718                 type->name);
719     /* retrieve the field number */
720     gras_dd_recv_int(sock, r_arch, &field_num);
721     if (field_num < 0)
722       THROW1(mismatch_error,0,
723              "Received union field for %s is negative", type->name);
724     if (field_num > xbt_dynar_length(union_data.fields)) 
725       THROW3(mismatch_error,0,
726              "Received union field for %s is said to be #%d but there is only %lu fields",
727              type->name, field_num, xbt_dynar_length(union_data.fields));
728     
729     /* Recv the content */
730     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
731     sub_type = field->type;
732     
733     gras_datadesc_recv_rec(sock,state,refs, sub_type,
734                            r_arch,NULL,0,
735                            l_data,-1,
736                            detect_cycle || sub_type->cycle);
737     if (field->recv)
738        field->recv(type,state,l_data);
739
740     break;
741   }
742
743   case e_gras_datadesc_type_cat_ref: {
744     char             **r_ref = NULL;
745     char             **l_ref = NULL;
746     gras_dd_cat_ref_t  ref_data;
747     int reference_is_to_recv = 0;
748     
749     ref_data = type->category.ref_data;
750
751     /* Get the referenced type locally or from peer */
752     sub_type = ref_data.type;
753     if (sub_type == NULL) {
754       int ref_code;
755       gras_dd_recv_int(sock, r_arch, &ref_code);
756       sub_type = gras_datadesc_by_id(ref_code);
757     }
758
759     /* Get the actual value of the pointer for cycle handling */
760     if (!pointer_type) {
761       pointer_type = gras_datadesc_by_name("data pointer");
762       xbt_assert(pointer_type);
763     }
764
765     r_ref = xbt_malloc(pointer_type->size[r_arch]);
766
767     gras_trp_recv(sock, (char*)r_ref,
768                   pointer_type->size[r_arch]);
769
770     /* Receive the pointed data only if not already sent */
771     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
772       VERB1("Not receiving data remotely referenced @%p since it's NULL",
773             *(void **)r_ref);
774       *(void**)l_data = NULL;
775       free(r_ref);
776       break;
777     }
778          
779     reference_is_to_recv = 0;
780     TRY {
781       if (detect_cycle) {
782         l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
783       } else {
784         reference_is_to_recv = 1;
785       }
786     } CATCH(e) {
787       if (e.category != not_found_error)
788         RETHROW;
789       reference_is_to_recv = 1;
790       xbt_ex_free(e);
791     }
792
793     if (reference_is_to_recv) {
794       int subsubcount = 0;
795       void *l_referenced=NULL;
796
797       VERB2("Receiving a ref to '%s', remotely @%p",
798             sub_type->name, *(void**)r_ref);
799       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
800         /* Damn. Reference to a dynamic array. Allocating the space for it 
801            is more complicated */
802         gras_dd_cat_array_t array_data = sub_type->category.array_data;
803         gras_datadesc_type_t subsub_type;
804
805         subsubcount = array_data.fixed_size;
806         if (subsubcount == 0)
807           gras_dd_recv_int(sock, r_arch, &subsubcount);
808
809         subsub_type = array_data.type;
810
811
812         gras_dd_alloc_ref(refs,
813                           subsub_type->size[GRAS_THISARCH] * subsubcount, 
814                           r_ref,pointer_type->size[r_arch], 
815                           (char**)&l_referenced,
816                           detect_cycle);
817       } else {
818         gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
819                           r_ref,pointer_type->size[r_arch], 
820                           (char**)&l_referenced,
821                           detect_cycle);
822       }
823
824       gras_datadesc_recv_rec(sock,state,refs, sub_type,
825                              r_arch,r_ref,pointer_type->size[r_arch],
826                              (char*)l_referenced, subsubcount,
827                              detect_cycle || sub_type->cycle);
828                                
829       *(void**)l_data=l_referenced;
830       VERB3("'%s' remotely referenced at %p locally at %p",
831             sub_type->name, *(void**)r_ref, l_referenced);
832       
833     } else {
834       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
835             *(void**)r_ref, *(void**)l_ref);
836
837       *(void**)l_data=*l_ref;
838
839     } 
840     free(r_ref);
841     break;
842   }
843
844   case e_gras_datadesc_type_cat_array: {
845     gras_dd_cat_array_t    array_data;
846     int       count;
847     char     *ptr;
848     long int  elm_size;
849
850     array_data = type->category.array_data;
851     /* determine element count locally, or from caller, or from peer */
852     count = array_data.fixed_size;
853     if (count == 0)
854       count = subsize;
855     if (count == 0)
856       gras_dd_recv_int(sock, r_arch, &count);
857     if (count == 0)
858       THROW1(mismatch_error,0,
859              "Invalid (=0) array size for type %s",type->name);
860
861     /* receive the content */
862     sub_type = array_data.type;
863     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
864       VERB1("Array of %d scalars, get it in one shoot", count);
865       if (sub_type->aligned_size[GRAS_THISARCH] >= 
866           sub_type->aligned_size[r_arch]) {
867         gras_trp_recv(sock, (char*)l_data, 
868                       sub_type->aligned_size[r_arch] * count);
869         if (r_arch != GRAS_THISARCH)
870           gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data);
871       } else {
872         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
873
874         gras_trp_recv(sock, (char*)ptr, 
875                       sub_type->size[r_arch] * count);
876         if (r_arch != GRAS_THISARCH)
877           gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data);
878         free(ptr);
879       }
880     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
881                sub_type->category.array_data.fixed_size > 0 &&
882                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
883       gras_datadesc_type_t subsub_type;
884       array_data = sub_type->category.array_data;
885       subsub_type = array_data.type;
886        
887       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
888       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
889           subsub_type->aligned_size[r_arch]) {
890         gras_trp_recv(sock, (char*)l_data, 
891                       subsub_type->aligned_size[r_arch] * count * 
892                       array_data.fixed_size);
893         if (r_arch != GRAS_THISARCH)
894           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data);
895       } else {
896         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
897
898         gras_trp_recv(sock, (char*)ptr, 
899                       subsub_type->size[r_arch] * count*array_data.fixed_size);
900         if (r_arch != GRAS_THISARCH)
901           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data);
902         free(ptr);
903       }
904       
905        
906     } else {
907       /* not scalar content, get it recursively (may contain pointers) */
908       elm_size = sub_type->aligned_size[GRAS_THISARCH];
909       VERB2("Receive a %d-long array of %s",count, sub_type->name);
910
911       ptr = l_data;
912       for (cpt=0; cpt<count; cpt++) {
913         gras_datadesc_recv_rec(sock,state,refs, sub_type,
914                                r_arch, NULL, 0, ptr,-1,
915                                detect_cycle || sub_type->cycle);
916                                    
917         ptr += elm_size;
918       }
919     }
920     break;
921   }
922         
923   default:
924     xbt_assert0(0, "Invalid type");
925   }
926   
927   if (type->recv)
928     type->recv(type,state,l_data);
929
930   if (!strcmp(type->name,"string"))
931     VERB1("value: '%s'",*(char**)l_data);
932
933 }
934
935 /**
936  * gras_datadesc_recv:
937  *
938  * Get an instance of the datatype described by @type from the @socket, 
939  * and store a pointer to it in @dst
940  *
941  */
942 void
943 gras_datadesc_recv(gras_socket_t         sock, 
944                    gras_datadesc_type_t  type,
945                    int                   r_arch,
946                    void                 *dst) {
947
948   xbt_ex_t e;
949   static gras_cbps_t state=NULL; /* callback persistent state */
950   xbt_dict_t  refs;  /* all references already sent */
951
952   refs = xbt_dict_new();
953   if (!state)
954     state = gras_cbps_new();
955
956   xbt_assert0(type,"called with NULL type descriptor");
957   TRY {
958     gras_datadesc_recv_rec(sock, state, refs, type, 
959                            r_arch, NULL, 0,
960                            (char *) dst,-1, 
961                            type->cycle);
962   } CLEANUP {
963     xbt_dict_free(&refs);
964     gras_cbps_reset(state);
965   } CATCH(e) {
966     RETHROW;
967   }
968 }
969