Logo AND Algorithmique Numérique Distribuée

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