Logo AND Algorithmique Numérique Distribuée

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