Logo AND Algorithmique Numérique Distribuée

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