Logo AND Algorithmique Numérique Distribuée

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