Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Better choice of what is debug and what is verbose
[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   gras_cbps_t  state;
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   state = gras_cbps_new();
380   
381   TRY {
382     size = gras_datadesc_copy_rec(state,refs,type,(char*)src,(char*)dst,0, 
383                                   type->cycle);
384   } CLEANUP {
385     xbt_dict_free(&refs);
386     gras_cbps_free(&state);
387   } CATCH(e) {
388     RETHROW;
389   }
390   return size;
391 }
392
393 /***
394  *** Direct use functions
395  ***/
396
397 static void
398 gras_datadesc_send_rec(gras_socket_t         sock,
399                        gras_cbps_t           state,
400                        xbt_dict_t            refs,
401                        gras_datadesc_type_t  type, 
402                        char                 *data,
403                        int                   detect_cycle) {
404
405   xbt_ex_t             e;
406   int                  cpt;
407   gras_datadesc_type_t sub_type; /* type on which we recurse */
408   
409   VERB2("Send a %s (%s)", 
410         type->name, gras_datadesc_cat_names[type->category_code]);
411
412   if (!strcmp(type->name,"string"))
413     VERB1("value: '%s'",*(char**)data);
414
415   if (type->send) {
416     type->send(type,state,data);
417     DEBUG0("Run the emission callback");
418   }
419
420   switch (type->category_code) {
421   case e_gras_datadesc_type_cat_scalar:
422     gras_trp_send(sock, data, type->size[GRAS_THISARCH], 1);
423     break;
424
425   case e_gras_datadesc_type_cat_struct: {
426     gras_dd_cat_struct_t struct_data;
427     gras_dd_cat_field_t  field;
428     char                *field_data;
429     
430     struct_data = type->category.struct_data;
431     xbt_assert1(struct_data.closed,
432       "Please call gras_datadesc_declare_struct_close on %s before sending it",
433                 type->name);
434     VERB1(">> Send all fields of the structure %s",type->name);
435     xbt_dynar_foreach(struct_data.fields, cpt, field) {
436       field_data = data;
437       field_data += field->offset[GRAS_THISARCH];
438       
439       sub_type = field->type;
440       
441       if (field->send) {
442         DEBUG1("Run the emission callback of field %s", field->name);
443         field->send(type,state,field_data);
444       }
445       
446       VERB1("Send field %s",field->name);
447       gras_datadesc_send_rec(sock,state,refs,sub_type, field_data, 
448                              detect_cycle || sub_type->cycle);
449       
450     }
451     VERB1("<< Sent all fields of the structure %s", type->name);
452     
453     break;
454   }
455
456   case e_gras_datadesc_type_cat_union: {
457     gras_dd_cat_union_t union_data;
458     gras_dd_cat_field_t field=NULL;
459     int                 field_num;
460     
461     union_data = type->category.union_data;
462     
463     xbt_assert1(union_data.closed,
464                 "Please call gras_datadesc_declare_union_close on %s before sending it",
465                 type->name);
466     /* retrieve the field number */
467     field_num = union_data.selector(type, state, data);
468     
469     xbt_assert1(field_num > 0,
470                  "union field selector of %s gave a negative value", 
471                  type->name);
472     
473     xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
474          "union field selector of %s returned %d but there is only %lu fields",
475                  type->name, field_num, xbt_dynar_length(union_data.fields));
476
477     /* Send the field number */
478     gras_dd_send_int(sock, &field_num, 0 /* not stable */);
479     
480     /* Send the content */
481     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
482     sub_type = field->type;
483     
484     if (field->send)
485       field->send(type,state,data);
486     
487     gras_datadesc_send_rec(sock,state,refs, sub_type, data, 
488                            detect_cycle || sub_type->cycle);
489           
490     break;
491   }
492     
493   case e_gras_datadesc_type_cat_ref: {
494     gras_dd_cat_ref_t      ref_data;
495     void                 **ref=(void**)data;
496     int                    reference_is_to_send;
497     
498     ref_data = type->category.ref_data;
499     
500     /* Detect the referenced type and send it to peer if needed */
501     sub_type = ref_data.type;
502     if (sub_type == NULL) {
503       sub_type = (*ref_data.selector)(type,state,data);
504       gras_dd_send_int(sock, (int*) &(sub_type->code),1 /*stable*/);
505     }
506     
507     /* Send the actual value of the pointer for cycle handling */
508     if (!pointer_type) {
509       pointer_type = gras_datadesc_by_name("data pointer");
510       xbt_assert(pointer_type);
511     }
512      
513     gras_trp_send(sock, (char*)data,
514                   pointer_type->size[GRAS_THISARCH], 1 /*stable*/);
515     
516     /* Send the pointed data only if not already sent */
517     if (*(void**)data == NULL) {
518       VERB0("Not sending NULL referenced data");
519       break;
520     }
521
522     reference_is_to_send = 0;
523     TRY {
524       if (detect_cycle)
525         /* return ignored. Just checking whether it's known or not */
526         xbt_dict_get_ext(refs,(char*)ref, sizeof(char*));
527       else 
528         reference_is_to_send = 1;
529     } CATCH(e) {
530       if (e.category != not_found_error)
531         RETHROW;
532       reference_is_to_send = 1;
533       xbt_ex_free(e);
534     }
535
536     if (reference_is_to_send) {
537        VERB1("Sending data referenced at %p", (void*)*ref);
538        if (detect_cycle)
539          xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
540        gras_datadesc_send_rec(sock,state,refs, sub_type, *ref, 
541                               detect_cycle || sub_type->cycle);
542           
543     } else {
544        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
545     } 
546     
547     break;
548   }
549
550   case e_gras_datadesc_type_cat_array: {
551     gras_dd_cat_array_t    array_data;
552     int                    count;
553     char                  *ptr=data;
554     long int               elm_size;
555     
556     array_data = type->category.array_data;
557     
558     /* determine and send the element count */
559     count = array_data.fixed_size;
560     if (count == 0) {
561       count = array_data.dynamic_size(type,state,data);
562       xbt_assert1(count >=0,
563                    "Invalid (negative) array size for type %s",type->name);
564       gras_dd_send_int(sock, &count, 0/*non-stable*/);
565     }
566     
567     /* send the content */
568     sub_type = array_data.type;
569     elm_size = sub_type->aligned_size[GRAS_THISARCH];
570     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
571       VERB1("Array of %d scalars, send it in one shot",count);
572       gras_trp_send(sock, data, 
573                     sub_type->aligned_size[GRAS_THISARCH] * count,
574                     0 /* not stable */);
575     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
576                sub_type->category.array_data.fixed_size > 0 &&
577                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
578        
579       VERB1("Array of %d fixed array of scalars, send it in one shot",count);
580       gras_trp_send(sock, data, 
581                     sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
582                     * count * sub_type->category.array_data.fixed_size,
583                     0 /* not stable */);
584        
585     } else {
586       for (cpt=0; cpt<count; cpt++) {
587         gras_datadesc_send_rec(sock,state,refs, sub_type, ptr, 
588                                detect_cycle || sub_type->cycle);
589         ptr += elm_size;
590       }
591     }
592     break;
593   }
594
595   default:
596     xbt_assert0(0, "Invalid type");
597   }
598 }
599
600 /**
601  * gras_datadesc_send:
602  *
603  * Copy the data pointed by src and described by type to the socket
604  *
605  */
606 void gras_datadesc_send(gras_socket_t        sock, 
607                         gras_datadesc_type_t type, 
608                         void *src) {
609
610   xbt_ex_t e;
611   static gras_cbps_t state=NULL;
612   xbt_dict_t  refs; /* all references already sent */
613  
614   xbt_assert0(type,"called with NULL type descriptor");
615
616   refs = xbt_dict_new();
617   if (!state)
618     state = gras_cbps_new();
619   
620   TRY {
621     gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
622   } CLEANUP {
623     xbt_dict_free(&refs);
624     gras_cbps_reset(state);
625   } CATCH(e) {
626     RETHROW;
627   }
628 }
629
630 /**
631  * gras_datadesc_recv_rec:
632  *
633  * Do the data reception job recursively.
634  *
635  * subsize used only to deal with vicious case of reference to dynamic array.
636  *  This size is needed at the reference reception level (to allocate enough 
637  * space) and at the array reception level (to fill enough room). 
638  * 
639  * Having this size passed as an argument of the recursive function is a crude
640  * hack, but I was told that working code is sometimes better than neat one ;)
641  */
642 static void
643 gras_datadesc_recv_rec(gras_socket_t         sock, 
644                        gras_cbps_t           state,
645                        xbt_dict_t           refs,
646                        gras_datadesc_type_t  type,
647                        int                   r_arch,
648                        char                **r_data,
649                        long int              r_lgr,
650                        char                 *l_data,
651                        int                   subsize,
652                        int                   detect_cycle) {
653
654   int                  cpt;
655   gras_datadesc_type_t sub_type;
656   xbt_ex_t e;
657
658   VERB2("Recv a %s @%p", type->name, (void*)l_data);
659   xbt_assert(l_data);
660
661   switch (type->category_code) {
662   case e_gras_datadesc_type_cat_scalar:
663     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
664       gras_trp_recv(sock, (char*)l_data, type->size[r_arch]);
665       if (r_arch != GRAS_THISARCH)
666         gras_dd_convert_elm(type,1,r_arch, l_data,l_data);
667     } else {
668       void *ptr = xbt_malloc(type->size[r_arch]);
669
670       gras_trp_recv(sock, (char*)ptr, type->size[r_arch]);
671       if (r_arch != GRAS_THISARCH)
672         gras_dd_convert_elm(type,1,r_arch, ptr,l_data);
673       free(ptr);
674     }
675     break;
676
677   case e_gras_datadesc_type_cat_struct: {
678     gras_dd_cat_struct_t struct_data;
679     gras_dd_cat_field_t  field;
680
681     struct_data = type->category.struct_data;
682
683     xbt_assert1(struct_data.closed,
684                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
685                 type->name);
686     VERB1(">> Receive all fields of the structure %s",type->name);
687     xbt_dynar_foreach(struct_data.fields, cpt, field) {
688       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
689
690       sub_type = field->type;
691
692       gras_datadesc_recv_rec(sock,state,refs, sub_type,
693                              r_arch,NULL,0,
694                              field_data,-1, 
695                              detect_cycle || sub_type->cycle);
696        
697       if (field->recv) {
698         DEBUG1("Run the reception callback of field %s", field->name);
699         field->recv(type,state,(void*)l_data);
700       }
701     
702     }
703     VERB1("<< Received all fields of the structure %s", type->name);
704     
705     break;
706   }
707
708   case e_gras_datadesc_type_cat_union: {
709     gras_dd_cat_union_t union_data;
710     gras_dd_cat_field_t field=NULL;
711     int                 field_num;
712
713     union_data = type->category.union_data;
714
715     xbt_assert1(union_data.closed,
716                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
717                 type->name);
718     /* retrieve the field number */
719     gras_dd_recv_int(sock, r_arch, &field_num);
720     if (field_num < 0)
721       THROW1(mismatch_error,0,
722              "Received union field for %s is negative", type->name);
723     if (field_num > xbt_dynar_length(union_data.fields)) 
724       THROW3(mismatch_error,0,
725              "Received union field for %s is said to be #%d but there is only %lu fields",
726              type->name, field_num, xbt_dynar_length(union_data.fields));
727     
728     /* Recv the content */
729     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
730     sub_type = field->type;
731     
732     gras_datadesc_recv_rec(sock,state,refs, sub_type,
733                            r_arch,NULL,0,
734                            l_data,-1,
735                            detect_cycle || sub_type->cycle);
736     if (field->recv)
737        field->recv(type,state,l_data);
738
739     break;
740   }
741
742   case e_gras_datadesc_type_cat_ref: {
743     char             **r_ref = NULL;
744     char             **l_ref = NULL;
745     gras_dd_cat_ref_t  ref_data;
746     int reference_is_to_recv = 0;
747     
748     ref_data = type->category.ref_data;
749
750     /* Get the referenced type locally or from peer */
751     sub_type = ref_data.type;
752     if (sub_type == NULL) {
753       int ref_code;
754       gras_dd_recv_int(sock, r_arch, &ref_code);
755       sub_type = gras_datadesc_by_id(ref_code);
756     }
757
758     /* Get the actual value of the pointer for cycle handling */
759     if (!pointer_type) {
760       pointer_type = gras_datadesc_by_name("data pointer");
761       xbt_assert(pointer_type);
762     }
763
764     r_ref = xbt_malloc(pointer_type->size[r_arch]);
765
766     gras_trp_recv(sock, (char*)r_ref,
767                   pointer_type->size[r_arch]);
768
769     /* Receive the pointed data only if not already sent */
770     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
771       VERB1("Not receiving data remotely referenced @%p since it's NULL",
772             *(void **)r_ref);
773       *(void**)l_data = NULL;
774       free(r_ref);
775       break;
776     }
777          
778     reference_is_to_recv = 0;
779     TRY {
780       if (detect_cycle)
781         l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
782       else 
783         reference_is_to_recv = 1;
784     } CATCH(e) {
785       if (e.category != not_found_error)
786         RETHROW;
787       reference_is_to_recv = 1;
788       xbt_ex_free(e);
789     }
790     if (reference_is_to_recv) {
791       int subsubcount = 0;
792       void *l_referenced=NULL;
793
794       VERB2("Receiving a ref to '%s', remotely @%p",
795             sub_type->name, *(void**)r_ref);
796       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
797         /* Damn. Reference to a dynamic array. Allocating the space for it 
798            is more complicated */
799         gras_dd_cat_array_t array_data = sub_type->category.array_data;
800         gras_datadesc_type_t subsub_type;
801
802         subsubcount = array_data.fixed_size;
803         if (subsubcount == 0)
804           gras_dd_recv_int(sock, r_arch, &subsubcount);
805
806         subsub_type = array_data.type;
807
808
809         gras_dd_alloc_ref(refs,
810                           subsub_type->size[GRAS_THISARCH] * subsubcount, 
811                           r_ref,pointer_type->size[r_arch], 
812                           (char**)&l_referenced,
813                           detect_cycle);
814       } else {
815         gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
816                           r_ref,pointer_type->size[r_arch], 
817                           (char**)&l_referenced,
818                           detect_cycle);
819       }
820
821       gras_datadesc_recv_rec(sock,state,refs, sub_type,
822                              r_arch,r_ref,pointer_type->size[r_arch],
823                              (char*)l_referenced, subsubcount,
824                              detect_cycle || sub_type->cycle);
825                                
826       *(void**)l_data=l_referenced;
827       VERB3("'%s' remotely referenced at %p locally at %p",
828             sub_type->name, *(void**)r_ref, l_referenced);
829       
830     } else {
831       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
832             *(void**)r_ref, *(void**)l_ref);
833
834       *(void**)l_data=*l_ref;
835
836     } 
837     free(r_ref);
838     break;
839   }
840
841   case e_gras_datadesc_type_cat_array: {
842     gras_dd_cat_array_t    array_data;
843     int       count;
844     char     *ptr;
845     long int  elm_size;
846
847     array_data = type->category.array_data;
848     /* determine element count locally, or from caller, or from peer */
849     count = array_data.fixed_size;
850     if (count == 0)
851       count = subsize;
852     if (count == 0)
853       gras_dd_recv_int(sock, r_arch, &count);
854     if (count == 0)
855       THROW1(mismatch_error,0,
856              "Invalid (=0) array size for type %s",type->name);
857
858     /* receive the content */
859     sub_type = array_data.type;
860     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
861       VERB1("Array of %d scalars, get it in one shoot", count);
862       if (sub_type->aligned_size[GRAS_THISARCH] >= 
863           sub_type->aligned_size[r_arch]) {
864         gras_trp_recv(sock, (char*)l_data, 
865                       sub_type->aligned_size[r_arch] * count);
866         if (r_arch != GRAS_THISARCH)
867           gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data);
868       } else {
869         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
870
871         gras_trp_recv(sock, (char*)ptr, 
872                       sub_type->size[r_arch] * count);
873         if (r_arch != GRAS_THISARCH)
874           gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data);
875         free(ptr);
876       }
877     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
878                sub_type->category.array_data.fixed_size > 0 &&
879                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
880       gras_datadesc_type_t subsub_type;
881       array_data = sub_type->category.array_data;
882       subsub_type = array_data.type;
883        
884       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
885       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
886           subsub_type->aligned_size[r_arch]) {
887         gras_trp_recv(sock, (char*)l_data, 
888                       subsub_type->aligned_size[r_arch] * count * 
889                       array_data.fixed_size);
890         if (r_arch != GRAS_THISARCH)
891           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data);
892       } else {
893         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
894
895         gras_trp_recv(sock, (char*)ptr, 
896                       subsub_type->size[r_arch] * count*array_data.fixed_size);
897         if (r_arch != GRAS_THISARCH)
898           gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data);
899         free(ptr);
900       }
901       
902        
903     } else {
904       /* not scalar content, get it recursively (may contain pointers) */
905       elm_size = sub_type->aligned_size[GRAS_THISARCH];
906       VERB2("Receive a %d-long array of %s",count, sub_type->name);
907
908       ptr = l_data;
909       for (cpt=0; cpt<count; cpt++) {
910         gras_datadesc_recv_rec(sock,state,refs, sub_type,
911                                r_arch, NULL, 0, ptr,-1,
912                                detect_cycle || sub_type->cycle);
913                                    
914         ptr += elm_size;
915       }
916     }
917     break;
918   }
919         
920   default:
921     xbt_assert0(0, "Invalid type");
922   }
923   
924   if (type->recv)
925     type->recv(type,state,l_data);
926
927   if (!strcmp(type->name,"string"))
928     VERB1("value: '%s'",*(char**)l_data);
929
930 }
931
932 /**
933  * gras_datadesc_recv:
934  *
935  * Get an instance of the datatype described by @type from the @socket, 
936  * and store a pointer to it in @dst
937  *
938  */
939 void
940 gras_datadesc_recv(gras_socket_t         sock, 
941                    gras_datadesc_type_t  type,
942                    int                   r_arch,
943                    void                 *dst) {
944
945   xbt_ex_t e;
946   static gras_cbps_t state=NULL; /* callback persistent state */
947   xbt_dict_t  refs;  /* all references already sent */
948
949   refs = xbt_dict_new();
950   if (!state)
951     state = gras_cbps_new();
952
953   xbt_assert0(type,"called with NULL type descriptor");
954   TRY {
955     gras_datadesc_recv_rec(sock, state, refs, type, 
956                            r_arch, NULL, 0,
957                            (char *) dst,-1, 
958                            type->cycle);
959   } CLEANUP {
960     xbt_dict_free(&refs);
961     gras_cbps_reset(state);
962   } CATCH(e) {
963     RETHROW;
964   }
965 }
966