Logo AND Algorithmique Numérique Distribuée

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