Logo AND Algorithmique Numérique Distribuée

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