Logo AND Algorithmique Numérique Distribuée

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