Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Sanitize the log channels naming scheme in GRAS too
[simgrid.git] / src / gras / DataDesc / ddt_exchange.c
1 /* $Id$ */
2
3 /* ddt_exchange - send/recv data described                                  */
4
5 /* Copyright (c) 2003 Olivier Aumage.                                       */
6 /* Copyright (c) 2003, 2004, 2005 Martin Quinson.                           */
7 /* All rights reserved.                                                     */
8
9 /* This program is free software; you can redistribute it and/or modify it
10  * under the terms of the license (GNU LGPL) which comes with this package. */
11
12 #include "xbt/ex.h"
13 #include "gras/DataDesc/datadesc_private.h"
14 #include "gras/Transport/transport_interface.h" /* gras_trp_send/recv */
15
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(gras_ddt_exchange,gras_ddt,
17                                  "Sending data over the network");
18 const char *gras_datadesc_cat_names[9] = { 
19   "undefined", 
20   "scalar", "struct", "union", "ref", "array", "ignored",
21   "invalid"};
22
23 static gras_datadesc_type_t int_type = NULL;
24 static gras_datadesc_type_t pointer_type = NULL;    
25
26 static _XBT_INLINE void
27 gras_dd_send_int(gras_socket_t sock,int *i, int stable) {
28
29   if (!int_type) {
30     int_type = gras_datadesc_by_name("int");
31      xbt_assert(int_type);  
32   }
33    
34   DEBUG1("send_int(%d)",*i);
35   gras_trp_send(sock, (char*)i, int_type->size[GRAS_THISARCH], stable);
36 }
37
38 static _XBT_INLINE void
39 gras_dd_recv_int(gras_socket_t sock, int r_arch, int *i) {
40
41   if (!int_type) {
42      int_type = gras_datadesc_by_name("int");
43      xbt_assert(int_type);
44   }
45
46   if (int_type->size[GRAS_THISARCH] >= int_type->size[r_arch]) {
47     gras_trp_recv(sock, (char*)i, int_type->size[r_arch]);
48     if (r_arch != GRAS_THISARCH)
49       gras_dd_convert_elm(int_type,1,r_arch, i,i);
50   } else {
51     void *ptr = xbt_malloc(int_type->size[r_arch]);
52
53     gras_trp_recv(sock, (char*)ptr, int_type->size[r_arch]);
54     if (r_arch != GRAS_THISARCH)
55       gras_dd_convert_elm(int_type,1,r_arch, ptr,i);
56     free(ptr);
57   }
58   DEBUG1("recv_int(%d)",*i);
59 }
60
61 /*
62  * Note: here we suppose that the remote NULL is a sequence 
63  *       of 'length' bytes set to 0.
64  * FIXME: Check in configure?
65  */
66 static _XBT_INLINE int 
67 gras_dd_is_r_null(char **r_ptr, long int length) {
68   int i;
69
70   for (i=0; i<length; i++) {
71     if ( ((unsigned char*)r_ptr) [i]) {
72       return 0;
73     }
74   }
75
76   return 1;
77 }
78
79 static _XBT_INLINE void
80 gras_dd_alloc_ref(xbt_dict_t  refs,
81                   long int     size,
82                   char       **r_ref,
83                   long int     r_len, /* pointer_type->size[r_arch] */
84                   char       **l_ref,
85                   int          detect_cycle) {
86   char *l_data = NULL;
87
88   xbt_assert1(size>0,"Cannot allocate %ld bytes!", size);
89   l_data = xbt_malloc((size_t)size);
90
91   *l_ref = l_data;
92   DEBUG5("alloc_ref: l_data=%p, &l_data=%p; r_ref=%p; *r_ref=%p, r_len=%ld",
93          (void*)l_data,(void*)&l_data,
94          (void*)r_ref, (void*)(r_ref?*r_ref:NULL), r_len);
95   if (detect_cycle && r_ref && !gras_dd_is_r_null( r_ref, r_len)) {
96     void *ptr = xbt_malloc(sizeof(void *));
97
98     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 (!strcmp(type->name,"string"))
394     VERB1("value: '%s'",*(char**)data);
395
396   if (type->send) {
397     type->send(type,state,data);
398     DEBUG0("Run the emission callback");
399   }
400
401   switch (type->category_code) {
402   case e_gras_datadesc_type_cat_scalar:
403     gras_trp_send(sock, data, type->size[GRAS_THISARCH], 1);
404     break;
405
406   case e_gras_datadesc_type_cat_struct: {
407     gras_dd_cat_struct_t struct_data;
408     gras_dd_cat_field_t  field;
409     char                *field_data;
410     
411     struct_data = type->category.struct_data;
412     xbt_assert1(struct_data.closed,
413       "Please call gras_datadesc_declare_struct_close on %s before sending it",
414                 type->name);
415     VERB1(">> Send all fields of the structure %s",type->name);
416     xbt_dynar_foreach(struct_data.fields, cpt, field) {
417       field_data = data;
418       field_data += field->offset[GRAS_THISARCH];
419       
420       sub_type = field->type;
421       
422       if (field->send) {
423         DEBUG1("Run the emission callback of field %s", field->name);
424         field->send(type,state,field_data);
425       }
426       
427       VERB1("Send field %s",field->name);
428       gras_datadesc_send_rec(sock,state,refs,sub_type, field_data, 
429                              detect_cycle || sub_type->cycle);
430       
431     }
432     VERB1("<< Sent all fields of the structure %s", type->name);
433     
434     break;
435   }
436
437   case e_gras_datadesc_type_cat_union: {
438     gras_dd_cat_union_t union_data;
439     gras_dd_cat_field_t field=NULL;
440     int                 field_num;
441     
442     union_data = type->category.union_data;
443     
444     xbt_assert1(union_data.closed,
445                 "Please call gras_datadesc_declare_union_close on %s before sending it",
446                 type->name);
447     /* retrieve the field number */
448     field_num = union_data.selector(type, state, data);
449     
450     xbt_assert1(field_num > 0,
451                  "union field selector of %s gave a negative value", 
452                  type->name);
453     
454     xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
455          "union field selector of %s returned %d but there is only %lu fields",
456                  type->name, field_num, xbt_dynar_length(union_data.fields));
457
458     /* Send the field number */
459     gras_dd_send_int(sock, &field_num, 0 /* not stable */);
460     
461     /* Send the content */
462     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
463     sub_type = field->type;
464     
465     if (field->send)
466       field->send(type,state,data);
467     
468     gras_datadesc_send_rec(sock,state,refs, sub_type, data, 
469                            detect_cycle || sub_type->cycle);
470           
471     break;
472   }
473     
474   case e_gras_datadesc_type_cat_ref: {
475     gras_dd_cat_ref_t      ref_data;
476     void                 **ref=(void**)data;
477     int                    reference_is_to_send;
478     
479     ref_data = type->category.ref_data;
480     
481     /* Detect the referenced type and send it to peer if needed */
482     sub_type = ref_data.type;
483     if (sub_type == NULL) {
484       sub_type = (*ref_data.selector)(type,state,data);
485       gras_dd_send_int(sock, (int*) &(sub_type->code),1 /*stable*/);
486     }
487     
488     /* Send the actual value of the pointer for cycle handling */
489     if (!pointer_type) {
490       pointer_type = gras_datadesc_by_name("data pointer");
491       xbt_assert(pointer_type);
492     }
493      
494     gras_trp_send(sock, (char*)data,
495                   pointer_type->size[GRAS_THISARCH], 1 /*stable*/);
496     
497     /* Send the pointed data only if not already sent */
498     if (*(void**)data == NULL) {
499       VERB0("Not sending NULL referenced data");
500       break;
501     }
502
503     reference_is_to_send = 0;
504     TRY {
505       if (detect_cycle)
506         /* return ignored. Just checking whether it's known or not */
507         xbt_dict_get_ext(refs,(char*)ref, sizeof(char*));
508       else 
509         reference_is_to_send = 1;
510     } CATCH(e) {
511       if (e.category != not_found_error)
512         RETHROW;
513       reference_is_to_send = 1;
514       xbt_ex_free(e);
515     }
516
517     if (reference_is_to_send) {
518        VERB1("Sending data referenced at %p", (void*)*ref);
519        if (detect_cycle)
520          xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
521        gras_datadesc_send_rec(sock,state,refs, sub_type, *ref, 
522                               detect_cycle || sub_type->cycle);
523           
524     } else {
525        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
526     } 
527     
528     break;
529   }
530
531   case e_gras_datadesc_type_cat_array: {
532     gras_dd_cat_array_t    array_data;
533     int                    count;
534     char                  *ptr=data;
535     long int               elm_size;
536     
537     array_data = type->category.array_data;
538     
539     /* determine and send the element count */
540     count = array_data.fixed_size;
541     if (count == 0) {
542       count = array_data.dynamic_size(type,state,data);
543       xbt_assert1(count >=0,
544                    "Invalid (negative) array size for type %s",type->name);
545       gras_dd_send_int(sock, &count, 0/*non-stable*/);
546     }
547     
548     /* send the content */
549     sub_type = array_data.type;
550     elm_size = sub_type->aligned_size[GRAS_THISARCH];
551     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
552       VERB1("Array of %d scalars, send it in one shot",count);
553       gras_trp_send(sock, data, 
554                     sub_type->aligned_size[GRAS_THISARCH] * count,
555                     0 /* not stable */);
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 %d fixed array of scalars, send it in one shot",count);
561       gras_trp_send(sock, data, 
562                     sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
563                     * count * sub_type->category.array_data.fixed_size,
564                     0 /* not stable */);
565        
566     } else {
567       for (cpt=0; cpt<count; cpt++) {
568         gras_datadesc_send_rec(sock,state,refs, sub_type, ptr, 
569                                detect_cycle || sub_type->cycle);
570         ptr += elm_size;
571       }
572     }
573     break;
574   }
575
576   default:
577     xbt_assert0(0, "Invalid type");
578   }
579 }
580
581 /**
582  * gras_datadesc_send:
583  *
584  * Copy the data pointed by src and described by type to the socket
585  *
586  */
587 void gras_datadesc_send(gras_socket_t        sock, 
588                         gras_datadesc_type_t type, 
589                         void *src) {
590
591   xbt_ex_t e;
592   static gras_cbps_t state=NULL;
593   xbt_dict_t  refs; /* all references already sent */
594  
595   xbt_assert0(type,"called with NULL type descriptor");
596
597   refs = xbt_dict_new();
598   if (!state)
599     state = gras_cbps_new();
600   
601   TRY {
602     gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
603   } CLEANUP {
604     xbt_dict_free(&refs);
605     gras_cbps_reset(state);
606   } CATCH(e) {
607     RETHROW;
608   }
609 }
610
611 /**
612  * gras_datadesc_recv_rec:
613  *
614  * Do the data reception job recursively.
615  *
616  * subsize used only to deal with vicious case of reference to dynamic array.
617  *  This size is needed at the reference reception level (to allocate enough 
618  * space) and at the array reception level (to fill enough room). 
619  * 
620  * Having this size passed as an argument of the recursive function is a crude
621  * hack, but I was told that working code is sometimes better than neat one ;)
622  */
623 static void
624 gras_datadesc_recv_rec(gras_socket_t         sock, 
625                        gras_cbps_t           state,
626                        xbt_dict_t           refs,
627                        gras_datadesc_type_t  type,
628                        int                   r_arch,
629                        char                **r_data,
630                        long int              r_lgr,
631                        char                 *l_data,
632                        int                   subsize,
633                        int                   detect_cycle) {
634
635   int                  cpt;
636   gras_datadesc_type_t sub_type;
637   xbt_ex_t e;
638
639   VERB2("Recv a %s @%p", type->name, (void*)l_data);
640   xbt_assert(l_data);
641
642   switch (type->category_code) {
643   case e_gras_datadesc_type_cat_scalar:
644     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
645       gras_trp_recv(sock, (char*)l_data, type->size[r_arch]);
646       if (r_arch != GRAS_THISARCH)
647         gras_dd_convert_elm(type,1,r_arch, l_data,l_data);
648     } else {
649       void *ptr = xbt_malloc(type->size[r_arch]);
650
651       gras_trp_recv(sock, (char*)ptr, type->size[r_arch]);
652       if (r_arch != GRAS_THISARCH)
653         gras_dd_convert_elm(type,1,r_arch, ptr,l_data);
654       free(ptr);
655     }
656     break;
657
658   case e_gras_datadesc_type_cat_struct: {
659     gras_dd_cat_struct_t struct_data;
660     gras_dd_cat_field_t  field;
661
662     struct_data = type->category.struct_data;
663
664     xbt_assert1(struct_data.closed,
665                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
666                 type->name);
667     VERB1(">> Receive all fields of the structure %s",type->name);
668     xbt_dynar_foreach(struct_data.fields, cpt, field) {
669       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
670
671       sub_type = field->type;
672
673       gras_datadesc_recv_rec(sock,state,refs, sub_type,
674                              r_arch,NULL,0,
675                              field_data,-1, 
676                              detect_cycle || sub_type->cycle);
677        
678       if (field->recv) {
679         DEBUG1("Run the reception callback of field %s", field->name);
680         field->recv(type,state,(void*)l_data);
681       }
682     
683     }
684     VERB1("<< Received all fields of the structure %s", type->name);
685     
686     break;
687   }
688
689   case e_gras_datadesc_type_cat_union: {
690     gras_dd_cat_union_t union_data;
691     gras_dd_cat_field_t field=NULL;
692     int                 field_num;
693
694     union_data = type->category.union_data;
695
696     xbt_assert1(union_data.closed,
697                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
698                 type->name);
699     /* retrieve the field number */
700     gras_dd_recv_int(sock, r_arch, &field_num);
701     if (field_num < 0)
702       THROW1(mismatch_error,0,
703              "Received union field for %s is negative", type->name);
704     if (field_num > xbt_dynar_length(union_data.fields)) 
705       THROW3(mismatch_error,0,
706              "Received union field for %s is said to be #%d but there is only %lu fields",
707              type->name, field_num, xbt_dynar_length(union_data.fields));
708     
709     /* Recv the content */
710     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
711     sub_type = field->type;
712     
713     gras_datadesc_recv_rec(sock,state,refs, sub_type,
714                            r_arch,NULL,0,
715                            l_data,-1,
716                            detect_cycle || sub_type->cycle);
717     if (field->recv)
718        field->recv(type,state,l_data);
719
720     break;
721   }
722
723   case e_gras_datadesc_type_cat_ref: {
724     char             **r_ref = NULL;
725     char             **l_ref = NULL;
726     gras_dd_cat_ref_t  ref_data;
727     int reference_is_to_recv = 0;
728     
729     ref_data = type->category.ref_data;
730
731     /* Get the referenced type locally or from peer */
732     sub_type = ref_data.type;
733     if (sub_type == NULL) {
734       int ref_code;
735       gras_dd_recv_int(sock, r_arch, &ref_code);
736       sub_type = gras_datadesc_by_id(ref_code);
737     }
738
739     /* Get the actual value of the pointer for cycle handling */
740     if (!pointer_type) {
741       pointer_type = gras_datadesc_by_name("data pointer");
742       xbt_assert(pointer_type);
743     }
744
745     r_ref = xbt_malloc(pointer_type->size[r_arch]);
746
747     gras_trp_recv(sock, (char*)r_ref,
748                   pointer_type->size[r_arch]);
749
750     /* Receive the pointed data only if not already sent */
751     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
752       VERB1("Not receiving data remotely referenced @%p since it's NULL",
753             *(void **)r_ref);
754       *(void**)l_data = NULL;
755       free(r_ref);
756       break;
757     }
758          
759     reference_is_to_recv = 0;
760     TRY {
761       if (detect_cycle)
762         l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
763       else 
764         reference_is_to_recv = 1;
765     } CATCH(e) {
766       if (e.category != not_found_error)
767         RETHROW;
768       reference_is_to_recv = 1;
769       xbt_ex_free(e);
770     }
771     if (reference_is_to_recv) {
772       int subsubcount = 0;
773       void *l_referenced=NULL;
774
775       VERB2("Receiving a ref to '%s', remotely @%p",
776             sub_type->name, *(void**)r_ref);
777       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
778         /* Damn. Reference to a dynamic array. Allocating the space for it 
779            is more complicated */
780         gras_dd_cat_array_t array_data = sub_type->category.array_data;
781         gras_datadesc_type_t subsub_type;
782
783         subsubcount = array_data.fixed_size;
784         if (subsubcount == 0)
785           gras_dd_recv_int(sock, r_arch, &subsubcount);
786
787         subsub_type = array_data.type;
788
789
790         gras_dd_alloc_ref(refs,
791                           subsub_type->size[GRAS_THISARCH] * subsubcount, 
792                           r_ref,pointer_type->size[r_arch], 
793                           (char**)&l_referenced,
794                           detect_cycle);
795       } else {
796         gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
797                           r_ref,pointer_type->size[r_arch], 
798                           (char**)&l_referenced,
799                           detect_cycle);
800       }
801
802       gras_datadesc_recv_rec(sock,state,refs, sub_type,
803                              r_arch,r_ref,pointer_type->size[r_arch],
804                              (char*)l_referenced, subsubcount,
805                              detect_cycle || sub_type->cycle);
806                                
807       *(void**)l_data=l_referenced;
808       VERB3("'%s' remotely referenced at %p locally at %p",
809             sub_type->name, *(void**)r_ref, l_referenced);
810       
811     } else {
812       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
813             *(void**)r_ref, *(void**)l_ref);
814
815       *(void**)l_data=*l_ref;
816
817     } 
818     free(r_ref);
819     break;
820   }
821
822   case e_gras_datadesc_type_cat_array: {
823     gras_dd_cat_array_t    array_data;
824     int       count;
825     char     *ptr;
826     long int  elm_size;
827
828     array_data = type->category.array_data;
829     /* determine element count locally, or from caller, or from peer */
830     count = array_data.fixed_size;
831     if (count == 0)
832       count = subsize;
833     if (count == 0)
834       gras_dd_recv_int(sock, r_arch, &count);
835     if (count == 0)
836       THROW1(mismatch_error,0,
837              "Invalid (=0) array size for type %s",type->name);
838
839     /* receive the content */
840     sub_type = array_data.type;
841     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
842       VERB1("Array of %d scalars, get it in one shoot", count);
843       if (sub_type->aligned_size[GRAS_THISARCH] >= 
844           sub_type->aligned_size[r_arch]) {
845         gras_trp_recv(sock, (char*)l_data, 
846                       sub_type->aligned_size[r_arch] * count);
847         if (r_arch != GRAS_THISARCH)
848           gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data);
849       } else {
850         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
851
852         gras_trp_recv(sock, (char*)ptr, 
853                       sub_type->size[r_arch] * count);
854         if (r_arch != GRAS_THISARCH)
855           gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data);
856         free(ptr);
857       }
858     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
859                sub_type->category.array_data.fixed_size > 0 &&
860                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
861       gras_datadesc_type_t subsub_type;
862       array_data = sub_type->category.array_data;
863       subsub_type = array_data.type;
864        
865       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
866       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
867           subsub_type->aligned_size[r_arch]) {
868         gras_trp_recv(sock, (char*)l_data, 
869                       subsub_type->aligned_size[r_arch] * count * 
870                       array_data.fixed_size);
871         if (r_arch != GRAS_THISARCH)
872           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data);
873       } else {
874         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
875
876         gras_trp_recv(sock, (char*)ptr, 
877                       subsub_type->size[r_arch] * count*array_data.fixed_size);
878         if (r_arch != GRAS_THISARCH)
879           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data);
880         free(ptr);
881       }
882       
883        
884     } else {
885       /* not scalar content, get it recursively (may contain pointers) */
886       elm_size = sub_type->aligned_size[GRAS_THISARCH];
887       VERB2("Receive a %d-long array of %s",count, sub_type->name);
888
889       ptr = l_data;
890       for (cpt=0; cpt<count; cpt++) {
891         gras_datadesc_recv_rec(sock,state,refs, sub_type,
892                                r_arch, NULL, 0, ptr,-1,
893                                detect_cycle || sub_type->cycle);
894                                    
895         ptr += elm_size;
896       }
897     }
898     break;
899   }
900         
901   default:
902     xbt_assert0(0, "Invalid type");
903   }
904   
905   if (type->recv)
906     type->recv(type,state,l_data);
907
908   if (!strcmp(type->name,"string"))
909     VERB1("value: '%s'",*(char**)l_data);
910
911 }
912
913 /**
914  * gras_datadesc_recv:
915  *
916  * Get an instance of the datatype described by @type from the @socket, 
917  * and store a pointer to it in @dst
918  *
919  */
920 void
921 gras_datadesc_recv(gras_socket_t         sock, 
922                    gras_datadesc_type_t  type,
923                    int                   r_arch,
924                    void                 *dst) {
925
926   xbt_ex_t e;
927   static gras_cbps_t state=NULL; /* callback persistent state */
928   xbt_dict_t  refs;  /* all references already sent */
929
930   refs = xbt_dict_new();
931   if (!state)
932     state = gras_cbps_new();
933
934   xbt_assert0(type,"called with NULL type descriptor");
935   TRY {
936     gras_datadesc_recv_rec(sock, state, refs, type, 
937                            r_arch, NULL, 0,
938                            (char *) dst,-1, 
939                            type->cycle);
940   } CLEANUP {
941     xbt_dict_free(&refs);
942     gras_cbps_reset(state);
943   } CATCH(e) {
944     RETHROW;
945   }
946 }
947