Logo AND Algorithmique Numérique Distribuée

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