Logo AND Algorithmique Numérique Distribuée

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