Logo AND Algorithmique Numérique Distribuée

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