Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Rework the Transport layer to simplify it and improve its performance
[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, &(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   gras_cbps_t  state;
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   state = gras_cbps_new();
590   
591   TRY {
592     gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
593   } CLEANUP {
594     xbt_dict_free(&refs);
595     gras_cbps_free(&state);
596   } CATCH(e) {
597     RETHROW;
598   }
599 }
600
601 /**
602  * gras_datadesc_recv_rec:
603  *
604  * Do the data reception job recursively.
605  *
606  * subsize used only to deal with vicious case of reference to dynamic array.
607  *  This size is needed at the reference reception level (to allocate enough 
608  * space) and at the array reception level (to fill enough room). 
609  * 
610  * Having this size passed as an argument of the recursive function is a crude
611  * hack, but I was told that working code is sometimes better than neat one ;)
612  */
613 static void
614 gras_datadesc_recv_rec(gras_socket_t         sock, 
615                        gras_cbps_t           state,
616                        xbt_dict_t           refs,
617                        gras_datadesc_type_t  type,
618                        int                   r_arch,
619                        char                **r_data,
620                        long int              r_lgr,
621                        char                 *l_data,
622                        int                   subsize,
623                        int                   detect_cycle) {
624
625   int                  cpt;
626   gras_datadesc_type_t sub_type;
627   xbt_ex_t e;
628
629   VERB2("Recv a %s @%p", type->name, (void*)l_data);
630   xbt_assert(l_data);
631
632   switch (type->category_code) {
633   case e_gras_datadesc_type_cat_scalar:
634     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
635       gras_trp_recv(sock, (char*)l_data, type->size[r_arch]);
636       if (r_arch != GRAS_THISARCH)
637         gras_dd_convert_elm(type,1,r_arch, l_data,l_data);
638     } else {
639       void *ptr = xbt_malloc(type->size[r_arch]);
640
641       gras_trp_recv(sock, (char*)ptr, type->size[r_arch]);
642       if (r_arch != GRAS_THISARCH)
643         gras_dd_convert_elm(type,1,r_arch, ptr,l_data);
644       free(ptr);
645     }
646     break;
647
648   case e_gras_datadesc_type_cat_struct: {
649     gras_dd_cat_struct_t struct_data;
650     gras_dd_cat_field_t  field;
651
652     struct_data = type->category.struct_data;
653
654     xbt_assert1(struct_data.closed,
655                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
656                 type->name);
657     VERB1(">> Receive all fields of the structure %s",type->name);
658     xbt_dynar_foreach(struct_data.fields, cpt, field) {
659       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
660
661       sub_type = field->type;
662
663       gras_datadesc_recv_rec(sock,state,refs, sub_type,
664                              r_arch,NULL,0,
665                              field_data,-1, 
666                              detect_cycle || sub_type->cycle);
667        
668       if (field->recv)
669         field->recv(type,state,(void*)l_data);
670     
671     }
672     VERB1("<< Received all fields of the structure %s", type->name);
673     
674     break;
675   }
676
677   case e_gras_datadesc_type_cat_union: {
678     gras_dd_cat_union_t union_data;
679     gras_dd_cat_field_t field=NULL;
680     int                 field_num;
681
682     union_data = type->category.union_data;
683
684     xbt_assert1(union_data.closed,
685                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
686                 type->name);
687     /* retrieve the field number */
688     gras_dd_recv_int(sock, r_arch, &field_num);
689     if (field_num < 0)
690       THROW1(mismatch_error,0,
691              "Received union field for %s is negative", type->name);
692     if (field_num > xbt_dynar_length(union_data.fields)) 
693       THROW3(mismatch_error,0,
694              "Received union field for %s is said to be #%d but there is only %lu fields",
695              type->name, field_num, xbt_dynar_length(union_data.fields));
696     
697     /* Recv the content */
698     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
699     sub_type = field->type;
700     
701     gras_datadesc_recv_rec(sock,state,refs, sub_type,
702                            r_arch,NULL,0,
703                            l_data,-1,
704                            detect_cycle || sub_type->cycle);
705     if (field->recv)
706        field->recv(type,state,l_data);
707
708     break;
709   }
710
711   case e_gras_datadesc_type_cat_ref: {
712     char             **r_ref = NULL;
713     char             **l_ref = NULL;
714     gras_dd_cat_ref_t  ref_data;
715     int reference_is_to_recv = 0;
716     
717     ref_data = type->category.ref_data;
718
719     /* Get the referenced type locally or from peer */
720     sub_type = ref_data.type;
721     if (sub_type == NULL) {
722       int ref_code;
723       gras_dd_recv_int(sock, r_arch, &ref_code);
724       sub_type = gras_datadesc_by_id(ref_code);
725     }
726
727     /* Get the actual value of the pointer for cycle handling */
728     if (!pointer_type) {
729       pointer_type = gras_datadesc_by_name("data pointer");
730       xbt_assert(pointer_type);
731     }
732
733     r_ref = xbt_malloc(pointer_type->size[r_arch]);
734
735     gras_trp_recv(sock, (char*)r_ref,
736                   pointer_type->size[r_arch]);
737
738     /* Receive the pointed data only if not already sent */
739     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
740       VERB1("Not receiving data remotely referenced @%p since it's NULL",
741             *(void **)r_ref);
742       *(void**)l_data = NULL;
743       free(r_ref);
744       break;
745     }
746          
747     reference_is_to_recv = 0;
748     TRY {
749       if (detect_cycle)
750         l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
751       else 
752         reference_is_to_recv = 1;
753     } CATCH(e) {
754       if (e.category != not_found_error)
755         RETHROW;
756       reference_is_to_recv = 1;
757       xbt_ex_free(e);
758     }
759     if (reference_is_to_recv) {
760       int subsubcount = 0;
761       void *l_referenced=NULL;
762
763       VERB2("Receiving a ref to '%s', remotely @%p",
764             sub_type->name, *(void**)r_ref);
765       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
766         /* Damn. Reference to a dynamic array. Allocating the space for it 
767            is more complicated */
768         gras_dd_cat_array_t array_data = sub_type->category.array_data;
769         gras_datadesc_type_t subsub_type;
770
771         subsubcount = array_data.fixed_size;
772         if (subsubcount == 0)
773           gras_dd_recv_int(sock, r_arch, &subsubcount);
774
775         subsub_type = array_data.type;
776
777
778         gras_dd_alloc_ref(refs,
779                           subsub_type->size[GRAS_THISARCH] * subsubcount, 
780                           r_ref,pointer_type->size[r_arch], 
781                           (char**)&l_referenced,
782                           detect_cycle);
783       } else {
784         gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
785                           r_ref,pointer_type->size[r_arch], 
786                           (char**)&l_referenced,
787                           detect_cycle);
788       }
789
790       gras_datadesc_recv_rec(sock,state,refs, sub_type,
791                              r_arch,r_ref,pointer_type->size[r_arch],
792                              (char*)l_referenced, subsubcount,
793                              detect_cycle || sub_type->cycle);
794                                
795       *(void**)l_data=l_referenced;
796       VERB3("'%s' remotely referenced at %p locally at %p",
797             sub_type->name, *(void**)r_ref, l_referenced);
798       
799     } else {
800       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
801             *(void**)r_ref, *(void**)l_ref);
802
803       *(void**)l_data=*l_ref;
804
805     } 
806     free(r_ref);
807     break;
808   }
809
810   case e_gras_datadesc_type_cat_array: {
811     gras_dd_cat_array_t    array_data;
812     int       count;
813     char     *ptr;
814     long int  elm_size;
815
816     array_data = type->category.array_data;
817     /* determine element count locally, or from caller, or from peer */
818     count = array_data.fixed_size;
819     if (count == 0)
820       count = subsize;
821     if (count == 0)
822       gras_dd_recv_int(sock, r_arch, &count);
823     if (count == 0)
824       THROW1(mismatch_error,0,
825              "Invalid (=0) array size for type %s",type->name);
826
827     /* receive the content */
828     sub_type = array_data.type;
829     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
830       VERB1("Array of %d scalars, get it in one shoot", count);
831       if (sub_type->aligned_size[GRAS_THISARCH] >= 
832           sub_type->aligned_size[r_arch]) {
833         gras_trp_recv(sock, (char*)l_data, 
834                       sub_type->aligned_size[r_arch] * count);
835         if (r_arch != GRAS_THISARCH)
836           gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data);
837       } else {
838         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
839
840         gras_trp_recv(sock, (char*)ptr, 
841                       sub_type->size[r_arch] * count);
842         if (r_arch != GRAS_THISARCH)
843           gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data);
844         free(ptr);
845       }
846     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
847                sub_type->category.array_data.fixed_size > 0 &&
848                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
849       gras_datadesc_type_t subsub_type;
850       array_data = sub_type->category.array_data;
851       subsub_type = array_data.type;
852        
853       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
854       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
855           subsub_type->aligned_size[r_arch]) {
856         gras_trp_recv(sock, (char*)l_data, 
857                       subsub_type->aligned_size[r_arch] * count * 
858                       array_data.fixed_size);
859         if (r_arch != GRAS_THISARCH)
860           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data);
861       } else {
862         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
863
864         gras_trp_recv(sock, (char*)ptr, 
865                       subsub_type->size[r_arch] * count*array_data.fixed_size);
866         if (r_arch != GRAS_THISARCH)
867           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data);
868         free(ptr);
869       }
870       
871        
872     } else {
873       /* not scalar content, get it recursively (may contain pointers) */
874       elm_size = sub_type->aligned_size[GRAS_THISARCH];
875       VERB2("Receive a %d-long array of %s",count, sub_type->name);
876
877       ptr = l_data;
878       for (cpt=0; cpt<count; cpt++) {
879         gras_datadesc_recv_rec(sock,state,refs, sub_type,
880                                r_arch, NULL, 0, ptr,-1,
881                                detect_cycle || sub_type->cycle);
882                                    
883         ptr += elm_size;
884       }
885     }
886     break;
887   }
888         
889   default:
890     xbt_assert0(0, "Invalid type");
891   }
892   
893   if (type->recv)
894     type->recv(type,state,l_data);
895
896 }
897
898 /**
899  * gras_datadesc_recv:
900  *
901  * Get an instance of the datatype described by @type from the @socket, 
902  * and store a pointer to it in @dst
903  *
904  */
905 void
906 gras_datadesc_recv(gras_socket_t         sock, 
907                    gras_datadesc_type_t  type,
908                    int                   r_arch,
909                    void                 *dst) {
910
911   xbt_ex_t e;
912   gras_cbps_t  state; /* callback persistent state */
913   xbt_dict_t  refs;  /* all references already sent */
914
915   refs = xbt_dict_new();
916   state = gras_cbps_new();
917
918   xbt_assert0(type,"called with NULL type descriptor");
919   TRY {
920     gras_datadesc_recv_rec(sock, state, refs, type, 
921                            r_arch, NULL, 0,
922                            (char *) dst,-1, 
923                            type->cycle);
924   } CLEANUP {
925     xbt_dict_free(&refs);
926     gras_cbps_free(&state);
927   } CATCH(e) {
928     RETHROW;
929   }
930 }
931