Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add regression tests for the lastly fixed bugs in GRAS dadadesc
[simgrid.git] / src / gras / DataDesc / ddt_exchange.c
1 /* $Id$ */
2
3 /* ddt_exchange - send/recv data described                                  */
4
5 /* Copyright (c) 2003-2009 The SimGrid Team.  All rights reserved.          */
6
7 /* This program is free software; you can redistribute it and/or modify it
8  * under the terms of the license (GNU LGPL) which comes with this package. */
9
10 #include "xbt/ex.h"
11 #include "gras/DataDesc/datadesc_private.h"
12 #include "gras/Transport/transport_interface.h" /* gras_trp_send/recv */
13
14 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(gras_ddt_exchange,gras_ddt,
15                 "Sending data over the network");
16 const char *gras_datadesc_cat_names[9] = {
17                 "undefined",
18                 "scalar", "struct", "union", "ref", "array", "ignored",
19                 "invalid"};
20
21 static gras_datadesc_type_t int_type = NULL;
22 static gras_datadesc_type_t pointer_type = NULL;
23
24 static XBT_INLINE void
25 gras_dd_send_int(gras_socket_t sock, int *i, int stable) {
26
27         if (!int_type) {
28                 int_type = gras_datadesc_by_name("int");
29                 xbt_assert(int_type);
30         }
31
32         DEBUG1("send_int(%u)",*i);
33         gras_trp_send(sock, (char*)i, int_type->size[GRAS_THISARCH], stable);
34 }
35
36 static XBT_INLINE void
37 gras_dd_recv_int(gras_socket_t sock, int r_arch, int *i) {
38
39         if (!int_type) {
40                 int_type = gras_datadesc_by_name("int");
41                 xbt_assert(int_type);
42         }
43
44         if (int_type->size[GRAS_THISARCH] >= int_type->size[r_arch]) {
45                 gras_trp_recv(sock, (char*)i, int_type->size[r_arch]);
46                 if (r_arch != GRAS_THISARCH)
47                         gras_dd_convert_elm(int_type,1,r_arch, i,i);
48         } else {
49                 void *ptr = xbt_malloc(int_type->size[r_arch]);
50
51                 gras_trp_recv(sock, (char*)ptr, int_type->size[r_arch]);
52                 if (r_arch != GRAS_THISARCH)
53                         gras_dd_convert_elm(int_type,1,r_arch, ptr,i);
54                 free(ptr);
55         }
56         DEBUG1("recv_int(%u)",*i);
57 }
58
59 /*
60  * Note: here we suppose that the remote NULL is a sequence
61  *       of 'length' bytes set to 0.
62  * FIXME: Check in configure?
63  */
64 static XBT_INLINE int
65 gras_dd_is_r_null(char **r_ptr, long int length) {
66         int i;
67
68         for (i=0; i<length; i++) {
69                 if ( ((unsigned char*)r_ptr) [i]) {
70                         return 0;
71                 }
72         }
73
74         return 1;
75 }
76
77 static XBT_INLINE void
78 gras_dd_alloc_ref(xbt_dict_t  refs,
79                 long int     size,
80                 char       **r_ref,
81                 long int     r_len, /* pointer_type->size[r_arch] */
82                 char         **l_ref,
83                 int          detect_cycle) {
84         char *l_data = NULL;
85
86         xbt_assert1(size>0,"Cannot allocate %ld bytes!", size);
87         l_data = xbt_malloc((size_t)size);
88
89         *l_ref = l_data;
90         DEBUG5("alloc_ref: l_data=%p, &l_data=%p; r_ref=%p; *r_ref=%p, r_len=%ld",
91                         (void*)l_data,(void*)&l_data,
92                         (void*)r_ref, (void*)(r_ref?*r_ref:NULL), r_len);
93         if (detect_cycle && r_ref && !gras_dd_is_r_null( r_ref, r_len)) {
94                 void *ptr = xbt_malloc(sizeof(void *));
95
96                 memcpy(ptr,l_ref, sizeof(void *));
97
98                 DEBUG2("Insert l_ref=%p under r_ref=%p",*(void**)ptr, *(void**)r_ref);
99
100                 if (detect_cycle)
101                         xbt_dict_set_ext(refs,(const char *) r_ref, r_len, ptr, xbt_free_f);
102         }
103 }
104
105 static int
106 gras_datadesc_memcpy_rec(gras_cbps_t           state,
107                 xbt_dict_t            refs,
108                 gras_datadesc_type_t  type,
109                 char                 *src,
110                 char                 *dst,
111                 int                   subsize,
112                 int                   detect_cycle) {
113
114
115         xbt_ex_t             e;
116         unsigned int         cpt;
117         gras_datadesc_type_t sub_type; /* type on which we recurse */
118         int count = 0;
119
120         VERB5("Copy a %s (%s) from %p to %p (local sizeof=%ld)",
121                         type->name, gras_datadesc_cat_names[type->category_code],
122                         src,dst,type->size[GRAS_THISARCH]);
123
124         if (type->send) {
125                 type->send(type,state,src);
126         }
127
128         switch (type->category_code) {
129         case e_gras_datadesc_type_cat_scalar:
130                 memcpy(dst,src,type->size[GRAS_THISARCH]);
131                 count += type->size[GRAS_THISARCH];
132                 break;
133
134         case e_gras_datadesc_type_cat_struct: {
135                 gras_dd_cat_struct_t struct_data;
136                 gras_dd_cat_field_t  field;
137                 char                *field_src;
138                 char                *field_dst;
139
140                 struct_data = type->category.struct_data;
141                 xbt_assert1(struct_data.closed,
142                                 "Please call gras_datadesc_declare_struct_close on %s before copying it",
143                                 type->name);
144                 VERB1(">> Copy all fields of the structure %s",type->name);
145                 xbt_dynar_foreach(struct_data.fields, cpt, field) {
146                         field_src = src + field->offset[GRAS_THISARCH];
147                         field_dst = dst + field->offset[GRAS_THISARCH];
148
149                         sub_type = field->type;
150
151                         if (field->send)
152                                 field->send(type,state,field_src);
153
154                         DEBUG1("Copy field %s",field->name);
155                         count += gras_datadesc_memcpy_rec(state,refs,sub_type, field_src, field_dst, 0,
156                                         detect_cycle || sub_type->cycle);
157
158                         if (XBT_LOG_ISENABLED(gras_ddt_exchange,xbt_log_priority_verbose)) {
159                                 if (sub_type == gras_datadesc_by_name("unsigned int")) {
160                                         VERB2("Copied value for field '%s': %d (type: unsigned int)",field->name, *(unsigned int*)field_dst);
161                                 } else if (sub_type == gras_datadesc_by_name("int")) {
162                                         VERB2("Copied value for field '%s': %d (type: int)",field->name, *(int*)field_dst);
163
164                                 } else if (sub_type == gras_datadesc_by_name("unsigned long int")) {
165                                         VERB2("Copied value for field '%s': %ld (type: unsigned long int)",field->name, *(unsigned long int*)field_dst);
166                                 } else if (sub_type == gras_datadesc_by_name("long int")) {
167                                         VERB2("Copied value for field '%s': %ld (type: long int)",field->name, *(long int*)field_dst);
168
169                                 } else if (sub_type == gras_datadesc_by_name("string")) {
170                                         VERB2("Copied value for field '%s': '%s' (type: string)", field->name, *(char**)field_dst);
171                                 } else {
172                                         VERB1("Copied a value for field '%s' (type not scalar?)", field->name);
173                                 }
174                         }
175
176                 }
177                 VERB1("<< Copied all fields of the structure %s", type->name);
178
179                 break;
180         }
181
182         case e_gras_datadesc_type_cat_union: {
183                 gras_dd_cat_union_t union_data;
184                 gras_dd_cat_field_t field=NULL;
185                 unsigned int        field_num;
186
187                 union_data = type->category.union_data;
188
189                 xbt_assert1(union_data.closed,
190                                 "Please call gras_datadesc_declare_union_close on %s before copying it",
191                                 type->name);
192                 /* retrieve the field number */
193                 field_num = union_data.selector(type, state, src);
194
195                 xbt_assert1(field_num > 0,
196                                 "union field selector of %s gave a negative value",
197                                 type->name);
198
199                 xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
200                                 "union field selector of %s returned %d but there is only %lu fields",
201                                 type->name, field_num, xbt_dynar_length(union_data.fields));
202
203                 /* Copy the content */
204                 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
205                 sub_type = field->type;
206
207                 if (field->send)
208                         field->send(type,state,src);
209
210                 count += gras_datadesc_memcpy_rec(state,refs, sub_type, src, dst,0,
211                                 detect_cycle || sub_type->cycle);
212
213                 break;
214         }
215
216         case e_gras_datadesc_type_cat_ref: {
217                 gras_dd_cat_ref_t      ref_data;
218                 char                 **o_ref=NULL;
219                 char                 **n_ref=NULL;
220                 int                    reference_is_to_cpy;
221
222                 ref_data = type->category.ref_data;
223
224                 /* Detect the referenced type */
225                 sub_type = ref_data.type;
226                 if (sub_type == NULL) {
227                         sub_type = (*ref_data.selector)(type,state,src);
228                 }
229
230                 /* Send the pointed data only if not already sent */
231                 if (*(void**)src == NULL) {
232                         VERB0("Not copying NULL referenced data");
233                         *(void**)dst = NULL;
234                         break;
235                 }
236                 o_ref=(char**)src;
237
238                 reference_is_to_cpy = 0;
239                 TRY {
240                         if (detect_cycle) {
241                                 /* return ignored. Just checking whether it's known or not */
242                                 n_ref=xbt_dict_get_ext(refs,(char*)o_ref, sizeof(char*));
243                         } else {
244                                 reference_is_to_cpy = 1;
245                         }
246                 } CATCH(e) {
247                         if (e.category != not_found_error)
248                                 RETHROW;
249                         reference_is_to_cpy = 1;
250                         xbt_ex_free(e);
251                 }
252
253                 if (reference_is_to_cpy) {
254                         int subsubcount = -1;
255                         void *l_referenced=NULL;
256                         VERB2("Copy a ref to '%s' referenced at %p",sub_type->name, (void*)*o_ref);
257
258                         if (!pointer_type) {
259                                 pointer_type = gras_datadesc_by_name("data pointer");
260                                 xbt_assert(pointer_type);
261                         }
262
263                         if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
264                                 /* Damn. Reference to a dynamic array. Allocating the space for it is more complicated */
265                                 gras_dd_cat_array_t array_data = sub_type->category.array_data;
266                                 gras_datadesc_type_t subsub_type;
267
268                                 subsub_type = array_data.type;
269                                 subsubcount = array_data.fixed_size;
270                                 if (subsubcount == -1)
271                                         subsubcount = array_data.dynamic_size(subsub_type,state,*o_ref);
272
273                                 if (subsubcount != 0)
274                                         gras_dd_alloc_ref(refs,
275                                                         subsub_type->size[GRAS_THISARCH] * subsubcount,
276                                                         o_ref,pointer_type->size[GRAS_THISARCH],
277                                                         (char**)&l_referenced,
278                                                         detect_cycle);
279                         } else {
280                                 gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
281                                                 o_ref,pointer_type->size[GRAS_THISARCH],
282                                                 (char**)&l_referenced,
283                                                 detect_cycle);
284                         }
285
286                         count += gras_datadesc_memcpy_rec(state,refs, sub_type,
287                                         *o_ref,(char*)l_referenced, subsubcount,
288                                         detect_cycle || sub_type->cycle);
289
290                         *(void**)dst=l_referenced;
291                         VERB3("'%s' previously referenced at %p now at %p",
292                                         sub_type->name, *(void**)o_ref, l_referenced);
293
294                 } else {
295                         VERB2("NOT copying data previously referenced @%p (already done, @%p now)",
296                                         *(void**)o_ref, *(void**)n_ref);
297
298                         *(void**)dst=*n_ref;
299
300                 }
301                 break;
302         }
303
304         case e_gras_datadesc_type_cat_array: {
305                 gras_dd_cat_array_t    array_data;
306                 unsigned long int     array_count;
307                 char                  *src_ptr=src;
308                 char                  *dst_ptr=dst;
309                 long int               elm_size;
310
311                 array_data = type->category.array_data;
312
313                 /* determine and send the element count */
314                 array_count = array_data.fixed_size;
315                 if (array_count == -1)
316                         array_count = subsize;
317                 if (array_count == -1) {
318                         array_count = array_data.dynamic_size(type,state,src);
319                         xbt_assert1(array_count >=0,
320                                         "Invalid (negative) array size for type %s",type->name);
321                 }
322
323                 /* send the content */
324                 sub_type = array_data.type;
325                 elm_size = sub_type->aligned_size[GRAS_THISARCH];
326                 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
327                         VERB1("Array of %ld scalars, copy it in one shot",array_count);
328                         memcpy(dst, src, sub_type->aligned_size[GRAS_THISARCH] * array_count);
329                         count += sub_type->aligned_size[GRAS_THISARCH] * array_count;
330                 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
331                                 sub_type->category.array_data.fixed_size > 0 &&
332                                 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
333
334                         VERB1("Array of %ld fixed array of scalars, copy it in one shot",
335                                         array_count);
336                         memcpy(dst,src,sub_type->category.array_data.type->aligned_size[GRAS_THISARCH]
337                                                                                         * array_count * sub_type->category.array_data.fixed_size);
338                         count += sub_type->category.array_data.type->aligned_size[GRAS_THISARCH]
339                                                                                   * array_count * sub_type->category.array_data.fixed_size;
340
341                 } else {
342                         VERB1("Array of %ld stuff, copy it in one after the other",array_count);
343                         for (cpt=0; cpt<array_count; cpt++) {
344                                 VERB2("Copy the %dth stuff out of %ld",cpt,array_count);
345                                 count += gras_datadesc_memcpy_rec(state,refs, sub_type, src_ptr, dst_ptr, 0,
346                                                 detect_cycle || sub_type->cycle);
347                                 src_ptr += elm_size;
348                                 dst_ptr += elm_size;
349                         }
350                 }
351                 break;
352         }
353
354         default:
355                 xbt_die("Invalid type");
356         }
357
358         return count;
359 }
360 /**
361  * gras_datadesc_memcpy:
362  *
363  * Copy the data pointed by src and described by type
364  * to a new location, and store a pointer to it in dst.
365  *
366  */
367 int gras_datadesc_memcpy(gras_datadesc_type_t type,
368                 void *src, void *dst) {
369         xbt_ex_t e;
370         static gras_cbps_t state=NULL;
371         static xbt_dict_t  refs=NULL; /* all references already sent */
372         int size=0;
373
374         xbt_assert0(type,"called with NULL type descriptor");
375
376         DEBUG3("Memcopy a %s from %p to %p",gras_datadesc_get_name(type),src,dst);
377         if (!state) {
378                 state = gras_cbps_new();
379                 refs = xbt_dict_new();
380         }
381
382         TRY {
383                 size = gras_datadesc_memcpy_rec(state,refs,type,(char*)src,(char*)dst,0,
384                                 type->cycle);
385         } CLEANUP {
386                 xbt_dict_reset(refs);
387                 gras_cbps_reset(state);
388         } CATCH(e) {
389                 RETHROW;
390         }
391         return size;
392 }
393
394 /***
395  *** Direct use functions
396  ***/
397
398 static void
399 gras_datadesc_send_rec(gras_socket_t         sock,
400                 gras_cbps_t           state,
401                 xbt_dict_t            refs,
402                 gras_datadesc_type_t  type,
403                 char                 *data,
404                 int                   detect_cycle) {
405
406         xbt_ex_t             e;
407         unsigned int         cpt;
408         gras_datadesc_type_t sub_type; /* type on which we recurse */
409
410         VERB2("Send a %s (%s)",
411                         type->name, gras_datadesc_cat_names[type->category_code]);
412
413         if (!strcmp(type->name,"string"))
414                 VERB1("value: '%s'",*(char**)data);
415
416         if (type->send) {
417                 type->send(type,state,data);
418                 DEBUG0("Run the emission callback");
419         }
420
421         switch (type->category_code) {
422         case e_gras_datadesc_type_cat_scalar:
423                 gras_trp_send(sock, data, type->size[GRAS_THISARCH], 1);
424                 break;
425
426         case e_gras_datadesc_type_cat_struct: {
427                 gras_dd_cat_struct_t struct_data;
428                 gras_dd_cat_field_t  field;
429                 char                *field_data;
430
431                 struct_data = type->category.struct_data;
432                 xbt_assert1(struct_data.closed,
433                                 "Please call gras_datadesc_declare_struct_close on %s before sending it",
434                                 type->name);
435                 VERB1(">> Send all fields of the structure %s",type->name);
436                 xbt_dynar_foreach(struct_data.fields, cpt, field) {
437                         field_data = data;
438                         field_data += field->offset[GRAS_THISARCH];
439
440                         sub_type = field->type;
441
442                         if (field->send) {
443                                 DEBUG1("Run the emission callback of field %s", field->name);
444                                 field->send(type,state,field_data);
445                         }
446
447                         VERB1("Send field %s",field->name);
448                         gras_datadesc_send_rec(sock,state,refs,sub_type, field_data,
449                                         detect_cycle || sub_type->cycle);
450
451                 }
452                 VERB1("<< Sent all fields of the structure %s", type->name);
453
454                 break;
455         }
456
457         case e_gras_datadesc_type_cat_union: {
458                 gras_dd_cat_union_t union_data;
459                 gras_dd_cat_field_t field=NULL;
460                 int field_num;
461
462                 union_data = type->category.union_data;
463
464                 xbt_assert1(union_data.closed,
465                                 "Please call gras_datadesc_declare_union_close on %s before sending it",
466                                 type->name);
467                 /* retrieve the field number */
468                 field_num = union_data.selector(type, state, data);
469
470                 xbt_assert1(field_num > 0,
471                                 "union field selector of %s gave a negative value",
472                                 type->name);
473
474                 xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
475                                 "union field selector of %s returned %d but there is only %lu fields",
476                                 type->name, field_num, xbt_dynar_length(union_data.fields));
477
478                 /* Send the field number */
479                 gras_dd_send_int(sock, &field_num, 0 /* not stable */);
480
481                 /* Send the content */
482                 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
483                 sub_type = field->type;
484
485                 if (field->send)
486                         field->send(type,state,data);
487
488                 gras_datadesc_send_rec(sock,state,refs, sub_type, data,
489                                 detect_cycle || sub_type->cycle);
490
491                 break;
492         }
493
494         case e_gras_datadesc_type_cat_ref: {
495                 gras_dd_cat_ref_t      ref_data;
496                 void                 **ref=(void**)data;
497                 int                    reference_is_to_send;
498
499                 ref_data = type->category.ref_data;
500
501                 /* Detect the referenced type and send it to peer if needed */
502                 sub_type = ref_data.type;
503                 if (sub_type == NULL) {
504                         sub_type = (*ref_data.selector)(type,state,data);
505                         gras_dd_send_int(sock, &(sub_type->code),1 /*stable*/);
506                 }
507
508                 /* Send the actual value of the pointer for cycle handling */
509                 if (!pointer_type) {
510                         pointer_type = gras_datadesc_by_name("data pointer");
511                         xbt_assert(pointer_type);
512                 }
513
514                 gras_trp_send(sock, (char*)data,
515                                 pointer_type->size[GRAS_THISARCH], 1 /*stable*/);
516
517                 /* Send the pointed data only if not already sent */
518                 if (*(void**)data == NULL) {
519                         VERB0("Not sending NULL referenced data");
520                         break;
521                 }
522
523                 reference_is_to_send = 0;
524                 TRY {
525                         if (detect_cycle)
526                                 /* return ignored. Just checking whether it's known or not */
527                                 xbt_dict_get_ext(refs,(char*)ref, sizeof(char*));
528                         else
529                                 reference_is_to_send = 1;
530                 } CATCH(e) {
531                         if (e.category != not_found_error)
532                                 RETHROW;
533                         reference_is_to_send = 1;
534                         xbt_ex_free(e);
535                 }
536
537                 if (reference_is_to_send) {
538                         VERB1("Sending data referenced at %p", (void*)*ref);
539                         if (detect_cycle)
540                                 xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
541                         gras_datadesc_send_rec(sock,state,refs, sub_type, *ref,
542                                         detect_cycle || sub_type->cycle);
543
544                 } else {
545                         VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
546                 }
547
548                 break;
549         }
550
551         case e_gras_datadesc_type_cat_array: {
552                 gras_dd_cat_array_t    array_data;
553                 int                    count;
554                 char                  *ptr=data;
555                 long int               elm_size;
556
557                 array_data = type->category.array_data;
558
559                 /* determine and send the element count */
560                 count = array_data.fixed_size;
561                 if (count == -1) {
562                         count = array_data.dynamic_size(type,state,data);
563                         xbt_assert1(count >=0,
564                                         "Invalid (negative) array size for type %s",type->name);
565                         gras_dd_send_int(sock, &count, 0/*non-stable*/);
566                 }
567
568                 /* send the content */
569                 sub_type = array_data.type;
570                 elm_size = sub_type->aligned_size[GRAS_THISARCH];
571                 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
572                         VERB1("Array of %d scalars, send it in one shot",count);
573                         gras_trp_send(sock, data,
574                                         sub_type->aligned_size[GRAS_THISARCH] * count,
575                                         0 /* not stable */);
576                 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
577                                 sub_type->category.array_data.fixed_size > 0 &&
578                                 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
579
580                         VERB1("Array of %d fixed array of scalars, send it in one shot",count);
581                         gras_trp_send(sock, data,
582                                         sub_type->category.array_data.type->aligned_size[GRAS_THISARCH]
583                                                                                          * count * sub_type->category.array_data.fixed_size,
584                                                                                          0 /* not stable */);
585
586                 } else {
587                         for (cpt=0; cpt<count; cpt++) {
588                                 gras_datadesc_send_rec(sock,state,refs, sub_type, ptr,
589                                                 detect_cycle || sub_type->cycle);
590                                 ptr += elm_size;
591                         }
592                 }
593                 break;
594         }
595
596         default:
597                 xbt_die("Invalid type");
598         }
599 }
600
601 /**
602  * gras_datadesc_send:
603  *
604  * Copy the data pointed by src and described by type to the socket
605  *
606  */
607 void gras_datadesc_send(gras_socket_t        sock,
608                 gras_datadesc_type_t type,
609                 void *src) {
610
611         xbt_ex_t e;
612         static gras_cbps_t state=NULL;
613         static xbt_dict_t  refs=NULL; /* all references already sent */
614
615         xbt_assert0(type,"called with NULL type descriptor");
616
617         if (!state) {
618                 state = gras_cbps_new();
619                 refs = xbt_dict_new();
620         }
621
622         TRY {
623                 gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
624         } CLEANUP {
625                 xbt_dict_reset(refs);
626                 gras_cbps_reset(state);
627         } CATCH(e) {
628                 RETHROW;
629         }
630 }
631
632 /**
633  * gras_datadesc_recv_rec:
634  *
635  * Do the data reception job recursively.
636  *
637  * subsize used only to deal with vicious case of reference to dynamic array.
638  *  This size is needed at the reference reception level (to allocate enough
639  * space) and at the array reception level (to fill enough room).
640  *
641  * Having this size passed as an argument of the recursive function is a crude
642  * hack, but I was told that working code is sometimes better than neat one ;)
643  */
644 static void
645 gras_datadesc_recv_rec(gras_socket_t         sock,
646                 gras_cbps_t           state,
647                 xbt_dict_t           refs,
648                 gras_datadesc_type_t  type,
649                 int                   r_arch,
650                 char                **r_data,
651                 long int              r_lgr,
652                 char                 *l_data,
653                 int                   subsize,
654                 int                   detect_cycle) {
655
656         unsigned int         cpt;
657         gras_datadesc_type_t sub_type;
658         xbt_ex_t e;
659
660         VERB2("Recv a %s @%p", type->name, (void*)l_data);
661         xbt_assert(l_data);
662
663         switch (type->category_code) {
664         case e_gras_datadesc_type_cat_scalar:
665                 if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
666                         gras_trp_recv(sock, (char*)l_data, type->size[r_arch]);
667                         if (r_arch != GRAS_THISARCH)
668                                 gras_dd_convert_elm(type,1,r_arch, l_data,l_data);
669                 } else {
670                         void *ptr = xbt_malloc(type->size[r_arch]);
671
672                         gras_trp_recv(sock, (char*)ptr, type->size[r_arch]);
673                         if (r_arch != GRAS_THISARCH)
674                                 gras_dd_convert_elm(type,1,r_arch, ptr,l_data);
675                         free(ptr);
676                 }
677                 break;
678
679         case e_gras_datadesc_type_cat_struct: {
680                 gras_dd_cat_struct_t struct_data;
681                 gras_dd_cat_field_t  field;
682
683                 struct_data = type->category.struct_data;
684
685                 xbt_assert1(struct_data.closed,
686                                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
687                                 type->name);
688                 VERB1(">> Receive all fields of the structure %s",type->name);
689                 xbt_dynar_foreach(struct_data.fields, cpt, field) {
690                         char                 *field_data = l_data + field->offset[GRAS_THISARCH];
691
692                         sub_type = field->type;
693
694                         gras_datadesc_recv_rec(sock,state,refs, sub_type,
695                                         r_arch,NULL,0,
696                                         field_data,-1,
697                                         detect_cycle || sub_type->cycle);
698
699                         if (field->recv) {
700                                 DEBUG1("Run the reception callback of field %s", field->name);
701                                 field->recv(type,state,(void*)l_data);
702                         }
703
704                 }
705                 VERB1("<< Received all fields of the structure %s", type->name);
706
707                 break;
708         }
709
710         case e_gras_datadesc_type_cat_union: {
711                 gras_dd_cat_union_t union_data;
712                 gras_dd_cat_field_t field=NULL;
713                 int field_num;
714
715                 union_data = type->category.union_data;
716
717                 xbt_assert1(union_data.closed,
718                                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
719                                 type->name);
720                 /* retrieve the field number */
721                 gras_dd_recv_int(sock, r_arch, &field_num);
722                 if (field_num < 0)
723                         THROW1(mismatch_error,0,
724                                         "Received union field for %s is negative", type->name);
725                 if (field_num > xbt_dynar_length(union_data.fields))
726                         THROW3(mismatch_error,0,
727                                         "Received union field for %s is said to be #%d but there is only %lu fields",
728                                         type->name, field_num, xbt_dynar_length(union_data.fields));
729
730                 /* Recv the content */
731                 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
732                 sub_type = field->type;
733
734                 gras_datadesc_recv_rec(sock,state,refs, sub_type,
735                                 r_arch,NULL,0,
736                                 l_data,-1,
737                                 detect_cycle || sub_type->cycle);
738                 if (field->recv)
739                         field->recv(type,state,l_data);
740
741                 break;
742         }
743
744         case e_gras_datadesc_type_cat_ref: {
745                 char             **r_ref = NULL;
746                 char             **l_ref = NULL;
747                 gras_dd_cat_ref_t  ref_data;
748                 int reference_is_to_recv = 0;
749
750                 ref_data = type->category.ref_data;
751
752                 /* Get the referenced type locally or from peer */
753                 sub_type = ref_data.type;
754                 if (sub_type == NULL) {
755                         int ref_code;
756                         gras_dd_recv_int(sock, r_arch, &ref_code);
757                         sub_type = gras_datadesc_by_id(ref_code);
758                 }
759
760                 /* Get the actual value of the pointer for cycle handling */
761                 if (!pointer_type) {
762                         pointer_type = gras_datadesc_by_name("data pointer");
763                         xbt_assert(pointer_type);
764                 }
765
766                 r_ref = xbt_malloc(pointer_type->size[r_arch]);
767
768                 gras_trp_recv(sock, (char*)r_ref,
769                                 pointer_type->size[r_arch]);
770
771                 /* Receive the pointed data only if not already sent */
772                 if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
773                         VERB1("Not receiving data remotely referenced @%p since it's NULL",
774                                         *(void **)r_ref);
775                         *(void**)l_data = NULL;
776                         free(r_ref);
777                         break;
778                 }
779
780                 reference_is_to_recv = 0;
781                 TRY {
782                         if (detect_cycle) {
783                                 l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
784                         } else {
785                                 reference_is_to_recv = 1;
786                         }
787                 } CATCH(e) {
788                         if (e.category != not_found_error)
789                                 RETHROW;
790                         reference_is_to_recv = 1;
791                         xbt_ex_free(e);
792                 }
793
794                 if (reference_is_to_recv) {
795                         int subsubcount = -1;
796                         void *l_referenced=NULL;
797
798                         VERB2("Receiving a ref to '%s', remotely @%p",
799                                         sub_type->name, *(void**)r_ref);
800                         if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
801                                 /* Damn. Reference to a dynamic array. Allocating the space for it is more complicated */
802                                 gras_dd_cat_array_t array_data = sub_type->category.array_data;
803                                 gras_datadesc_type_t subsub_type;
804
805                                 subsubcount = array_data.fixed_size;
806                                 if (subsubcount == -1)
807                                         gras_dd_recv_int(sock, r_arch, &subsubcount);
808
809                                 subsub_type = array_data.type;
810
811                                 if (subsubcount != 0)
812                                         gras_dd_alloc_ref(refs,
813                                                         subsub_type->size[GRAS_THISARCH] * subsubcount,
814                                                         r_ref,pointer_type->size[r_arch],
815                                                         (char**)&l_referenced,
816                                                         detect_cycle);
817                                 else
818                                         l_referenced = NULL;
819                         } else {
820                                 gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
821                                                 r_ref,pointer_type->size[r_arch],
822                                                 (char**)&l_referenced,
823                                                 detect_cycle);
824                         }
825
826                         if (l_referenced != NULL)
827                                 gras_datadesc_recv_rec(sock,state,refs, sub_type,
828                                                 r_arch,r_ref,pointer_type->size[r_arch],
829                                                 (char*)l_referenced, subsubcount,
830                                                 detect_cycle || sub_type->cycle);
831
832                         *(void**)l_data=l_referenced;
833                         VERB3("'%s' remotely referenced at %p locally at %p",
834                                         sub_type->name, *(void**)r_ref, l_referenced);
835
836                 } else {
837                         VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
838                                         *(void**)r_ref, *(void**)l_ref);
839
840                         *(void**)l_data=*l_ref;
841
842                 }
843                 free(r_ref);
844                 break;
845         }
846
847         case e_gras_datadesc_type_cat_array: {
848                 gras_dd_cat_array_t    array_data;
849                 int count;
850                 char     *ptr;
851                 long int  elm_size;
852
853                 array_data = type->category.array_data;
854                 /* determine element count locally, or from caller, or from peer */
855                 count = array_data.fixed_size;
856                 if (count == -1)
857                         count = subsize;
858                 if (count == -1)
859                         gras_dd_recv_int(sock, r_arch, &count);
860                 if (count == -1)
861                         THROW1(mismatch_error,0,
862                                         "Invalid (=-1) array size for type %s",type->name);
863
864                 /* receive the content */
865                 sub_type = array_data.type;
866                 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
867                         VERB1("Array of %d scalars, get it in one shoot", count);
868                         if (sub_type->aligned_size[GRAS_THISARCH] >=
869                                         sub_type->aligned_size[r_arch]) {
870                                 gras_trp_recv(sock, (char*)l_data,
871                                                 sub_type->aligned_size[r_arch] * count);
872                                 if (r_arch != GRAS_THISARCH)
873                                         gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data);
874                         } else {
875                                 ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
876
877                                 gras_trp_recv(sock, (char*)ptr,
878                                                 sub_type->size[r_arch] * count);
879                                 if (r_arch != GRAS_THISARCH)
880                                         gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data);
881                                 free(ptr);
882                         }
883                 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
884                                 sub_type->category.array_data.fixed_size >= 0 &&
885                                 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
886                         gras_datadesc_type_t subsub_type;
887                         array_data = sub_type->category.array_data;
888                         subsub_type = array_data.type;
889
890                         VERB1("Array of %d fixed array of scalars, get it in one shot",count);
891                         if (subsub_type->aligned_size[GRAS_THISARCH] >=
892                                         subsub_type->aligned_size[r_arch]) {
893                                 gras_trp_recv(sock, (char*)l_data,
894                                                 subsub_type->aligned_size[r_arch] * count *
895                                                 array_data.fixed_size);
896                                 if (r_arch != GRAS_THISARCH)
897                                         gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data);
898                         } else {
899                                 ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
900
901                                 gras_trp_recv(sock, (char*)ptr,
902                                                 subsub_type->size[r_arch] * count*array_data.fixed_size);
903                                 if (r_arch != GRAS_THISARCH)
904                                         gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data);
905                                 free(ptr);
906                         }
907
908
909                 } else {
910                         /* not scalar content, get it recursively (may contain pointers) */
911                         elm_size = sub_type->aligned_size[GRAS_THISARCH];
912                         VERB2("Receive a %d-long array of %s",count, sub_type->name);
913
914                         ptr = l_data;
915                         for (cpt=0; cpt<count; cpt++) {
916                                 gras_datadesc_recv_rec(sock,state,refs, sub_type,
917                                                 r_arch, NULL, 0, ptr,-1,
918                                                 detect_cycle || sub_type->cycle);
919
920                                 ptr += elm_size;
921                         }
922                 }
923                 break;
924         }
925
926         default:
927                 xbt_die("Invalid type");
928         }
929
930         if (type->recv)
931                 type->recv(type,state,l_data);
932
933         if (!strcmp(type->name,"string"))
934                 VERB1("value: '%s'",*(char**)l_data);
935
936 }
937
938 /**
939  * gras_datadesc_recv:
940  *
941  * Get an instance of the datatype described by @type from the @socket,
942  * and store a pointer to it in @dst
943  *
944  */
945 void
946 gras_datadesc_recv(gras_socket_t         sock,
947                 gras_datadesc_type_t  type,
948                 int                   r_arch,
949                 void                 *dst) {
950
951         xbt_ex_t e;
952         static gras_cbps_t state=NULL; /* callback persistent state */
953         static xbt_dict_t  refs=NULL;  /* all references already sent */
954
955         if (!state) {
956                 state = gras_cbps_new();
957                 refs = xbt_dict_new();
958         }
959
960         xbt_assert0(type,"called with NULL type descriptor");
961         TRY {
962                 gras_datadesc_recv_rec(sock, state, refs, type,
963                                 r_arch, NULL, 0,
964                                 (char *) dst,-1,
965                                 type->cycle);
966         } CLEANUP {
967                 xbt_dict_reset(refs);
968                 gras_cbps_reset(state);
969         } CATCH(e) {
970                 RETHROW;
971         }
972 }
973