Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
b9ceeeea5a1c4c23e0db3771cec0f83b3faf8eea
[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,1,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,1,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     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
458       VERB1("Array of %d scalars, send it in one shoot",count);
459       TRY(gras_trp_chunk_send(sock, data, 
460                               sub_type->aligned_size[GRAS_THISARCH] * count));
461     } else {
462       for (cpt=0; cpt<count; cpt++) {
463         TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, ptr));
464         ptr += elm_size;
465       }
466     }
467     break;
468   }
469
470   default:
471     gras_assert0(0, "Invalid type");
472   }
473
474   if (type->post) {
475     type->post(state,type,data);
476   }
477
478   return no_error;
479 }
480
481 /**
482  * gras_datadesc_send:
483  *
484  * Copy the data pointed by src and described by type to the socket
485  *
486  */
487 gras_error_t gras_datadesc_send(gras_socket_t *sock, 
488                                 gras_datadesc_type_t *type, 
489                                 void *src) {
490
491   gras_error_t errcode;
492   gras_dd_cbps_t *state = NULL;
493   gras_dict_t    *refs; /* all references already sent */
494  
495   TRY(gras_dict_new(&refs));
496   TRY(gras_dd_cbps_new(&state));
497
498   errcode = gras_datadesc_send_rec(sock,state,refs,type,(char*)src);
499
500   gras_dict_free(&refs);
501   gras_dd_cbps_free(&state);
502
503   return errcode;
504 }
505
506 /**
507  * gras_datadesc_recv_rec:
508  *
509  * Do the data reception job recursively.
510  *
511  * subsize used only to deal with vicious case of reference to dynamic array.
512  *  This size is needed at the reference reception level (to allocate enough 
513  * space) and at the array reception level (to fill enough room). 
514  * 
515  * Having this size passed as an argument of the recursive function is a crude
516  * hack, but I was told that working code is sometimes better than neat one ;)
517  */
518 gras_error_t
519 gras_datadesc_recv_rec(gras_socket_t        *sock, 
520                        gras_dd_cbps_t       *state,
521                        gras_dict_t          *refs,
522                        gras_datadesc_type_t *type,
523                        int                   r_arch,
524                        char                **r_data,
525                        long int              r_lgr,
526                        char                 *l_data,
527                        int                   subsize) {
528
529   gras_error_t          errcode;
530   int                   cpt;
531   gras_datadesc_type_t *sub_type;
532
533   VERB2("Recv a %s @%p", type->name, l_data);
534   gras_assert(l_data);
535
536   switch (type->category_code) {
537   case e_gras_datadesc_type_cat_scalar:
538     if (type->size[GRAS_THISARCH] >= type->size[r_arch]) {
539       TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
540       TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
541     } else {
542       void *ptr = NULL;
543       ptr = malloc((size_t)type->size[r_arch]);
544       TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
545       TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
546       free(ptr);
547     }
548     break;
549
550   case e_gras_datadesc_type_cat_struct: {
551     gras_dd_cat_struct_t   struct_data;
552     gras_dd_cat_field_t   *field;
553
554     struct_data = type->category.struct_data;
555
556     VERB1(">> Receive all fields of the structure %s",type->name);
557     gras_dynar_foreach(struct_data.fields, cpt, field) {
558       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
559
560       TRY(gras_datadesc_by_id(field->code, &sub_type));
561
562       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
563                                  r_arch,NULL,0,
564                                  field_data,-1));
565     }
566     VERB1("<< Received all fields of the structure %s", type->name);
567     
568     break;
569   }
570
571   case e_gras_datadesc_type_cat_union: {
572     gras_dd_cat_union_t    union_data;
573     gras_dd_cat_field_t   *field;
574     int                    field_num;
575
576     union_data = type->category.union_data;
577
578     /* retrieve the field number */
579     TRY(gras_dd_recv_int(sock, r_arch, &field_num));
580     if (field_num < 0)
581       RAISE1(mismatch_error,
582              "Received union field for %s is negative", type->name);
583     if (field_num < gras_dynar_length(union_data.fields)) 
584       RAISE3(mismatch_error,
585              "Received union field for %s is %d but there is only %d fields", 
586              type->name, field_num, gras_dynar_length(union_data.fields));
587     
588     /* Recv the content */
589     gras_dynar_get(union_data.fields, field_num, field);
590     TRY(gras_datadesc_by_id(field->code, &sub_type));
591     
592     TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
593                                r_arch,NULL,0,
594                                l_data,-1));
595     break;
596   }
597
598   case e_gras_datadesc_type_cat_ref: {
599     char             **r_ref = NULL;
600     char             **l_ref = NULL;
601     gras_dd_cat_ref_t  ref_data;
602     int                ref_code;
603     
604     ref_data = type->category.ref_data;
605
606     /* Get the referenced type locally or from peer */
607     ref_code = ref_data.code;
608     if (ref_code < 0) 
609       TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
610
611     /* Get the actual value of the pointer for cycle handling */
612     if (!pointer_type) {
613       pointer_type = gras_datadesc_by_name("data pointer");
614       gras_assert(pointer_type);
615     }
616
617     if (! (r_ref = malloc((size_t)pointer_type->size[r_arch])) )
618       RAISE_MALLOC;
619     TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
620                             pointer_type->size[r_arch]));
621
622     /* Receive the pointed data only if not already sent */
623     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
624       VERB1("Not receiving data remotely referenced @%p since it's NULL",
625             *(void **)r_ref);
626       *(void**)l_data = NULL;
627       free(r_ref);
628       break;
629     }
630     errcode = gras_dict_get_ext(refs,
631                                 (char*)r_ref, pointer_type->size[r_arch],
632                                 (void**)&l_ref);
633
634
635     if (errcode == mismatch_error) {
636       int subsubcount = -1;
637       void *l_referenced=NULL;
638
639       TRY(gras_datadesc_by_id(ref_code, &sub_type));
640       
641       VERB2("Receiving a ref to '%s', remotely @%p",
642             sub_type->name, *(void**)r_ref);
643       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
644         /* Damn. Reference to a dynamic array. Allocating the size for it 
645            is more complicated */
646         gras_dd_cat_array_t array_data = sub_type->category.array_data;
647         gras_datadesc_type_t *subsub_type;
648
649         subsubcount = array_data.fixed_size;
650         if (subsubcount < 0)
651           TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
652
653         TRY(gras_datadesc_by_id(array_data.code, &subsub_type));
654
655
656         TRY(gras_dd_alloc_ref(refs,
657                               subsub_type->size[GRAS_THISARCH] * subsubcount, 
658                               r_ref,pointer_type->size[r_arch], 
659                               (char**)&l_referenced));
660       } else {
661         TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
662                               r_ref,pointer_type->size[r_arch], 
663                               (char**)&l_referenced));
664       }
665
666       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
667                                  r_arch,r_ref,pointer_type->size[r_arch],
668                                  (char*)l_referenced, subsubcount));
669       *(void**)l_data=l_referenced;
670       VERB3("'%s' remotely referenced at %p locally at %p",
671             sub_type->name, *(void**)r_ref, l_referenced);
672       
673     } else if (errcode == no_error) {
674       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
675             *(void**)r_ref, *(void**)l_ref);
676
677       *(void**)l_data=*l_ref;
678
679     } else {
680       return errcode;
681     }
682     free(r_ref);
683     break;
684   }
685
686   case e_gras_datadesc_type_cat_array: {
687     gras_dd_cat_array_t    array_data;
688     int       count;
689     char     *ptr;
690     long int  elm_size;
691
692     array_data = type->category.array_data;
693     /* determine element count locally, or from caller, or from peer */
694     count = array_data.fixed_size;
695     if (count <= 0)
696       count = subsize;
697     if (count < 0)
698       TRY(gras_dd_recv_int(sock, r_arch, &count));
699     if (count < 0)
700       RAISE1(mismatch_error,
701              "Invalid (negative) array size for type %s",type->name);
702
703     /* receive the content */
704     TRY(gras_datadesc_by_id(array_data.code, &sub_type));
705     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
706       VERB1("Array of %d scalars, get it in one shoot", count);
707       if (sub_type->aligned_size[GRAS_THISARCH] >= 
708           sub_type->aligned_size[r_arch]) {
709         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
710                                 sub_type->aligned_size[r_arch] * count));
711         TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
712       } else {
713         ptr = malloc((size_t)sub_type->aligned_size[r_arch] * count);
714         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
715                                 sub_type->size[r_arch] * count));
716         TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
717         free(ptr);
718       }
719     } else {
720       /* not scalar content, get it recursively (may contain pointers) */
721       elm_size = sub_type->aligned_size[GRAS_THISARCH];
722       VERB2("Receive a %d-long array of %s",count, sub_type->name);
723
724       ptr = l_data;
725       for (cpt=0; cpt<count; cpt++) {
726         TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
727                                    r_arch, NULL, 0, ptr,-1));
728         ptr += elm_size;
729       }
730     }
731     break;
732   }
733         
734   default:
735     gras_assert0(0, "Invalid type");
736   }
737   
738   return no_error;
739 }
740
741 /**
742  * gras_datadesc_recv:
743  *
744  * Get an instance of the datatype described by @type from the @socket, 
745  * and store a pointer to it in @dst
746  *
747  */
748 gras_error_t
749 gras_datadesc_recv(gras_socket_t *sock, 
750                    gras_datadesc_type_t *type, 
751                    int r_arch,
752                    void *dst) {
753
754   gras_error_t errcode;
755   gras_dd_cbps_t *state = NULL; /* callback persistent state */
756   gras_dict_t    *refs;         /* all references already sent */
757
758   TRY(gras_dict_new(&refs));
759   TRY(gras_dd_cbps_new(&state));
760
761   errcode = gras_datadesc_recv_rec(sock, state, refs, type, 
762                                    r_arch, NULL, 0,
763                                    (char *) dst,-1);
764
765   gras_dict_free(&refs);
766   gras_dd_cbps_free(&state);
767
768   return errcode;
769 }