Logo AND Algorithmique Numérique Distribuée

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