Logo AND Algorithmique Numérique Distribuée

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