Logo AND Algorithmique Numérique Distribuée

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