Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
e0c876729ed6b73b6ec3199b8f38ffa0fbaeb35c
[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 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 "gras/DataDesc/datadesc_private.h"
13 #include "gras/Transport/transport_interface.h" /* gras_trp_chunk_send/recv */
14
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ddt_exchange,datadesc,
16                                  "Sending data over the network");
17 const char *gras_datadesc_cat_names[9] = { 
18   "undefined", 
19   "scalar", "struct", "union", "ref", "array", "ignored",
20   "invalid"};
21
22 static gras_datadesc_type_t int_type = NULL;
23 static gras_datadesc_type_t pointer_type = NULL;    
24 static _XBT_INLINE xbt_error_t gras_dd_send_int(gras_socket_t sock,             int  i);
25 static _XBT_INLINE xbt_error_t gras_dd_recv_int(gras_socket_t sock, int r_arch, int *i);
26
27 static _XBT_INLINE xbt_error_t
28 gras_dd_alloc_ref(xbt_dict_t  refs,  long int     size,
29                   char       **r_ref, long int     r_len,
30                   char       **l_ref, int detect_cycle);
31
32 static _XBT_INLINE int
33 gras_dd_is_r_null(char **r_ptr, long int length);
34
35 static _XBT_INLINE xbt_error_t
36 gras_dd_send_int(gras_socket_t sock,int i) {
37
38   if (!int_type) {
39     int_type = gras_datadesc_by_name("int");
40      xbt_assert(int_type);  
41   }
42    
43   DEBUG1("send_int(%d)",i);
44   return gras_trp_chunk_send(sock, (char*)&i, int_type->size[GRAS_THISARCH]);
45 }
46
47 static _XBT_INLINE xbt_error_t
48 gras_dd_recv_int(gras_socket_t sock, int r_arch, int *i) {
49   xbt_error_t errcode;
50
51   if (!int_type) {
52      int_type = gras_datadesc_by_name("int");
53      xbt_assert(int_type);
54   }
55
56   if (int_type->size[GRAS_THISARCH] >= int_type->size[r_arch]) {
57     TRY(gras_trp_chunk_recv(sock, (char*)i, int_type->size[r_arch]));
58     if (r_arch != GRAS_THISARCH)
59       TRY(gras_dd_convert_elm(int_type,1,r_arch, i,i));
60   } else {
61     void *ptr = xbt_malloc(int_type->size[r_arch]);
62
63     TRY(gras_trp_chunk_recv(sock, (char*)ptr, int_type->size[r_arch]));
64     if (r_arch != GRAS_THISARCH)
65       TRY(gras_dd_convert_elm(int_type,1,r_arch, ptr,i));
66     free(ptr);
67   }
68   DEBUG1("recv_int(%d)",*i);
69
70   return no_error;
71 }
72
73 /*
74  * Note: here we suppose that the remote NULL is a sequence 
75  *       of 'length' bytes set to 0.
76  * FIXME: Check in configure?
77  */
78 static _XBT_INLINE int 
79 gras_dd_is_r_null(char **r_ptr, long int length) {
80   int i;
81
82   for (i=0; i<length; i++) {
83     if ( ((unsigned char*)r_ptr) [i]) {
84       return 0;
85     }
86   }
87
88   return 1;
89 }
90
91 static _XBT_INLINE xbt_error_t
92 gras_dd_alloc_ref(xbt_dict_t  refs,
93                   long int     size,
94                   char       **r_ref,
95                   long int     r_len, /* pointer_type->size[r_arch] */
96                   char       **l_ref,
97                   int          detect_cycle) {
98   char *l_data = NULL;
99
100   xbt_assert1(size>0,"Cannot allocate %ld bytes!", size);
101   l_data = xbt_malloc((size_t)size);
102
103   *l_ref = l_data;
104   DEBUG2("l_data=%p, &l_data=%p",(void*)l_data,(void*)&l_data);
105
106   DEBUG3("alloc_ref: r_ref=%p; *r_ref=%p, r_len=%ld",
107          (void*)r_ref, (void*)(r_ref?*r_ref:NULL), r_len);
108   if (detect_cycle && r_ref && !gras_dd_is_r_null( r_ref, r_len)) {
109     void *ptr = xbt_malloc(sizeof(void *));
110
111     CRITICAL0("detect_cycle");
112     memcpy(ptr,l_ref, sizeof(void *));
113
114     DEBUG2("Insert %p under %p",*(void**)ptr, *(void**)r_ref);
115
116     if (detect_cycle)
117        xbt_dict_set_ext(refs,(const char *) r_ref, r_len, ptr, free);
118   }
119   return no_error;
120 }
121
122 /**
123  * gras_datadesc_cpy:
124  *
125  * Copy the data pointed by src and described by type 
126  * to a new location, and store a pointer to it in dst.
127  *
128  */
129 xbt_error_t gras_datadesc_cpy(gras_datadesc_type_t type, 
130                                void *src, 
131                                void **dst) {
132   RAISE_UNIMPLEMENTED;
133 }
134
135 /***
136  *** Direct use functions
137  ***/
138
139 static xbt_error_t 
140 gras_datadesc_send_rec(gras_socket_t         sock,
141                        gras_cbps_t           state,
142                        xbt_dict_t           refs,
143                        gras_datadesc_type_t  type, 
144                        char                 *data,
145                        int                   detect_cycle) {
146
147   xbt_error_t         errcode;
148   int                  cpt;
149   gras_datadesc_type_t sub_type; /* type on which we recurse */
150   
151   VERB2("Send a %s (%s)", 
152         type->name, gras_datadesc_cat_names[type->category_code]);
153
154   if (type->send) {
155     type->send(state,data);
156   }
157
158   switch (type->category_code) {
159   case e_gras_datadesc_type_cat_scalar:
160     TRY(gras_trp_chunk_send(sock, data, type->size[GRAS_THISARCH]));
161     break;
162
163   case e_gras_datadesc_type_cat_struct: {
164     gras_dd_cat_struct_t struct_data;
165     gras_dd_cat_field_t  field;
166     char                *field_data;
167     
168     struct_data = type->category.struct_data;
169     xbt_assert1(struct_data.closed,
170       "Please call gras_datadesc_declare_struct_close on %s before sending it",
171                 type->name);
172     VERB1(">> Send all fields of the structure %s",type->name);
173     xbt_dynar_foreach(struct_data.fields, cpt, field) {
174       field_data = data;
175       field_data += field->offset[GRAS_THISARCH];
176       
177       sub_type = field->type;
178       
179       if (field->pre)
180         field->pre(state,field_data);
181       
182       VERB1("Send field %s",field->name);
183       TRY(gras_datadesc_send_rec(sock,state,refs,sub_type, field_data, detect_cycle || sub_type->cycle));
184       
185       if (field->post)
186         field->post(state,field_data);
187     }
188     VERB1("<< Sent all fields of the structure %s", type->name);
189     
190     break;
191   }
192
193   case e_gras_datadesc_type_cat_union: {
194     gras_dd_cat_union_t union_data;
195     gras_dd_cat_field_t field=NULL;
196     int                 field_num;
197     
198     union_data = type->category.union_data;
199     
200     xbt_assert1(union_data.closed,
201                 "Please call gras_datadesc_declare_union_close on %s before sending it",
202                 type->name);
203     /* retrieve the field number */
204     field_num = union_data.selector(state, data);
205     
206     xbt_assert1(field_num > 0,
207                  "union field selector of %s gave a negative value", 
208                  type->name);
209     
210     xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
211          "union field selector of %s returned %d but there is only %lu fields",
212                  type->name, field_num, xbt_dynar_length(union_data.fields));
213
214     /* Send the field number */
215     TRY(gras_dd_send_int(sock, field_num));
216     
217     /* Send the content */
218     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
219     sub_type = field->type;
220     
221     if (field->pre)
222       field->pre(state,data);
223     
224     TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, data, detect_cycle || sub_type->cycle));
225       
226     if (field->post)
227       field->post(state,data);
228     
229     break;
230   }
231     
232   case e_gras_datadesc_type_cat_ref: {
233     gras_dd_cat_ref_t      ref_data;
234
235     void                 **ref=(void**)data;
236     void *dummy;
237     
238     ref_data = type->category.ref_data;
239     
240     /* Detect the referenced type and send it to peer if needed */
241     sub_type = ref_data.type;
242     if (sub_type == NULL) {
243       sub_type = (*ref_data.selector)(state,data);
244       TRY(gras_dd_send_int(sock, sub_type->code));
245     }
246     
247     /* Send the actual value of the pointer for cycle handling */
248     if (!pointer_type) {
249       pointer_type = gras_datadesc_by_name("data pointer");
250       xbt_assert(pointer_type);
251     }
252      
253     TRY(gras_trp_chunk_send(sock, (char*)data,
254                             pointer_type->size[GRAS_THISARCH]));
255     
256     /* Send the pointed data only if not already sent */
257     if (*(void**)data == NULL) {
258       VERB0("Not sending NULL referenced data");
259       break;
260     }
261     errcode = detect_cycle 
262             ? xbt_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy)
263             : mismatch_error;
264     if (errcode == mismatch_error) {
265        VERB1("Sending data referenced at %p", (void*)*ref);
266        if (detect_cycle)
267          xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
268        TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, *ref, detect_cycle || sub_type->cycle));
269           
270     } else if (errcode == no_error) {
271        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
272     } else {
273        return errcode;
274     }
275     
276     break;
277   }
278
279   case e_gras_datadesc_type_cat_array: {
280     gras_dd_cat_array_t    array_data;
281     long int               count;
282     char                  *ptr=data;
283     long int               elm_size;
284     
285     array_data = type->category.array_data;
286     
287     /* determine and send the element count */
288     count = array_data.fixed_size;
289     if (count == 0) {
290       count = array_data.dynamic_size(state,data);
291       xbt_assert1(count >=0,
292                    "Invalid (negative) array size for type %s",type->name);
293       TRY(gras_dd_send_int(sock, count));
294     }
295     
296     /* send the content */
297     sub_type = array_data.type;
298     elm_size = sub_type->aligned_size[GRAS_THISARCH];
299     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
300       VERB1("Array of %ld scalars, send it in one shot",count);
301       TRY(gras_trp_chunk_send(sock, data, 
302                               sub_type->aligned_size[GRAS_THISARCH] * count));
303     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
304                sub_type->category.array_data.fixed_size > 0 &&
305                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
306        
307       VERB1("Array of %ld fixed array of scalars, send it in one shot",count);
308       TRY(gras_trp_chunk_send(sock, data, 
309                               sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
310                                  * count * sub_type->category.array_data.fixed_size));
311        
312     } else {
313       for (cpt=0; cpt<count; cpt++) {
314         TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, ptr, detect_cycle || sub_type->cycle));
315         ptr += elm_size;
316       }
317     }
318     break;
319   }
320
321   default:
322     xbt_assert0(0, "Invalid type");
323   }
324
325   return no_error;
326 }
327
328 /**
329  * gras_datadesc_send:
330  *
331  * Copy the data pointed by src and described by type to the socket
332  *
333  */
334 xbt_error_t gras_datadesc_send(gras_socket_t        sock, 
335                                 gras_datadesc_type_t type, 
336                                 void *src) {
337
338   xbt_error_t errcode;
339   gras_cbps_t  state;
340   xbt_dict_t  refs; /* all references already sent */
341  
342   refs = xbt_dict_new();
343   state = gras_cbps_new();
344   
345   xbt_assert0(type,"called with NULL type descriptor");
346   errcode = gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
347
348   xbt_dict_free(&refs);
349   gras_cbps_free(&state);
350
351   return errcode;
352 }
353
354 /**
355  * gras_datadesc_recv_rec:
356  *
357  * Do the data reception job recursively.
358  *
359  * subsize used only to deal with vicious case of reference to dynamic array.
360  *  This size is needed at the reference reception level (to allocate enough 
361  * space) and at the array reception level (to fill enough room). 
362  * 
363  * Having this size passed as an argument of the recursive function is a crude
364  * hack, but I was told that working code is sometimes better than neat one ;)
365  */
366 static xbt_error_t
367 gras_datadesc_recv_rec(gras_socket_t         sock, 
368                        gras_cbps_t           state,
369                        xbt_dict_t           refs,
370                        gras_datadesc_type_t  type,
371                        int                   r_arch,
372                        char                **r_data,
373                        long int              r_lgr,
374                        char                 *l_data,
375                        int                   subsize,
376                        int                   detect_cycle) {
377
378   xbt_error_t         errcode;
379   int                  cpt;
380   gras_datadesc_type_t sub_type;
381
382   VERB2("Recv a %s @%p", type->name, (void*)l_data);
383   xbt_assert(l_data);
384
385   switch (type->category_code) {
386   case e_gras_datadesc_type_cat_scalar:
387     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
388       TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
389       if (r_arch != GRAS_THISARCH)
390         TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
391     } else {
392       void *ptr = xbt_malloc(type->size[r_arch]);
393
394       TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
395       if (r_arch != GRAS_THISARCH)
396         TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
397       free(ptr);
398     }
399     break;
400
401   case e_gras_datadesc_type_cat_struct: {
402     gras_dd_cat_struct_t struct_data;
403     gras_dd_cat_field_t  field;
404
405     struct_data = type->category.struct_data;
406
407     xbt_assert1(struct_data.closed,
408                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
409                 type->name);
410     VERB1(">> Receive all fields of the structure %s",type->name);
411     xbt_dynar_foreach(struct_data.fields, cpt, field) {
412       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
413
414       sub_type = field->type;
415
416       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
417                                  r_arch,NULL,0,
418                                  field_data,-1, 
419                                  detect_cycle || sub_type->cycle));
420     }
421     VERB1("<< Received all fields of the structure %s", type->name);
422     
423     break;
424   }
425
426   case e_gras_datadesc_type_cat_union: {
427     gras_dd_cat_union_t union_data;
428     gras_dd_cat_field_t field=NULL;
429     int                 field_num;
430
431     union_data = type->category.union_data;
432
433     xbt_assert1(union_data.closed,
434                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
435                 type->name);
436     /* retrieve the field number */
437     TRY(gras_dd_recv_int(sock, r_arch, &field_num));
438     if (field_num < 0)
439       RAISE1(mismatch_error,
440              "Received union field for %s is negative", type->name);
441     if (field_num < xbt_dynar_length(union_data.fields)) 
442       RAISE3(mismatch_error,
443              "Received union field for %s is %d but there is only %lu fields",
444              type->name, field_num, xbt_dynar_length(union_data.fields));
445     
446     /* Recv the content */
447     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
448     sub_type = field->type;
449     
450     TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
451                                r_arch,NULL,0,
452                                l_data,-1, 
453                                detect_cycle || sub_type->cycle));
454     break;
455   }
456
457   case e_gras_datadesc_type_cat_ref: {
458     char             **r_ref = NULL;
459     char             **l_ref = NULL;
460     gras_dd_cat_ref_t  ref_data;
461     
462     ref_data = type->category.ref_data;
463
464     /* Get the referenced type locally or from peer */
465     sub_type = ref_data.type;
466     if (sub_type == NULL) {
467       int ref_code;
468       TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
469       TRY(gras_datadesc_by_id(ref_code, &sub_type));
470     }
471
472     /* Get the actual value of the pointer for cycle handling */
473     if (!pointer_type) {
474       pointer_type = gras_datadesc_by_name("data pointer");
475       xbt_assert(pointer_type);
476     }
477
478     r_ref = xbt_malloc(pointer_type->size[r_arch]);
479
480     TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
481                             pointer_type->size[r_arch]));
482
483     /* Receive the pointed data only if not already sent */
484     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
485       VERB1("Not receiving data remotely referenced @%p since it's NULL",
486             *(void **)r_ref);
487       *(void**)l_data = NULL;
488       free(r_ref);
489       break;
490     }
491          
492     errcode = detect_cycle
493             ? xbt_dict_get_ext(refs,
494                                 (char*)r_ref, pointer_type->size[r_arch],
495                                 (void**)&l_ref)
496             : mismatch_error;
497
498     if (errcode == mismatch_error) {
499       int subsubcount = 0;
500       void *l_referenced=NULL;
501
502       VERB2("Receiving a ref to '%s', remotely @%p",
503             sub_type->name, *(void**)r_ref);
504       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
505         /* Damn. Reference to a dynamic array. Allocating the size for it 
506            is more complicated */
507         gras_dd_cat_array_t array_data = sub_type->category.array_data;
508         gras_datadesc_type_t subsub_type;
509
510         subsubcount = array_data.fixed_size;
511         if (subsubcount == 0)
512           TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
513
514         subsub_type = array_data.type;
515
516
517         TRY(gras_dd_alloc_ref(refs,
518                               subsub_type->size[GRAS_THISARCH] * subsubcount, 
519                               r_ref,pointer_type->size[r_arch], 
520                               (char**)&l_referenced,
521                               detect_cycle));
522       } else {
523         TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
524                               r_ref,pointer_type->size[r_arch], 
525                               (char**)&l_referenced,
526                               detect_cycle));
527       }
528
529       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
530                                  r_arch,r_ref,pointer_type->size[r_arch],
531                                  (char*)l_referenced, subsubcount, 
532                                  detect_cycle || sub_type->cycle));
533       *(void**)l_data=l_referenced;
534       VERB3("'%s' remotely referenced at %p locally at %p",
535             sub_type->name, *(void**)r_ref, l_referenced);
536       
537     } else if (errcode == no_error) {
538       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
539             *(void**)r_ref, *(void**)l_ref);
540
541       *(void**)l_data=*l_ref;
542
543     } else {
544       return errcode;
545     }
546     free(r_ref);
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;
554     long int  elm_size;
555
556     array_data = type->category.array_data;
557     /* determine element count locally, or from caller, or from peer */
558     count = array_data.fixed_size;
559     if (count == 0)
560       count = subsize;
561     if (count == 0)
562       TRY(gras_dd_recv_int(sock, r_arch, &count));
563     if (count == 0)
564       RAISE1(mismatch_error,
565              "Invalid (=0) array size for type %s",type->name);
566
567     /* receive the content */
568     sub_type = array_data.type;
569     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
570       VERB1("Array of %d scalars, get it in one shoot", count);
571       if (sub_type->aligned_size[GRAS_THISARCH] >= 
572           sub_type->aligned_size[r_arch]) {
573         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
574                                 sub_type->aligned_size[r_arch] * count));
575         if (r_arch != GRAS_THISARCH)
576           TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
577       } else {
578         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
579
580         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
581                                 sub_type->size[r_arch] * count));
582         if (r_arch != GRAS_THISARCH)
583           TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
584         free(ptr);
585       }
586     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
587                sub_type->category.array_data.fixed_size > 0 &&
588                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
589       gras_datadesc_type_t subsub_type;
590       array_data = sub_type->category.array_data;
591       subsub_type = array_data.type;
592        
593       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
594       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
595           subsub_type->aligned_size[r_arch]) {
596         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
597                                 subsub_type->aligned_size[r_arch] * count * 
598                                   array_data.fixed_size));
599         if (r_arch != GRAS_THISARCH)
600           TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data));
601       } else {
602         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
603
604         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
605                                 subsub_type->size[r_arch] * count*array_data.fixed_size));
606         if (r_arch != GRAS_THISARCH)
607           TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data));
608         free(ptr);
609       }
610       
611        
612     } else {
613       /* not scalar content, get it recursively (may contain pointers) */
614       elm_size = sub_type->aligned_size[GRAS_THISARCH];
615       VERB2("Receive a %d-long array of %s",count, sub_type->name);
616
617       ptr = l_data;
618       for (cpt=0; cpt<count; cpt++) {
619         TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
620                                    r_arch, NULL, 0, ptr,-1,
621                                    detect_cycle || sub_type->cycle));
622         ptr += elm_size;
623       }
624     }
625     break;
626   }
627         
628   default:
629     xbt_assert0(0, "Invalid type");
630   }
631   
632   if (type->recv)
633     type->recv(state,l_data);
634
635   return no_error;
636 }
637
638 /**
639  * gras_datadesc_recv:
640  *
641  * Get an instance of the datatype described by @type from the @socket, 
642  * and store a pointer to it in @dst
643  *
644  */
645 xbt_error_t
646 gras_datadesc_recv(gras_socket_t         sock, 
647                    gras_datadesc_type_t  type,
648                    int                   r_arch,
649                    void                 *dst) {
650
651   xbt_error_t errcode;
652   gras_cbps_t  state; /* callback persistent state */
653   xbt_dict_t  refs;  /* all references already sent */
654
655   refs = xbt_dict_new();
656   state = gras_cbps_new();
657
658   xbt_assert0(type,"called with NULL type descriptor");
659   errcode = gras_datadesc_recv_rec(sock, state, refs, type, 
660                                    r_arch, NULL, 0,
661                                    (char *) dst,-1, 
662                                    type->cycle);
663
664   xbt_dict_free(&refs);
665   gras_cbps_free(&state);
666
667   return errcode;
668 }
669
670 #if 0
671 /***
672  *** IDL compiling functions
673  ***/
674
675 #define gras_datadesc_send_rec foo /* Just to make sure the copypast was ok */
676 #define gras_datadesc_send     foo /* Just to make sure the copypast was ok */
677 #define gras_datadesc_recv_rec foo /* Just to make sure the copypast was ok */
678 #define gras_datadesc_recv     foo /* Just to make sure the copypast was ok */
679
680 static xbt_error_t 
681 gras_datadesc_gen_send_rec(gras_socket_t         sock,
682                            gras_cbps_t           state,
683                            xbt_dict_t           refs,
684                            gras_datadesc_type_t  type, 
685                            char                 *data,
686                            int                   detect_cycle) {
687
688   xbt_error_t         errcode;
689   int                  cpt;
690   gras_datadesc_type_t sub_type; /* type on which we recurse */
691   
692   printf("  VERB2(\"Send a %s (%s)\");\n", 
693          type->name, gras_datadesc_cat_names[type->category_code]);
694
695   xbt_assert0(!type->send, "Callbacks not implemented in IDL compiler");
696
697   switch (type->category_code) {
698   case e_gras_datadesc_type_cat_scalar:
699     printf("  TRY(gras_trp_chunk_send(sock, data, %lu));\n",type->size[GRAS_THISARCH]);
700     break;
701
702   case e_gras_datadesc_type_cat_struct: {
703     gras_dd_cat_struct_t struct_data;
704     gras_dd_cat_field_t  field;
705     char                *field_data;
706     
707     struct_data = type->category.struct_data;
708     xbt_assert1(struct_data.closed,
709       "Please call gras_datadesc_declare_struct_close on %s before sending it",
710                 type->name);
711     printf("  VERB1(\">> Send all fields of the structure %s\");\n",type->name);
712     xbt_dynar_foreach(struct_data.fields, cpt, field) {
713       field_data = data;
714       field_data += field->offset[GRAS_THISARCH];
715       
716       sub_type = field->type;
717       
718       xbt_assert0(!field->pre, "Callbacks not implemented in IDL compiler");
719       
720       printf("  VERB1(\"Send field %s\");\n",field->name);
721       printf("  data += %lu;\n",field->offset[GRAS_THISARCH]);
722       TRY(gras_datadesc_gen_send_rec(sock,state,refs,sub_type, field_data, detect_cycle || sub_type->cycle));
723       printf("  data -= %lu;\n",field->offset[GRAS_THISARCH]);
724       
725       xbt_assert0(!field->post, "Callbacks not implemented in IDL compiler");
726     }
727     printf("  VERB1(\"<< Sent all fields of the structure %s\"", type->name);
728     
729     break;
730   }
731
732   case e_gras_datadesc_type_cat_union: {
733     gras_dd_cat_union_t union_data;
734     gras_dd_cat_field_t field=NULL;
735     int                 field_num;
736     
737     union_data = type->category.union_data;
738     
739     xbt_assert1(union_data.closed,
740                 "Please call gras_datadesc_declare_union_close on %s before sending it",
741                 type->name);
742     /* retrieve the field number */
743     printf("  field_num = union_data.selector(state, data);\n");
744     
745     printf("  xbt_assert0(field_num > 0,\n");
746     printf("              \"union field selector of %s gave a negative value\");\n",type->name);
747     
748     printf("  xbt_assert3(field_num < xbt_dynar_length(union_data.fields),\n");
749     printf("              \"union field selector of %s returned %%d but there is only %lu fields\",field_num);\n",
750                  type->name, xbt_dynar_length(union_data.fields));
751
752     /* Send the field number */
753     printf("TRY(gras_dd_send_int(sock, field_num));\n");
754     
755     /* Send the content */
756     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
757     sub_type = field->type;
758     
759     if (field->pre)
760       field->pre(state,data);
761     
762     TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, data, detect_cycle || sub_type->cycle));
763       
764     if (field->post)
765       field->post(state,data);
766     
767     break;
768   }
769     
770   case e_gras_datadesc_type_cat_ref: {
771     gras_dd_cat_ref_t      ref_data;
772
773     void                 **ref=(void**)data;
774     void *dummy;
775     
776     ref_data = type->category.ref_data;
777     
778     /* Detect the referenced type and send it to peer if needed */
779     sub_type = ref_data.type;
780     if (sub_type == NULL) {
781       sub_type = (*ref_data.selector)(state,data);
782       TRY(gras_dd_send_int(sock, sub_type->code));
783     }
784     
785     /* Send the actual value of the pointer for cycle handling */
786     if (!pointer_type) {
787       pointer_type = gras_datadesc_by_name("data pointer");
788       xbt_assert(pointer_type);
789     }
790      
791     TRY(gras_trp_chunk_send(sock, (char*)data,
792                             pointer_type->size[GRAS_THISARCH]));
793     
794     /* Send the pointed data only if not already sent */
795     if (*(void**)data == NULL) {
796       VERB0("Not sending NULL referenced data");
797       break;
798     }
799     errcode = detect_cycle 
800             ? xbt_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy)
801             : mismatch_error;
802     if (errcode == mismatch_error) {
803        VERB1("Sending data referenced at %p", (void*)*ref);
804        if (detect_cycle)
805          xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
806        TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, *ref, detect_cycle || sub_type->cycle));
807           
808     } else if (errcode == no_error) {
809        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
810     } else {
811        return errcode;
812     }
813     
814     break;
815   }
816
817   case e_gras_datadesc_type_cat_array: {
818     gras_dd_cat_array_t    array_data;
819     long int               count;
820     char                  *ptr=data;
821     long int               elm_size;
822     
823     array_data = type->category.array_data;
824     
825     /* determine and send the element count */
826     count = array_data.fixed_size;
827     if (count == 0) {
828       count = array_data.dynamic_size(state,data);
829       xbt_assert1(count >=0,
830                    "Invalid (negative) array size for type %s",type->name);
831       TRY(gras_dd_send_int(sock, count));
832     }
833     
834     /* send the content */
835     sub_type = array_data.type;
836     elm_size = sub_type->aligned_size[GRAS_THISARCH];
837     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
838       VERB1("Array of %ld scalars, send it in one shot",count);
839       TRY(gras_trp_chunk_send(sock, data, 
840                               sub_type->aligned_size[GRAS_THISARCH] * count));
841     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
842                sub_type->category.array_data.fixed_size > 0 &&
843                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
844        
845       VERB1("Array of %ld fixed array of scalars, send it in one shot",count);
846       TRY(gras_trp_chunk_send(sock, data, 
847                               sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
848                                  * count * sub_type->category.array_data.fixed_size));
849        
850     } else {
851       for (cpt=0; cpt<count; cpt++) {
852         TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, ptr, detect_cycle || sub_type->cycle));
853         ptr += elm_size;
854       }
855     }
856     break;
857   }
858
859   default:
860     xbt_assert0(0, "Invalid type");
861   }
862
863   return no_error;
864 }
865
866 /**
867  * gras_datadesc_gen_send:
868  *
869  * Copy the data pointed by src and described by type to the socket
870  *
871  */
872 xbt_error_t gras_datadesc_gen_send(gras_socket_t        sock, 
873                                    gras_datadesc_type_t type, 
874                                    void *src) {
875
876   xbt_error_t errcode;
877   gras_cbps_t  state;
878   xbt_dict_t  refs; /* all references already sent */
879  
880   refs = xbt_dict_new();
881   state = gras_cbps_new();
882    
883   printf("xbt_error_t gras_%s_send(gras_socket_t sock,void *dst){\n",
884          type->name);
885   errcode = gras_datadesc_gen_send_rec(sock,state,refs,type,(char*)src, type->cycle);
886   printf("}\n");
887   
888   xbt_dict_free(&refs);
889   gras_cbps_free(&state);
890
891   return errcode;
892 }
893
894 /**
895  * gras_datadesc_gen_recv_rec:
896  *
897  * Do the data reception job recursively.
898  *
899  * subsize used only to deal with vicious case of reference to dynamic array.
900  *  This size is needed at the reference reception level (to allocate enough 
901  * space) and at the array reception level (to fill enough room). 
902  * 
903  * Having this size passed as an argument of the recursive function is a crude
904  * hack, but I was told that working code is sometimes better than neat one ;)
905  */
906 static xbt_error_t
907 gras_datadesc_gen_recv_rec(gras_socket_t         sock, 
908                            gras_cbps_t           state,
909                            xbt_dict_t           refs,
910                            gras_datadesc_type_t  type,
911                            int                   r_arch,
912                            char                **r_data,
913                            long int              r_lgr,
914                            char                 *l_data,
915                            int                   subsize,
916                            int                   detect_cycle) {
917
918   xbt_error_t         errcode;
919   int                  cpt;
920   gras_datadesc_type_t sub_type;
921
922   VERB2("Recv a %s @%p", type->name, (void*)l_data);
923   xbt_assert(l_data);
924
925   switch (type->category_code) {
926   case e_gras_datadesc_type_cat_scalar:
927     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
928       TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
929       if (r_arch != GRAS_THISARCH)
930         TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
931     } else {
932       void *ptr = xbt_malloc(type->size[r_arch]);
933
934       TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
935       if (r_arch != GRAS_THISARCH)
936         TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
937       free(ptr);
938     }
939     break;
940
941   case e_gras_datadesc_type_cat_struct: {
942     gras_dd_cat_struct_t struct_data;
943     gras_dd_cat_field_t  field;
944
945     struct_data = type->category.struct_data;
946
947     xbt_assert1(struct_data.closed,
948                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
949                 type->name);
950     VERB1(">> Receive all fields of the structure %s",type->name);
951     xbt_dynar_foreach(struct_data.fields, cpt, field) {
952       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
953
954       sub_type = field->type;
955
956       TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
957                                      r_arch,NULL,0,
958                                      field_data,-1, 
959                                      detect_cycle || sub_type->cycle));
960     }
961     VERB1("<< Received all fields of the structure %s", type->name);
962     
963     break;
964   }
965
966   case e_gras_datadesc_type_cat_union: {
967     gras_dd_cat_union_t union_data;
968     gras_dd_cat_field_t field=NULL;
969     int                 field_num;
970
971     union_data = type->category.union_data;
972
973     xbt_assert1(union_data.closed,
974                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
975                 type->name);
976     /* retrieve the field number */
977     TRY(gras_dd_recv_int(sock, r_arch, &field_num));
978     if (field_num < 0)
979       RAISE1(mismatch_error,
980              "Received union field for %s is negative", type->name);
981     if (field_num < xbt_dynar_length(union_data.fields)) 
982       RAISE3(mismatch_error,
983              "Received union field for %s is %d but there is only %lu fields",
984              type->name, field_num, xbt_dynar_length(union_data.fields));
985     
986     /* Recv the content */
987     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
988     sub_type = field->type;
989     
990     TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
991                                    r_arch,NULL,0,
992                                    l_data,-1, 
993                                    detect_cycle || sub_type->cycle));
994     break;
995   }
996
997   case e_gras_datadesc_type_cat_ref: {
998     char             **r_ref = NULL;
999     char             **l_ref = NULL;
1000     gras_dd_cat_ref_t  ref_data;
1001     
1002     ref_data = type->category.ref_data;
1003
1004     /* Get the referenced type locally or from peer */
1005     sub_type = ref_data.type;
1006     if (sub_type == NULL) {
1007       int ref_code;
1008       TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
1009       TRY(gras_datadesc_by_id(ref_code, &sub_type));
1010     }
1011
1012     /* Get the actual value of the pointer for cycle handling */
1013     if (!pointer_type) {
1014       pointer_type = gras_datadesc_by_name("data pointer");
1015       xbt_assert(pointer_type);
1016     }
1017
1018     r_ref = xbt_malloc(pointer_type->size[r_arch]);
1019
1020     TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
1021                             pointer_type->size[r_arch]));
1022
1023     /* Receive the pointed data only if not already sent */
1024     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
1025       VERB1("Not receiving data remotely referenced @%p since it's NULL",
1026             *(void **)r_ref);
1027       *(void**)l_data = NULL;
1028       free(r_ref);
1029       break;
1030     }
1031          
1032     errcode = detect_cycle
1033             ? xbt_dict_get_ext(refs,
1034                                 (char*)r_ref, pointer_type->size[r_arch],
1035                                 (void**)&l_ref)
1036             : mismatch_error;
1037
1038     if (errcode == mismatch_error) {
1039       int subsubcount = 0;
1040       void *l_referenced=NULL;
1041
1042       VERB2("Receiving a ref to '%s', remotely @%p",
1043             sub_type->name, *(void**)r_ref);
1044       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
1045         /* Damn. Reference to a dynamic array. Allocating the size for it 
1046            is more complicated */
1047         gras_dd_cat_array_t array_data = sub_type->category.array_data;
1048         gras_datadesc_type_t subsub_type;
1049
1050         subsubcount = array_data.fixed_size;
1051         if (subsubcount == 0)
1052           TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
1053
1054         subsub_type = array_data.type;
1055
1056
1057         TRY(gras_dd_alloc_ref(refs,
1058                               subsub_type->size[GRAS_THISARCH] * subsubcount, 
1059                               r_ref,pointer_type->size[r_arch], 
1060                               (char**)&l_referenced,
1061                               detect_cycle));
1062       } else {
1063         TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
1064                               r_ref,pointer_type->size[r_arch], 
1065                               (char**)&l_referenced,
1066                               detect_cycle));
1067       }
1068
1069       TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1070                                      r_arch,r_ref,pointer_type->size[r_arch],
1071                                      (char*)l_referenced, subsubcount, 
1072                                      detect_cycle || sub_type->cycle));
1073       *(void**)l_data=l_referenced;
1074       VERB3("'%s' remotely referenced at %p locally at %p",
1075             sub_type->name, *(void**)r_ref, l_referenced);
1076       
1077     } else if (errcode == no_error) {
1078       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
1079             *(void**)r_ref, *(void**)l_ref);
1080
1081       *(void**)l_data=*l_ref;
1082
1083     } else {
1084       return errcode;
1085     }
1086     free(r_ref);
1087     break;
1088   }
1089
1090   case e_gras_datadesc_type_cat_array: {
1091     gras_dd_cat_array_t    array_data;
1092     int       count;
1093     char     *ptr;
1094     long int  elm_size;
1095
1096     array_data = type->category.array_data;
1097     /* determine element count locally, or from caller, or from peer */
1098     count = array_data.fixed_size;
1099     if (count == 0)
1100       count = subsize;
1101     if (count == 0)
1102       TRY(gras_dd_recv_int(sock, r_arch, &count));
1103     if (count == 0)
1104       RAISE1(mismatch_error,
1105              "Invalid (=0) array size for type %s",type->name);
1106
1107     /* receive the content */
1108     sub_type = array_data.type;
1109     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
1110       VERB1("Array of %d scalars, get it in one shoot", count);
1111       if (sub_type->aligned_size[GRAS_THISARCH] >= 
1112           sub_type->aligned_size[r_arch]) {
1113         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
1114                                 sub_type->aligned_size[r_arch] * count));
1115         if (r_arch != GRAS_THISARCH)
1116           TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
1117       } else {
1118         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
1119
1120         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
1121                                 sub_type->size[r_arch] * count));
1122         if (r_arch != GRAS_THISARCH)
1123           TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
1124         free(ptr);
1125       }
1126     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
1127                sub_type->category.array_data.fixed_size > 0 &&
1128                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
1129       gras_datadesc_type_t subsub_type;
1130       array_data = sub_type->category.array_data;
1131       subsub_type = array_data.type;
1132        
1133       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
1134       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
1135           subsub_type->aligned_size[r_arch]) {
1136         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
1137                                 subsub_type->aligned_size[r_arch] * count * 
1138                                   array_data.fixed_size));
1139         if (r_arch != GRAS_THISARCH)
1140           TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data));
1141       } else {
1142         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
1143
1144         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
1145                                 subsub_type->size[r_arch] * count*array_data.fixed_size));
1146         if (r_arch != GRAS_THISARCH)
1147           TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data));
1148         free(ptr);
1149       }
1150       
1151        
1152     } else {
1153       /* not scalar content, get it recursively (may contain pointers) */
1154       elm_size = sub_type->aligned_size[GRAS_THISARCH];
1155       VERB2("Receive a %d-long array of %s",count, sub_type->name);
1156
1157       ptr = l_data;
1158       for (cpt=0; cpt<count; cpt++) {
1159         TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1160                                        r_arch, NULL, 0, ptr,-1,
1161                                        detect_cycle || sub_type->cycle));
1162         ptr += elm_size;
1163       }
1164     }
1165     break;
1166   }
1167         
1168   default:
1169     xbt_assert0(0, "Invalid type");
1170   }
1171   
1172   if (type->recv)
1173     type->recv(state,l_data);
1174
1175   return no_error;
1176 }
1177
1178 /**
1179  * gras_datadesc_gen_recv:
1180  *
1181  * Get an instance of the datatype described by @type from the @socket, 
1182  * and store a pointer to it in @dst
1183  *
1184  */
1185 xbt_error_t
1186 gras_datadesc_gen_recv(gras_socket_t         sock, 
1187                        gras_datadesc_type_t  type,
1188                        int                   r_arch,
1189                        void                 *dst) {
1190
1191   xbt_error_t errcode;
1192   gras_cbps_t  state; /* callback persistent state */
1193   xbt_dict_t  refs;  /* all references already sent */
1194
1195   refs = xbt_dict_new();
1196   state = gras_cbps_new();
1197
1198   printf("xbt_error_t gras_%s_recv(gras_socket_t sock,void *dst){\n",
1199          type->name);
1200    
1201   errcode = gras_datadesc_gen_recv_rec(sock, state, refs, type, 
1202                                        r_arch, NULL, 0,
1203                                        (char *) dst,-1, 
1204                                        type->cycle);
1205
1206   printf("}\n");
1207   xbt_dict_free(&refs);
1208   gras_cbps_free(&state);
1209
1210   return errcode;
1211 }
1212 #endif