Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
376752f60086bde8245474221333b02772444200
[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   errcode = gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
346
347   xbt_dict_free(&refs);
348   gras_cbps_free(&state);
349
350   return errcode;
351 }
352
353 /**
354  * gras_datadesc_recv_rec:
355  *
356  * Do the data reception job recursively.
357  *
358  * subsize used only to deal with vicious case of reference to dynamic array.
359  *  This size is needed at the reference reception level (to allocate enough 
360  * space) and at the array reception level (to fill enough room). 
361  * 
362  * Having this size passed as an argument of the recursive function is a crude
363  * hack, but I was told that working code is sometimes better than neat one ;)
364  */
365 static xbt_error_t
366 gras_datadesc_recv_rec(gras_socket_t         sock, 
367                        gras_cbps_t           state,
368                        xbt_dict_t           refs,
369                        gras_datadesc_type_t  type,
370                        int                   r_arch,
371                        char                **r_data,
372                        long int              r_lgr,
373                        char                 *l_data,
374                        int                   subsize,
375                        int                   detect_cycle) {
376
377   xbt_error_t         errcode;
378   int                  cpt;
379   gras_datadesc_type_t sub_type;
380
381   VERB2("Recv a %s @%p", type->name, (void*)l_data);
382   xbt_assert(l_data);
383
384   switch (type->category_code) {
385   case e_gras_datadesc_type_cat_scalar:
386     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
387       TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
388       if (r_arch != GRAS_THISARCH)
389         TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
390     } else {
391       void *ptr = xbt_malloc(type->size[r_arch]);
392
393       TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
394       if (r_arch != GRAS_THISARCH)
395         TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
396       free(ptr);
397     }
398     break;
399
400   case e_gras_datadesc_type_cat_struct: {
401     gras_dd_cat_struct_t struct_data;
402     gras_dd_cat_field_t  field;
403
404     struct_data = type->category.struct_data;
405
406     xbt_assert1(struct_data.closed,
407                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
408                 type->name);
409     VERB1(">> Receive all fields of the structure %s",type->name);
410     xbt_dynar_foreach(struct_data.fields, cpt, field) {
411       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
412
413       sub_type = field->type;
414
415       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
416                                  r_arch,NULL,0,
417                                  field_data,-1, 
418                                  detect_cycle || sub_type->cycle));
419     }
420     VERB1("<< Received all fields of the structure %s", type->name);
421     
422     break;
423   }
424
425   case e_gras_datadesc_type_cat_union: {
426     gras_dd_cat_union_t union_data;
427     gras_dd_cat_field_t field=NULL;
428     int                 field_num;
429
430     union_data = type->category.union_data;
431
432     xbt_assert1(union_data.closed,
433                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
434                 type->name);
435     /* retrieve the field number */
436     TRY(gras_dd_recv_int(sock, r_arch, &field_num));
437     if (field_num < 0)
438       RAISE1(mismatch_error,
439              "Received union field for %s is negative", type->name);
440     if (field_num < xbt_dynar_length(union_data.fields)) 
441       RAISE3(mismatch_error,
442              "Received union field for %s is %d but there is only %lu fields",
443              type->name, field_num, xbt_dynar_length(union_data.fields));
444     
445     /* Recv the content */
446     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
447     sub_type = field->type;
448     
449     TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
450                                r_arch,NULL,0,
451                                l_data,-1, 
452                                detect_cycle || sub_type->cycle));
453     break;
454   }
455
456   case e_gras_datadesc_type_cat_ref: {
457     char             **r_ref = NULL;
458     char             **l_ref = NULL;
459     gras_dd_cat_ref_t  ref_data;
460     
461     ref_data = type->category.ref_data;
462
463     /* Get the referenced type locally or from peer */
464     sub_type = ref_data.type;
465     if (sub_type == NULL) {
466       int ref_code;
467       TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
468       TRY(gras_datadesc_by_id(ref_code, &sub_type));
469     }
470
471     /* Get the actual value of the pointer for cycle handling */
472     if (!pointer_type) {
473       pointer_type = gras_datadesc_by_name("data pointer");
474       xbt_assert(pointer_type);
475     }
476
477     r_ref = xbt_malloc(pointer_type->size[r_arch]);
478
479     TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
480                             pointer_type->size[r_arch]));
481
482     /* Receive the pointed data only if not already sent */
483     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
484       VERB1("Not receiving data remotely referenced @%p since it's NULL",
485             *(void **)r_ref);
486       *(void**)l_data = NULL;
487       free(r_ref);
488       break;
489     }
490          
491     errcode = detect_cycle
492             ? xbt_dict_get_ext(refs,
493                                 (char*)r_ref, pointer_type->size[r_arch],
494                                 (void**)&l_ref)
495             : mismatch_error;
496
497     if (errcode == mismatch_error) {
498       int subsubcount = 0;
499       void *l_referenced=NULL;
500
501       VERB2("Receiving a ref to '%s', remotely @%p",
502             sub_type->name, *(void**)r_ref);
503       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
504         /* Damn. Reference to a dynamic array. Allocating the size for it 
505            is more complicated */
506         gras_dd_cat_array_t array_data = sub_type->category.array_data;
507         gras_datadesc_type_t subsub_type;
508
509         subsubcount = array_data.fixed_size;
510         if (subsubcount == 0)
511           TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
512
513         subsub_type = array_data.type;
514
515
516         TRY(gras_dd_alloc_ref(refs,
517                               subsub_type->size[GRAS_THISARCH] * subsubcount, 
518                               r_ref,pointer_type->size[r_arch], 
519                               (char**)&l_referenced,
520                               detect_cycle));
521       } else {
522         TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
523                               r_ref,pointer_type->size[r_arch], 
524                               (char**)&l_referenced,
525                               detect_cycle));
526       }
527
528       TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
529                                  r_arch,r_ref,pointer_type->size[r_arch],
530                                  (char*)l_referenced, subsubcount, 
531                                  detect_cycle || sub_type->cycle));
532       *(void**)l_data=l_referenced;
533       VERB3("'%s' remotely referenced at %p locally at %p",
534             sub_type->name, *(void**)r_ref, l_referenced);
535       
536     } else if (errcode == no_error) {
537       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
538             *(void**)r_ref, *(void**)l_ref);
539
540       *(void**)l_data=*l_ref;
541
542     } else {
543       return errcode;
544     }
545     free(r_ref);
546     break;
547   }
548
549   case e_gras_datadesc_type_cat_array: {
550     gras_dd_cat_array_t    array_data;
551     int       count;
552     char     *ptr;
553     long int  elm_size;
554
555     array_data = type->category.array_data;
556     /* determine element count locally, or from caller, or from peer */
557     count = array_data.fixed_size;
558     if (count == 0)
559       count = subsize;
560     if (count == 0)
561       TRY(gras_dd_recv_int(sock, r_arch, &count));
562     if (count == 0)
563       RAISE1(mismatch_error,
564              "Invalid (=0) array size for type %s",type->name);
565
566     /* receive the content */
567     sub_type = array_data.type;
568     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
569       VERB1("Array of %d scalars, get it in one shoot", count);
570       if (sub_type->aligned_size[GRAS_THISARCH] >= 
571           sub_type->aligned_size[r_arch]) {
572         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
573                                 sub_type->aligned_size[r_arch] * count));
574         if (r_arch != GRAS_THISARCH)
575           TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
576       } else {
577         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
578
579         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
580                                 sub_type->size[r_arch] * count));
581         if (r_arch != GRAS_THISARCH)
582           TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
583         free(ptr);
584       }
585     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
586                sub_type->category.array_data.fixed_size > 0 &&
587                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
588       gras_datadesc_type_t subsub_type;
589       array_data = sub_type->category.array_data;
590       subsub_type = array_data.type;
591        
592       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
593       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
594           subsub_type->aligned_size[r_arch]) {
595         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
596                                 subsub_type->aligned_size[r_arch] * count * 
597                                   array_data.fixed_size));
598         if (r_arch != GRAS_THISARCH)
599           TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data));
600       } else {
601         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
602
603         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
604                                 subsub_type->size[r_arch] * count*array_data.fixed_size));
605         if (r_arch != GRAS_THISARCH)
606           TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data));
607         free(ptr);
608       }
609       
610        
611     } else {
612       /* not scalar content, get it recursively (may contain pointers) */
613       elm_size = sub_type->aligned_size[GRAS_THISARCH];
614       VERB2("Receive a %d-long array of %s",count, sub_type->name);
615
616       ptr = l_data;
617       for (cpt=0; cpt<count; cpt++) {
618         TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
619                                    r_arch, NULL, 0, ptr,-1,
620                                    detect_cycle || sub_type->cycle));
621         ptr += elm_size;
622       }
623     }
624     break;
625   }
626         
627   default:
628     xbt_assert0(0, "Invalid type");
629   }
630   
631   if (type->recv)
632     type->recv(state,l_data);
633
634   return no_error;
635 }
636
637 /**
638  * gras_datadesc_recv:
639  *
640  * Get an instance of the datatype described by @type from the @socket, 
641  * and store a pointer to it in @dst
642  *
643  */
644 xbt_error_t
645 gras_datadesc_recv(gras_socket_t         sock, 
646                    gras_datadesc_type_t  type,
647                    int                   r_arch,
648                    void                 *dst) {
649
650   xbt_error_t errcode;
651   gras_cbps_t  state; /* callback persistent state */
652   xbt_dict_t  refs;  /* all references already sent */
653
654   refs = xbt_dict_new();
655   state = gras_cbps_new();
656
657   errcode = gras_datadesc_recv_rec(sock, state, refs, type, 
658                                    r_arch, NULL, 0,
659                                    (char *) dst,-1, 
660                                    type->cycle);
661
662   xbt_dict_free(&refs);
663   gras_cbps_free(&state);
664
665   return errcode;
666 }
667
668 #if 0
669 /***
670  *** IDL compiling functions
671  ***/
672
673 #define gras_datadesc_send_rec foo /* Just to make sure the copypast was ok */
674 #define gras_datadesc_send     foo /* Just to make sure the copypast was ok */
675 #define gras_datadesc_recv_rec foo /* Just to make sure the copypast was ok */
676 #define gras_datadesc_recv     foo /* Just to make sure the copypast was ok */
677
678 static xbt_error_t 
679 gras_datadesc_gen_send_rec(gras_socket_t         sock,
680                            gras_cbps_t           state,
681                            xbt_dict_t           refs,
682                            gras_datadesc_type_t  type, 
683                            char                 *data,
684                            int                   detect_cycle) {
685
686   xbt_error_t         errcode;
687   int                  cpt;
688   gras_datadesc_type_t sub_type; /* type on which we recurse */
689   
690   printf("  VERB2(\"Send a %s (%s)\");\n", 
691          type->name, gras_datadesc_cat_names[type->category_code]);
692
693   xbt_assert0(!type->send, "Callbacks not implemented in IDL compiler");
694
695   switch (type->category_code) {
696   case e_gras_datadesc_type_cat_scalar:
697     printf("  TRY(gras_trp_chunk_send(sock, data, %lu));\n",type->size[GRAS_THISARCH]);
698     break;
699
700   case e_gras_datadesc_type_cat_struct: {
701     gras_dd_cat_struct_t struct_data;
702     gras_dd_cat_field_t  field;
703     char                *field_data;
704     
705     struct_data = type->category.struct_data;
706     xbt_assert1(struct_data.closed,
707       "Please call gras_datadesc_declare_struct_close on %s before sending it",
708                 type->name);
709     printf("  VERB1(\">> Send all fields of the structure %s\");\n",type->name);
710     xbt_dynar_foreach(struct_data.fields, cpt, field) {
711       field_data = data;
712       field_data += field->offset[GRAS_THISARCH];
713       
714       sub_type = field->type;
715       
716       xbt_assert0(!field->pre, "Callbacks not implemented in IDL compiler");
717       
718       printf("  VERB1(\"Send field %s\");\n",field->name);
719       printf("  data += %lu;\n",field->offset[GRAS_THISARCH]);
720       TRY(gras_datadesc_gen_send_rec(sock,state,refs,sub_type, field_data, detect_cycle || sub_type->cycle));
721       printf("  data -= %lu;\n",field->offset[GRAS_THISARCH]);
722       
723       xbt_assert0(!field->post, "Callbacks not implemented in IDL compiler");
724     }
725     printf("  VERB1(\"<< Sent all fields of the structure %s\"", type->name);
726     
727     break;
728   }
729
730   case e_gras_datadesc_type_cat_union: {
731     gras_dd_cat_union_t union_data;
732     gras_dd_cat_field_t field=NULL;
733     int                 field_num;
734     
735     union_data = type->category.union_data;
736     
737     xbt_assert1(union_data.closed,
738                 "Please call gras_datadesc_declare_union_close on %s before sending it",
739                 type->name);
740     /* retrieve the field number */
741     printf("  field_num = union_data.selector(state, data);\n");
742     
743     printf("  xbt_assert0(field_num > 0,\n");
744     printf("              \"union field selector of %s gave a negative value\");\n",type->name);
745     
746     printf("  xbt_assert3(field_num < xbt_dynar_length(union_data.fields),\n");
747     printf("              \"union field selector of %s returned %%d but there is only %lu fields\",field_num);\n",
748                  type->name, xbt_dynar_length(union_data.fields));
749
750     /* Send the field number */
751     printf("TRY(gras_dd_send_int(sock, field_num));\n");
752     
753     /* Send the content */
754     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
755     sub_type = field->type;
756     
757     if (field->pre)
758       field->pre(state,data);
759     
760     TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, data, detect_cycle || sub_type->cycle));
761       
762     if (field->post)
763       field->post(state,data);
764     
765     break;
766   }
767     
768   case e_gras_datadesc_type_cat_ref: {
769     gras_dd_cat_ref_t      ref_data;
770
771     void                 **ref=(void**)data;
772     void *dummy;
773     
774     ref_data = type->category.ref_data;
775     
776     /* Detect the referenced type and send it to peer if needed */
777     sub_type = ref_data.type;
778     if (sub_type == NULL) {
779       sub_type = (*ref_data.selector)(state,data);
780       TRY(gras_dd_send_int(sock, sub_type->code));
781     }
782     
783     /* Send the actual value of the pointer for cycle handling */
784     if (!pointer_type) {
785       pointer_type = gras_datadesc_by_name("data pointer");
786       xbt_assert(pointer_type);
787     }
788      
789     TRY(gras_trp_chunk_send(sock, (char*)data,
790                             pointer_type->size[GRAS_THISARCH]));
791     
792     /* Send the pointed data only if not already sent */
793     if (*(void**)data == NULL) {
794       VERB0("Not sending NULL referenced data");
795       break;
796     }
797     errcode = detect_cycle 
798             ? xbt_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy)
799             : mismatch_error;
800     if (errcode == mismatch_error) {
801        VERB1("Sending data referenced at %p", (void*)*ref);
802        if (detect_cycle)
803          xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
804        TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, *ref, detect_cycle || sub_type->cycle));
805           
806     } else if (errcode == no_error) {
807        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
808     } else {
809        return errcode;
810     }
811     
812     break;
813   }
814
815   case e_gras_datadesc_type_cat_array: {
816     gras_dd_cat_array_t    array_data;
817     long int               count;
818     char                  *ptr=data;
819     long int               elm_size;
820     
821     array_data = type->category.array_data;
822     
823     /* determine and send the element count */
824     count = array_data.fixed_size;
825     if (count == 0) {
826       count = array_data.dynamic_size(state,data);
827       xbt_assert1(count >=0,
828                    "Invalid (negative) array size for type %s",type->name);
829       TRY(gras_dd_send_int(sock, count));
830     }
831     
832     /* send the content */
833     sub_type = array_data.type;
834     elm_size = sub_type->aligned_size[GRAS_THISARCH];
835     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
836       VERB1("Array of %ld scalars, send it in one shot",count);
837       TRY(gras_trp_chunk_send(sock, data, 
838                               sub_type->aligned_size[GRAS_THISARCH] * count));
839     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
840                sub_type->category.array_data.fixed_size > 0 &&
841                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
842        
843       VERB1("Array of %ld fixed array of scalars, send it in one shot",count);
844       TRY(gras_trp_chunk_send(sock, data, 
845                               sub_type->category.array_data.type->aligned_size[GRAS_THISARCH] 
846                                  * count * sub_type->category.array_data.fixed_size));
847        
848     } else {
849       for (cpt=0; cpt<count; cpt++) {
850         TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, ptr, detect_cycle || sub_type->cycle));
851         ptr += elm_size;
852       }
853     }
854     break;
855   }
856
857   default:
858     xbt_assert0(0, "Invalid type");
859   }
860
861   return no_error;
862 }
863
864 /**
865  * gras_datadesc_gen_send:
866  *
867  * Copy the data pointed by src and described by type to the socket
868  *
869  */
870 xbt_error_t gras_datadesc_gen_send(gras_socket_t        sock, 
871                                    gras_datadesc_type_t type, 
872                                    void *src) {
873
874   xbt_error_t errcode;
875   gras_cbps_t  state;
876   xbt_dict_t  refs; /* all references already sent */
877  
878   refs = xbt_dict_new();
879   state = gras_cbps_new();
880    
881   printf("xbt_error_t gras_%s_send(gras_socket_t sock,void *dst){\n",
882          type->name);
883   errcode = gras_datadesc_gen_send_rec(sock,state,refs,type,(char*)src, type->cycle);
884   printf("}\n");
885   
886   xbt_dict_free(&refs);
887   gras_cbps_free(&state);
888
889   return errcode;
890 }
891
892 /**
893  * gras_datadesc_gen_recv_rec:
894  *
895  * Do the data reception job recursively.
896  *
897  * subsize used only to deal with vicious case of reference to dynamic array.
898  *  This size is needed at the reference reception level (to allocate enough 
899  * space) and at the array reception level (to fill enough room). 
900  * 
901  * Having this size passed as an argument of the recursive function is a crude
902  * hack, but I was told that working code is sometimes better than neat one ;)
903  */
904 static xbt_error_t
905 gras_datadesc_gen_recv_rec(gras_socket_t         sock, 
906                            gras_cbps_t           state,
907                            xbt_dict_t           refs,
908                            gras_datadesc_type_t  type,
909                            int                   r_arch,
910                            char                **r_data,
911                            long int              r_lgr,
912                            char                 *l_data,
913                            int                   subsize,
914                            int                   detect_cycle) {
915
916   xbt_error_t         errcode;
917   int                  cpt;
918   gras_datadesc_type_t sub_type;
919
920   VERB2("Recv a %s @%p", type->name, (void*)l_data);
921   xbt_assert(l_data);
922
923   switch (type->category_code) {
924   case e_gras_datadesc_type_cat_scalar:
925     if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
926       TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
927       if (r_arch != GRAS_THISARCH)
928         TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
929     } else {
930       void *ptr = xbt_malloc(type->size[r_arch]);
931
932       TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
933       if (r_arch != GRAS_THISARCH)
934         TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
935       free(ptr);
936     }
937     break;
938
939   case e_gras_datadesc_type_cat_struct: {
940     gras_dd_cat_struct_t struct_data;
941     gras_dd_cat_field_t  field;
942
943     struct_data = type->category.struct_data;
944
945     xbt_assert1(struct_data.closed,
946                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
947                 type->name);
948     VERB1(">> Receive all fields of the structure %s",type->name);
949     xbt_dynar_foreach(struct_data.fields, cpt, field) {
950       char                 *field_data = l_data + field->offset[GRAS_THISARCH];
951
952       sub_type = field->type;
953
954       TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
955                                      r_arch,NULL,0,
956                                      field_data,-1, 
957                                      detect_cycle || sub_type->cycle));
958     }
959     VERB1("<< Received all fields of the structure %s", type->name);
960     
961     break;
962   }
963
964   case e_gras_datadesc_type_cat_union: {
965     gras_dd_cat_union_t union_data;
966     gras_dd_cat_field_t field=NULL;
967     int                 field_num;
968
969     union_data = type->category.union_data;
970
971     xbt_assert1(union_data.closed,
972                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
973                 type->name);
974     /* retrieve the field number */
975     TRY(gras_dd_recv_int(sock, r_arch, &field_num));
976     if (field_num < 0)
977       RAISE1(mismatch_error,
978              "Received union field for %s is negative", type->name);
979     if (field_num < xbt_dynar_length(union_data.fields)) 
980       RAISE3(mismatch_error,
981              "Received union field for %s is %d but there is only %lu fields",
982              type->name, field_num, xbt_dynar_length(union_data.fields));
983     
984     /* Recv the content */
985     field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
986     sub_type = field->type;
987     
988     TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
989                                    r_arch,NULL,0,
990                                    l_data,-1, 
991                                    detect_cycle || sub_type->cycle));
992     break;
993   }
994
995   case e_gras_datadesc_type_cat_ref: {
996     char             **r_ref = NULL;
997     char             **l_ref = NULL;
998     gras_dd_cat_ref_t  ref_data;
999     
1000     ref_data = type->category.ref_data;
1001
1002     /* Get the referenced type locally or from peer */
1003     sub_type = ref_data.type;
1004     if (sub_type == NULL) {
1005       int ref_code;
1006       TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
1007       TRY(gras_datadesc_by_id(ref_code, &sub_type));
1008     }
1009
1010     /* Get the actual value of the pointer for cycle handling */
1011     if (!pointer_type) {
1012       pointer_type = gras_datadesc_by_name("data pointer");
1013       xbt_assert(pointer_type);
1014     }
1015
1016     r_ref = xbt_malloc(pointer_type->size[r_arch]);
1017
1018     TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
1019                             pointer_type->size[r_arch]));
1020
1021     /* Receive the pointed data only if not already sent */
1022     if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
1023       VERB1("Not receiving data remotely referenced @%p since it's NULL",
1024             *(void **)r_ref);
1025       *(void**)l_data = NULL;
1026       free(r_ref);
1027       break;
1028     }
1029          
1030     errcode = detect_cycle
1031             ? xbt_dict_get_ext(refs,
1032                                 (char*)r_ref, pointer_type->size[r_arch],
1033                                 (void**)&l_ref)
1034             : mismatch_error;
1035
1036     if (errcode == mismatch_error) {
1037       int subsubcount = 0;
1038       void *l_referenced=NULL;
1039
1040       VERB2("Receiving a ref to '%s', remotely @%p",
1041             sub_type->name, *(void**)r_ref);
1042       if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
1043         /* Damn. Reference to a dynamic array. Allocating the size for it 
1044            is more complicated */
1045         gras_dd_cat_array_t array_data = sub_type->category.array_data;
1046         gras_datadesc_type_t subsub_type;
1047
1048         subsubcount = array_data.fixed_size;
1049         if (subsubcount == 0)
1050           TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
1051
1052         subsub_type = array_data.type;
1053
1054
1055         TRY(gras_dd_alloc_ref(refs,
1056                               subsub_type->size[GRAS_THISARCH] * subsubcount, 
1057                               r_ref,pointer_type->size[r_arch], 
1058                               (char**)&l_referenced,
1059                               detect_cycle));
1060       } else {
1061         TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
1062                               r_ref,pointer_type->size[r_arch], 
1063                               (char**)&l_referenced,
1064                               detect_cycle));
1065       }
1066
1067       TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1068                                      r_arch,r_ref,pointer_type->size[r_arch],
1069                                      (char*)l_referenced, subsubcount, 
1070                                      detect_cycle || sub_type->cycle));
1071       *(void**)l_data=l_referenced;
1072       VERB3("'%s' remotely referenced at %p locally at %p",
1073             sub_type->name, *(void**)r_ref, l_referenced);
1074       
1075     } else if (errcode == no_error) {
1076       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
1077             *(void**)r_ref, *(void**)l_ref);
1078
1079       *(void**)l_data=*l_ref;
1080
1081     } else {
1082       return errcode;
1083     }
1084     free(r_ref);
1085     break;
1086   }
1087
1088   case e_gras_datadesc_type_cat_array: {
1089     gras_dd_cat_array_t    array_data;
1090     int       count;
1091     char     *ptr;
1092     long int  elm_size;
1093
1094     array_data = type->category.array_data;
1095     /* determine element count locally, or from caller, or from peer */
1096     count = array_data.fixed_size;
1097     if (count == 0)
1098       count = subsize;
1099     if (count == 0)
1100       TRY(gras_dd_recv_int(sock, r_arch, &count));
1101     if (count == 0)
1102       RAISE1(mismatch_error,
1103              "Invalid (=0) array size for type %s",type->name);
1104
1105     /* receive the content */
1106     sub_type = array_data.type;
1107     if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
1108       VERB1("Array of %d scalars, get it in one shoot", count);
1109       if (sub_type->aligned_size[GRAS_THISARCH] >= 
1110           sub_type->aligned_size[r_arch]) {
1111         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
1112                                 sub_type->aligned_size[r_arch] * count));
1113         if (r_arch != GRAS_THISARCH)
1114           TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
1115       } else {
1116         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
1117
1118         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
1119                                 sub_type->size[r_arch] * count));
1120         if (r_arch != GRAS_THISARCH)
1121           TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
1122         free(ptr);
1123       }
1124     } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
1125                sub_type->category.array_data.fixed_size > 0 &&
1126                sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
1127       gras_datadesc_type_t subsub_type;
1128       array_data = sub_type->category.array_data;
1129       subsub_type = array_data.type;
1130        
1131       VERB1("Array of %d fixed array of scalars, get it in one shot",count);
1132       if (subsub_type->aligned_size[GRAS_THISARCH] >= 
1133           subsub_type->aligned_size[r_arch]) {
1134         TRY(gras_trp_chunk_recv(sock, (char*)l_data, 
1135                                 subsub_type->aligned_size[r_arch] * count * 
1136                                   array_data.fixed_size));
1137         if (r_arch != GRAS_THISARCH)
1138           TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data));
1139       } else {
1140         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
1141
1142         TRY(gras_trp_chunk_recv(sock, (char*)ptr, 
1143                                 subsub_type->size[r_arch] * count*array_data.fixed_size));
1144         if (r_arch != GRAS_THISARCH)
1145           TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data));
1146         free(ptr);
1147       }
1148       
1149        
1150     } else {
1151       /* not scalar content, get it recursively (may contain pointers) */
1152       elm_size = sub_type->aligned_size[GRAS_THISARCH];
1153       VERB2("Receive a %d-long array of %s",count, sub_type->name);
1154
1155       ptr = l_data;
1156       for (cpt=0; cpt<count; cpt++) {
1157         TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1158                                        r_arch, NULL, 0, ptr,-1,
1159                                        detect_cycle || sub_type->cycle));
1160         ptr += elm_size;
1161       }
1162     }
1163     break;
1164   }
1165         
1166   default:
1167     xbt_assert0(0, "Invalid type");
1168   }
1169   
1170   if (type->recv)
1171     type->recv(state,l_data);
1172
1173   return no_error;
1174 }
1175
1176 /**
1177  * gras_datadesc_gen_recv:
1178  *
1179  * Get an instance of the datatype described by @type from the @socket, 
1180  * and store a pointer to it in @dst
1181  *
1182  */
1183 xbt_error_t
1184 gras_datadesc_gen_recv(gras_socket_t         sock, 
1185                        gras_datadesc_type_t  type,
1186                        int                   r_arch,
1187                        void                 *dst) {
1188
1189   xbt_error_t errcode;
1190   gras_cbps_t  state; /* callback persistent state */
1191   xbt_dict_t  refs;  /* all references already sent */
1192
1193   refs = xbt_dict_new();
1194   state = gras_cbps_new();
1195
1196   printf("xbt_error_t gras_%s_recv(gras_socket_t sock,void *dst){\n",
1197          type->name);
1198    
1199   errcode = gras_datadesc_gen_recv_rec(sock, state, refs, type, 
1200                                        r_arch, NULL, 0,
1201                                        (char *) dst,-1, 
1202                                        type->cycle);
1203
1204   printf("}\n");
1205   xbt_dict_free(&refs);
1206   gras_cbps_free(&state);
1207
1208   return errcode;
1209 }
1210 #endif