Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
f132161fed8b8c3ec61d7f08652d92337f262091
[simgrid.git] / src / gras / DataDesc / ddt_exchange.c
1 /* $Id$ */
2
3 /* ddt_exchange - send/recv data described                                  */
4
5 /* Authors: Olivier Aumage, Martin Quinson                                  */
6 /* Copyright (C) 2003, 2004 the GRAS posse.                                 */
7
8 /* This program is free software; you can redistribute it and/or modify it
9    under the terms of the license (GNU LGPL) which comes with this package. */
10
11 #include "gras/DataDesc/datadesc_private.h"
12 #include "gras/Transport/transport_interface.h" /* gras_trp_chunk_send/recv */
13
14 GRAS_LOG_NEW_DEFAULT_SUBCATEGORY(ddt_exchange,datadesc,
15                                  "Sending data over the network");
16 const char *gras_datadesc_cat_names[9] = { 
17   "undefined", 
18   "scalar", "struct", "union", "ref", "array", "ignored",
19   "invalid"};
20
21 static gras_datadesc_type_t *int_type = NULL;
22 static gras_datadesc_type_t *pointer_type = NULL;    
23 static _GRAS_INLINE gras_error_t gras_dd_send_int(gras_socket_t *sock,             int  i);
24 static _GRAS_INLINE gras_error_t gras_dd_recv_int(gras_socket_t *sock, int r_arch, int *i);
25
26 static _GRAS_INLINE gras_error_t
27 gras_dd_alloc_ref(gras_dict_t *refs,  long int     size,
28                   char       **r_ref, long int     r_len,
29                   char       **l_ref, int detect_cycle);
30
31 static _GRAS_INLINE int
32 gras_dd_is_r_null(char **r_ptr, long int length);
33
34 static gras_error_t 
35 gras_datadesc_send_rec(gras_socket_t        *sock,
36                        gras_cbps_t       *state,
37                        gras_dict_t          *refs,
38                        gras_datadesc_type_t *type, 
39                        char                 *data, 
40                        int                   detect_cycle);
41 static gras_error_t
42 gras_datadesc_recv_rec(gras_socket_t        *sock, 
43                        gras_cbps_t       *state,
44                        gras_dict_t          *refs,
45                        gras_datadesc_type_t *type,
46                        int                   r_arch,
47                        char                **r_data,
48                        long int              r_lgr,
49                        char                 *dst,
50                        int                   subsize, 
51                        int                   detect_cycle);
52
53
54 static _GRAS_INLINE gras_error_t
55 gras_dd_send_int(gras_socket_t *sock,int i) {
56
57   if (!int_type) {
58     int_type = gras_datadesc_by_name("int");
59      gras_assert(int_type);  
60   }
61    
62   DEBUG1("send_int(%d)",i);
63   return gras_trp_chunk_send(sock, (char*)&i, int_type->size[GRAS_THISARCH]);
64 }
65
66 static _GRAS_INLINE gras_error_t
67 gras_dd_recv_int(gras_socket_t *sock, int r_arch, int *i) {
68   gras_error_t errcode;
69
70   if (!int_type) {
71      int_type = gras_datadesc_by_name("int");
72      gras_assert(int_type);
73   }
74
75   if (int_type->size[GRAS_THISARCH] >= int_type->size[r_arch]) {
76     TRY(gras_trp_chunk_recv(sock, (char*)i, int_type->size[r_arch]));
77     if (r_arch != GRAS_THISARCH)
78       TRY(gras_dd_convert_elm(int_type,1,r_arch, i,i));
79   } else {
80     void *ptr = gras_malloc(int_type->size[r_arch]);
81
82     TRY(gras_trp_chunk_recv(sock, (char*)ptr, int_type->size[r_arch]));
83     if (r_arch != GRAS_THISARCH)
84       TRY(gras_dd_convert_elm(int_type,1,r_arch, ptr,i));
85     gras_free(ptr);
86   }
87   DEBUG1("recv_int(%d)",*i);
88
89   return no_error;
90 }
91
92 /*
93  * Note: here we suppose that the remote NULL is a sequence 
94  *       of 'length' bytes set to 0.
95  * FIXME: Check in configure?
96  */
97 static _GRAS_INLINE int 
98 gras_dd_is_r_null(char **r_ptr, long int length) {
99   int i;
100
101   for (i=0; i<length; i++) {
102     if ( ((unsigned char*)r_ptr) [i]) {
103       return 0;
104     }
105   }
106
107   return 1;
108 }
109
110 static _GRAS_INLINE gras_error_t
111 gras_dd_alloc_ref(gras_dict_t *refs,
112                   long int     size,
113                   char       **r_ref,
114                   long int     r_len, /* pointer_type->size[r_arch] */
115                   char       **l_ref,
116                   int          detect_cycle) {
117   char *l_data = NULL;
118
119   gras_assert1(size>0,"Cannot allocate %ld bytes!", size);
120   l_data = gras_malloc((size_t)size);
121
122   *l_ref = l_data;
123   DEBUG2("l_data=%p, &l_data=%p",(void*)l_data,(void*)&l_data);
124
125   DEBUG3("alloc_ref: r_ref=%p; *r_ref=%p, r_len=%ld",
126          (void*)r_ref, (void*)(r_ref?*r_ref:NULL), r_len);
127   if (detect_cycle && r_ref && !gras_dd_is_r_null( r_ref, r_len)) {
128     gras_error_t errcode;
129     void *ptr = gras_malloc(sizeof(void *));
130
131     memcpy(ptr,l_ref, sizeof(void *));
132
133     DEBUG2("Insert %p under %p",*(void**)ptr, *(void**)r_ref);
134
135     if (detect_cycle)
136        gras_dict_set_ext(refs,(const char *) r_ref, r_len, ptr, gras_free);
137   }
138   return no_error;
139 }
140
141 /**
142  * gras_datadesc_type_cmp:
143  *
144  * Compares two datadesc types with the same semantic than strcmp.
145  *
146  * This comparison does not take the set headers into account (name and ID), 
147  * but only the payload (actual type description).
148  */
149 int gras_datadesc_type_cmp(const gras_datadesc_type_t *d1,
150                            const gras_datadesc_type_t *d2) {
151   int ret,cpt;
152   gras_dd_cat_field_t *field1,*field2;
153   gras_datadesc_type_t *field_desc_1,*field_desc_2;
154
155   if (d1 == d2) return 0; /* easy optimization */
156
157   if (!d1 && d2) {
158     DEBUG0("ddt_cmp: !d1 && d2 => 1");
159     return 1;
160   }
161   if (!d1 && !d2) {
162     DEBUG0("ddt_cmp: !d1 && !d2 => 0");
163     return 0;
164   }
165   if ( d1 && !d2) {
166     DEBUG0("ddt_cmp: d1 && !d2 => -1");
167     return -1;
168   }
169
170   for (cpt=0; cpt<gras_arch_count; cpt++) {
171     if (d1->size[cpt] != d2->size[cpt]) {
172       DEBUG5("ddt_cmp: %s->size=%ld  !=  %s->size=%ld (on %s)",
173              d1->name,d1->size[cpt],d2->name,d2->size[cpt],
174              gras_arches[cpt].name);
175       return d1->size[cpt] >  d2->size[cpt] ? 1 : -1;
176     }
177
178     if (d1->alignment[cpt] != d2->alignment[cpt]) {
179       DEBUG5("ddt_cmp: %s->alignment=%ld  !=  %s->alignment=%ld (on %s)",
180              d1->name,d1->alignment[cpt],d2->name,d2->alignment[cpt],
181              gras_arches[cpt].name);
182       return d1->alignment[cpt] > d2->alignment[cpt] ? 1 : -1;
183     }
184
185     if (d1->aligned_size[cpt] != d2->aligned_size[cpt]) {
186       DEBUG5("ddt_cmp: %s->aligned_size=%ld  !=  %s->aligned_size=%ld (on %s)",
187              d1->name,d1->aligned_size[cpt],d2->name,d2->aligned_size[cpt],
188              gras_arches[cpt].name);
189       return d1->aligned_size[cpt] > d2->aligned_size[cpt] ? 1 : -1;
190     }
191   }
192
193   if (d1->category_code != d2->category_code) {
194     DEBUG4("ddt_cmp: %s->cat=%s  !=  %s->cat=%s",
195            d1->name,gras_datadesc_cat_names[d1->category_code],
196            d2->name,gras_datadesc_cat_names[d2->category_code]);
197     return d1->category_code > d2->category_code ? 1 : -1;
198   }
199
200   if (d1->send != d2->send) {
201     DEBUG4("ddt_cmp: %s->send=%p  !=  %s->send=%p",
202            d1->name,(void*)d1->send, d2->name,(void*)d2->send);
203     return 1; /* ISO C forbids ordered comparisons of pointers to functions */
204   }
205
206   if (d1->recv != d2->recv) {
207     DEBUG4("ddt_cmp: %s->recv=%p  !=  %s->recv=%p",
208            d1->name,(void*)d1->recv, d2->name,(void*)d2->recv);
209     return 1; /* ISO C forbids ordered comparisons of pointers to functions */
210   }
211
212   switch (d1->category_code) {
213   case e_gras_datadesc_type_cat_scalar:
214     if (d1->category.scalar_data.encoding != d2->category.scalar_data.encoding)
215       return d1->category.scalar_data.encoding > d2->category.scalar_data.encoding ? 1 : -1 ;
216     break;
217     
218   case e_gras_datadesc_type_cat_struct:    
219     if (gras_dynar_length(d1->category.struct_data.fields) != 
220         gras_dynar_length(d2->category.struct_data.fields)) {
221       DEBUG4("ddt_cmp: %s (having %lu fields) !=  %s (having %lu fields)",
222              d1->name, gras_dynar_length(d1->category.struct_data.fields),
223              d2->name, gras_dynar_length(d2->category.struct_data.fields));
224       
225       return gras_dynar_length(d1->category.struct_data.fields) >
226         gras_dynar_length(d2->category.struct_data.fields) ?
227         1 : -1;
228     }
229     gras_dynar_foreach(d1->category.struct_data.fields, cpt, field1) {
230       
231       field2 = gras_dynar_get_as(d2->category.struct_data.fields, cpt, gras_dd_cat_field_t *);
232       field_desc_1 = field1->type;
233       field_desc_2 = field2->type;
234       ret = gras_datadesc_type_cmp(field_desc_1,field_desc_2);
235       if (ret) {
236         DEBUG6("%s->field[%d]=%s != %s->field[%d]=%s",
237                d1->name,cpt,field1->name,              
238                d2->name,cpt,field2->name);
239         return ret;
240       }
241       
242     }
243     break;
244     
245   case e_gras_datadesc_type_cat_union:
246     if (d1->category.union_data.selector != d2->category.union_data.selector) 
247       return 1;  /* ISO C forbids ordered comparisons of pointers to functions */
248     
249     if (gras_dynar_length(d1->category.union_data.fields) != 
250         gras_dynar_length(d2->category.union_data.fields))
251       return gras_dynar_length(d1->category.union_data.fields) >
252              gras_dynar_length(d2->category.union_data.fields) ?
253         1 : -1;
254     
255     gras_dynar_foreach(d1->category.union_data.fields, cpt, field1) {
256       
257       field2 = gras_dynar_get_as(d2->category.union_data.fields, cpt, gras_dd_cat_field_t *);
258       field_desc_1 = field1->type;
259       field_desc_2 = field2->type;
260       ret = gras_datadesc_type_cmp(field_desc_1,field_desc_2);
261       if (ret)
262         return ret;
263       
264     }
265     break;
266     
267     
268   case e_gras_datadesc_type_cat_ref:
269     if (d1->category.ref_data.selector != d2->category.ref_data.selector) 
270       return 1; /* ISO C forbids ordered comparisons of pointers to functions */
271     
272     if (d1->category.ref_data.type != d2->category.ref_data.type) 
273       return d1->category.ref_data.type > d2->category.ref_data.type ? 1 : -1;
274     break;
275     
276   case e_gras_datadesc_type_cat_array:
277     if (d1->category.array_data.type != d2->category.array_data.type) 
278       return d1->category.array_data.type > d2->category.array_data.type ? 1 : -1;
279     
280     if (d1->category.array_data.fixed_size != d2->category.array_data.fixed_size) 
281       return d1->category.array_data.fixed_size > d2->category.array_data.fixed_size ? 1 : -1;
282     
283     if (d1->category.array_data.dynamic_size != d2->category.array_data.dynamic_size) 
284       return 1; /* ISO C forbids ordered comparisons of pointers to functions */
285     
286     break;
287     
288   case e_gras_datadesc_type_cat_ignored:
289     /* That's ignored... */
290   default:
291     /* two stupidly created ddt are equally stupid ;) */
292     break;
293   }
294   return 0;
295   
296 }
297
298 /**
299  * gras_datadesc_cpy:
300  *
301  * Copy the data pointed by src and described by type 
302  * to a new location, and store a pointer to it in dst.
303  *
304  */
305 gras_error_t gras_datadesc_cpy(gras_datadesc_type_t *type, 
306                                void *src, 
307                                void **dst) {
308   RAISE_UNIMPLEMENTED;
309 }
310
311 static gras_error_t 
312 gras_datadesc_send_rec(gras_socket_t        *sock,
313                        gras_cbps_t       *state,
314                        gras_dict_t          *refs,
315                        gras_datadesc_type_t *type, 
316                        char                 *data,
317                        int                   detect_cycle) {
318
319   gras_error_t          errcode;
320   int                   cpt;
321   gras_datadesc_type_t *sub_type; /* type on which we recurse */
322   
323   VERB2("Send a %s (%s)", 
324         type->name, gras_datadesc_cat_names[type->category_code]);
325
326   if (type->send) {
327     type->send(state,data);
328   }
329
330   switch (type->category_code) {
331   case e_gras_datadesc_type_cat_scalar:
332     TRY(gras_trp_chunk_send(sock, data, type->size[GRAS_THISARCH]));
333     break;
334
335   case e_gras_datadesc_type_cat_struct: {
336     gras_dd_cat_struct_t  struct_data;
337     gras_dd_cat_field_t  *field;
338     char                 *field_data;
339     
340     struct_data = type->category.struct_data;
341     gras_assert1(struct_data.closed,
342       "Please call gras_datadesc_declare_struct_close on %s before sending it",
343                 type->name);
344     VERB1(">> Send all fields of the structure %s",type->name);
345     gras_dynar_foreach(struct_data.fields, cpt, field) {
346       field_data = data;
347       field_data += field->offset[GRAS_THISARCH];
348       
349       sub_type = field->type;
350       
351       if (field->pre)
352         field->pre(state,field_data);
353       
354       VERB1("Send field %s",field->name);
355       TRY(gras_datadesc_send_rec(sock,state,refs,sub_type, field_data, detect_cycle || sub_type->cycle));
356       
357       if (field->post)
358         field->post(state,field_data);
359     }
360     VERB1("<< Sent all fields of the structure %s", type->name);
361     
362     break;
363   }
364
365   case e_gras_datadesc_type_cat_union: {
366     gras_dd_cat_union_t    union_data;
367     gras_dd_cat_field_t   *field=NULL;
368     int                    field_num;
369     
370     union_data = type->category.union_data;
371     
372     gras_assert1(union_data.closed,
373                 "Please call gras_datadesc_declare_union_close on %s before sending it",
374                 type->name);
375     /* retrieve the field number */
376     field_num = union_data.selector(state, data);
377     
378     gras_assert1(field_num > 0,
379                  "union field selector of %s gave a negative value", 
380                  type->name);
381     
382     gras_assert3(field_num < gras_dynar_length(union_data.fields),
383          "union field selector of %s returned %d but there is only %lu fields",
384                  type->name, field_num, gras_dynar_length(union_data.fields));
385
386     /* Send the field number */
387     TRY(gras_dd_send_int(sock, field_num));
388     
389     /* Send the content */
390     field = gras_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t *);
391     sub_type = field->type;
392     
393     if (field->pre)
394       field->pre(state,data);
395     
396     TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, data, detect_cycle || sub_type->cycle));
397       
398     if (field->post)
399       field->post(state,data);
400     
401     break;
402   }
403     
404   case e_gras_datadesc_type_cat_ref: {
405     gras_dd_cat_ref_t      ref_data;
406
407     void                 **ref=(void**)data;
408     void *dummy;
409     
410     ref_data = type->category.ref_data;
411     
412     /* Detect the referenced type and send it to peer if needed */
413     sub_type = ref_data.type;
414     if (sub_type == NULL) {
415       sub_type = (*ref_data.selector)(state,data);
416       TRY(gras_dd_send_int(sock, sub_type->code));
417     }
418     
419     /* Send the actual value of the pointer for cycle handling */
420     if (!pointer_type) {
421       pointer_type = gras_datadesc_by_name("data pointer");
422       gras_assert(pointer_type);
423     }
424      
425     TRY(gras_trp_chunk_send(sock, (char*)data,
426                             pointer_type->size[GRAS_THISARCH]));
427     
428     /* Send the pointed data only if not already sent */
429     if (*(void**)data == NULL) {
430       VERB0("Not sending NULL referenced data");
431       break;
432     }
433     errcode = detect_cycle 
434             ? gras_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy)
435             : mismatch_error;
436     if (errcode == mismatch_error) {
437        VERB1("Sending data referenced at %p", (void*)*ref);
438        if (detect_cycle)
439          gras_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
440        TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, *ref, detect_cycle || sub_type->cycle));
441           
442     } else if (errcode == no_error) {
443        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
444     } else {
445        return errcode;
446     }
447     
448     break;
449   }
450
451   case e_gras_datadesc_type_cat_array: {
452     gras_dd_cat_array_t    array_data;
453     long int               count;
454     char                  *ptr=data;
455     long int               elm_size;
456     
457     array_data = type->category.array_data;
458     
459     /* determine and send the element count */
460     count = array_data.fixed_size;
461     if (count == 0) {
462       count = array_data.dynamic_size(state,data);
463       gras_assert1(count >=0,
464                    "Invalid (negative) array size for type %s",type->name);
465       TRY(gras_dd_send_int(sock, count));
466     }
467     
468     /* send the content */
469     sub_type = array_data.type;
470     elm_size = sub_type->aligned_size[GRAS_THISARCH];
471     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
472       VERB1("Array of %ld scalars, send it in one shot",count);
473       TRY(gras_trp_chunk_send(sock, data, 
474                               sub_type->aligned_size[GRAS_THISARCH] * count));
475     } else {
476       for (cpt=0; cpt<count; cpt++) {
477         TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, ptr, detect_cycle || sub_type->cycle));
478         ptr += elm_size;
479       }
480     }
481     break;
482   }
483
484   default:
485     gras_assert0(0, "Invalid type");
486   }
487
488   return no_error;
489 }
490
491 /**
492  * gras_datadesc_send:
493  *
494  * Copy the data pointed by src and described by type to the socket
495  *
496  */
497 gras_error_t gras_datadesc_send(gras_socket_t *sock, 
498                                 gras_datadesc_type_t *type, 
499                                 void *src) {
500
501   gras_error_t errcode;
502   gras_cbps_t *state = NULL;
503   gras_dict_t    *refs; /* all references already sent */
504  
505   refs = gras_dict_new();
506   state = gras_cbps_new();
507
508   errcode = gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
509
510   gras_dict_free(&refs);
511   gras_cbps_free(&state);
512
513   return errcode;
514 }
515
516 /**
517  * gras_datadesc_recv_rec:
518  *
519  * Do the data reception job recursively.
520  *
521  * subsize used only to deal with vicious case of reference to dynamic array.
522  *  This size is needed at the reference reception level (to allocate enough 
523  * space) and at the array reception level (to fill enough room). 
524  * 
525  * Having this size passed as an argument of the recursive function is a crude
526  * hack, but I was told that working code is sometimes better than neat one ;)
527  */
528 gras_error_t
529 gras_datadesc_recv_rec(gras_socket_t        *sock, 
530                        gras_cbps_t          *state,
531                        gras_dict_t          *refs,
532                        gras_datadesc_type_t *type,
533                        int                   r_arch,
534                        char                **r_data,
535                        long int              r_lgr,
536                        char                 *l_data,
537                        int                   subsize,
538                        int                   detect_cycle) {
539
540   gras_error_t          errcode;
541   int                   cpt;
542   gras_datadesc_type_t *sub_type;
543
544   VERB2("Recv a %s @%p", type->name, (void*)l_data);
545   gras_assert(l_data);
546
547   switch (type->category_code) {
548   case e_gras_datadesc_type_cat_scalar:
549     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
550       TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
551       if (r_arch != GRAS_THISARCH)
552         TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
553     } else {
554       void *ptr = gras_malloc(type->size[r_arch]);
555
556       TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
557       if (r_arch != GRAS_THISARCH)
558         TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
559       gras_free(ptr);
560     }
561     break;
562
563   case e_gras_datadesc_type_cat_struct: {
564     gras_dd_cat_struct_t   struct_data;
565     gras_dd_cat_field_t   *field;
566
567     struct_data = type->category.struct_data;
568
569     gras_assert1(struct_data.closed,
570                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
571                 type->name);
572     VERB1(">> Receive all fields of the structure %s",type->name);
573     gras_dynar_foreach(struct_data.fields, cpt, field) {
574       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
575
576       sub_type = field->type;
577
578       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
579                                  r_arch,NULL,0,
580                                  field_data,-1, 
581                                  detect_cycle || sub_type->cycle));
582     }
583     VERB1("<< Received all fields of the structure %s", type->name);
584     
585     break;
586   }
587
588   case e_gras_datadesc_type_cat_union: {
589     gras_dd_cat_union_t    union_data;
590     gras_dd_cat_field_t   *field=NULL;
591     int                    field_num;
592
593     union_data = type->category.union_data;
594
595     gras_assert1(union_data.closed,
596                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
597                 type->name);
598     /* retrieve the field number */
599     TRY(gras_dd_recv_int(sock, r_arch, &field_num));
600     if (field_num < 0)
601       RAISE1(mismatch_error,
602              "Received union field for %s is negative", type->name);
603     if (field_num < gras_dynar_length(union_data.fields)) 
604       RAISE3(mismatch_error,
605              "Received union field for %s is %d but there is only %lu fields",
606              type->name, field_num, gras_dynar_length(union_data.fields));
607     
608     /* Recv the content */
609     field = gras_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t *);
610     sub_type = field->type;
611     
612     TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
613                                r_arch,NULL,0,
614                                l_data,-1, 
615                                detect_cycle || sub_type->cycle));
616     break;
617   }
618
619   case e_gras_datadesc_type_cat_ref: {
620     char             **r_ref = NULL;
621     char             **l_ref = NULL;
622     gras_dd_cat_ref_t  ref_data;
623     
624     ref_data = type->category.ref_data;
625
626     /* Get the referenced type locally or from peer */
627     sub_type = ref_data.type;
628     if (sub_type == NULL) {
629       int ref_code;
630       TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
631       TRY(gras_datadesc_by_id(ref_code, &sub_type));
632     }
633
634     /* Get the actual value of the pointer for cycle handling */
635     if (!pointer_type) {
636       pointer_type = gras_datadesc_by_name("data pointer");
637       gras_assert(pointer_type);
638     }
639
640     r_ref = gras_malloc(pointer_type->size[r_arch]);
641
642     TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
643                             pointer_type->size[r_arch]));
644
645     /* Receive the pointed data only if not already sent */
646     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
647       VERB1("Not receiving data remotely referenced @%p since it's NULL",
648             *(void **)r_ref);
649       *(void**)l_data = NULL;
650       gras_free(r_ref);
651       break;
652     }
653          
654     errcode = detect_cycle
655             ? gras_dict_get_ext(refs,
656                                 (char*)r_ref, pointer_type->size[r_arch],
657                                 (void**)&l_ref)
658             : mismatch_error;
659
660     if (errcode == mismatch_error) {
661       int subsubcount = 0;
662       void *l_referenced=NULL;
663
664       VERB2("Receiving a ref to '%s', remotely @%p",
665             sub_type->name, *(void**)r_ref);
666       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
667         /* Damn. Reference to a dynamic array. Allocating the size for it 
668            is more complicated */
669         gras_dd_cat_array_t array_data = sub_type->category.array_data;
670         gras_datadesc_type_t *subsub_type;
671
672         subsubcount = array_data.fixed_size;
673         if (subsubcount == 0)
674           TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
675
676         subsub_type = array_data.type;
677
678
679         TRY(gras_dd_alloc_ref(refs,
680                               subsub_type->size[GRAS_THISARCH] * subsubcount, 
681                               r_ref,pointer_type->size[r_arch], 
682                               (char**)&l_referenced,
683                               detect_cycle));
684       } else {
685         TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
686                               r_ref,pointer_type->size[r_arch], 
687                               (char**)&l_referenced,
688                               detect_cycle));
689       }
690
691       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
692                                  r_arch,r_ref,pointer_type->size[r_arch],
693                                  (char*)l_referenced, subsubcount, 
694                                  detect_cycle || sub_type->cycle));
695       *(void**)l_data=l_referenced;
696       VERB3("'%s' remotely referenced at %p locally at %p",
697             sub_type->name, *(void**)r_ref, l_referenced);
698       
699     } else if (errcode == no_error) {
700       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
701             *(void**)r_ref, *(void**)l_ref);
702
703       *(void**)l_data=*l_ref;
704
705     } else {
706       return errcode;
707     }
708     gras_free(r_ref);
709     break;
710   }
711
712   case e_gras_datadesc_type_cat_array: {
713     gras_dd_cat_array_t    array_data;
714     int       count;
715     char     *ptr;
716     long int  elm_size;
717
718     array_data = type->category.array_data;
719     /* determine element count locally, or from caller, or from peer */
720     count = array_data.fixed_size;
721     if (count == 0)
722       count = subsize;
723     if (count == 0)
724       TRY(gras_dd_recv_int(sock, r_arch, &count));
725     if (count == 0)
726       RAISE1(mismatch_error,
727              "Invalid (=0) array size for type %s",type->name);
728
729     /* receive the content */
730     sub_type = array_data.type;
731     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
732       VERB1("Array of %d scalars, get it in one shoot", count);
733       if (sub_type->aligned_size[GRAS_THISARCH] >= 
734           sub_type->aligned_size[r_arch]) {
735         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
736                                 sub_type->aligned_size[r_arch] * count));
737         if (r_arch != GRAS_THISARCH)
738           TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
739       } else {
740         ptr = gras_malloc(sub_type->aligned_size[r_arch] * count);
741
742         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
743                                 sub_type->size[r_arch] * count));
744         if (r_arch != GRAS_THISARCH)
745           TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
746         gras_free(ptr);
747       }
748     } else {
749       /* not scalar content, get it recursively (may contain pointers) */
750       elm_size = sub_type->aligned_size[GRAS_THISARCH];
751       VERB2("Receive a %d-long array of %s",count, sub_type->name);
752
753       ptr = l_data;
754       for (cpt=0; cpt<count; cpt++) {
755         TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
756                                    r_arch, NULL, 0, ptr,-1,
757                                    detect_cycle || sub_type->cycle));
758         ptr += elm_size;
759       }
760     }
761     break;
762   }
763         
764   default:
765     gras_assert0(0, "Invalid type");
766   }
767   
768   if (type->recv)
769     type->recv(state,l_data);
770
771   return no_error;
772 }
773
774 /**
775  * gras_datadesc_recv:
776  *
777  * Get an instance of the datatype described by @type from the @socket, 
778  * and store a pointer to it in @dst
779  *
780  */
781 gras_error_t
782 gras_datadesc_recv(gras_socket_t *sock, 
783                    gras_datadesc_type_t *type, 
784                    int r_arch,
785                    void *dst) {
786
787   gras_error_t errcode;
788   gras_cbps_t *state = NULL; /* callback persistent state */
789   gras_dict_t    *refs;         /* all references already sent */
790
791   refs = gras_dict_new();
792   state = gras_cbps_new();
793
794   errcode = gras_datadesc_recv_rec(sock, state, refs, type, 
795                                    r_arch, NULL, 0,
796                                    (char *) dst,-1, 
797                                    type->cycle);
798
799   gras_dict_free(&refs);
800   gras_cbps_free(&state);
801
802   return errcode;
803 }