Logo AND Algorithmique Numérique Distribuée

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