3 /* ddt_exchange - send/recv data described */
5 /* Copyright (c) 2003 Olivier Aumage. */
6 /* Copyright (c) 2003, 2004, 2005 Martin Quinson. */
7 /* All rights reserved. */
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. */
12 #include "gras/DataDesc/datadesc_private.h"
13 #include "gras/Transport/transport_interface.h" /* gras_trp_chunk_send/recv */
15 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ddt_exchange,datadesc,
16 "Sending data over the network");
17 const char *gras_datadesc_cat_names[9] = {
19 "scalar", "struct", "union", "ref", "array", "ignored",
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);
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);
32 static _XBT_INLINE int
33 gras_dd_is_r_null(char **r_ptr, long int length);
35 static _XBT_INLINE xbt_error_t
36 gras_dd_send_int(gras_socket_t sock,int i) {
39 int_type = gras_datadesc_by_name("int");
43 DEBUG1("send_int(%d)",i);
44 return gras_trp_chunk_send(sock, (char*)&i, int_type->size[GRAS_THISARCH]);
47 static _XBT_INLINE xbt_error_t
48 gras_dd_recv_int(gras_socket_t sock, int r_arch, int *i) {
52 int_type = gras_datadesc_by_name("int");
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));
61 void *ptr = xbt_malloc(int_type->size[r_arch]);
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));
68 DEBUG1("recv_int(%d)",*i);
74 * Note: here we suppose that the remote NULL is a sequence
75 * of 'length' bytes set to 0.
76 * FIXME: Check in configure?
78 static _XBT_INLINE int
79 gras_dd_is_r_null(char **r_ptr, long int length) {
82 for (i=0; i<length; i++) {
83 if ( ((unsigned char*)r_ptr) [i]) {
91 static _XBT_INLINE xbt_error_t
92 gras_dd_alloc_ref(xbt_dict_t refs,
95 long int r_len, /* pointer_type->size[r_arch] */
100 xbt_assert1(size>0,"Cannot allocate %ld bytes!", size);
101 l_data = xbt_malloc((size_t)size);
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 *));
110 CRITICAL0("Check for cycles");
111 memcpy(ptr,l_ref, sizeof(void *));
113 DEBUG2("Insert l_ref=%p under r_ref=%p",*(void**)ptr, *(void**)r_ref);
116 xbt_dict_set_ext(refs,(const char *) r_ref, r_len, ptr, free);
124 * Copy the data pointed by src and described by type
125 * to a new location, and store a pointer to it in dst.
128 xbt_error_t gras_datadesc_cpy(gras_datadesc_type_t type,
135 *** Direct use functions
139 gras_datadesc_send_rec(gras_socket_t sock,
142 gras_datadesc_type_t type,
148 gras_datadesc_type_t sub_type; /* type on which we recurse */
150 VERB2("Send a %s (%s)",
151 type->name, gras_datadesc_cat_names[type->category_code]);
154 type->send(type,state,data);
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]));
162 case e_gras_datadesc_type_cat_struct: {
163 gras_dd_cat_struct_t struct_data;
164 gras_dd_cat_field_t field;
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",
171 VERB1(">> Send all fields of the structure %s",type->name);
172 xbt_dynar_foreach(struct_data.fields, cpt, field) {
174 field_data += field->offset[GRAS_THISARCH];
176 sub_type = field->type;
179 field->send(type,state,field_data);
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)));
186 VERB1("<< Sent all fields of the structure %s", type->name);
191 case e_gras_datadesc_type_cat_union: {
192 gras_dd_cat_union_t union_data;
193 gras_dd_cat_field_t field=NULL;
196 union_data = type->category.union_data;
198 xbt_assert1(union_data.closed,
199 "Please call gras_datadesc_declare_union_close on %s before sending it",
201 /* retrieve the field number */
202 field_num = union_data.selector(type, state, data);
204 xbt_assert1(field_num > 0,
205 "union field selector of %s gave a negative value",
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));
212 /* Send the field number */
213 TRY(gras_dd_send_int(sock, field_num));
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;
220 field->send(type,state,data);
222 TRY(gras_datadesc_send_rec(sock,state,refs, sub_type, data,
223 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
228 case e_gras_datadesc_type_cat_ref: {
229 gras_dd_cat_ref_t ref_data;
231 void **ref=(void**)data;
234 ref_data = type->category.ref_data;
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));
243 /* Send the actual value of the pointer for cycle handling */
245 pointer_type = gras_datadesc_by_name("data pointer");
246 xbt_assert(pointer_type);
249 TRY(gras_trp_chunk_send(sock, (char*)data,
250 pointer_type->size[GRAS_THISARCH]));
252 /* Send the pointed data only if not already sent */
253 if (*(void**)data == NULL) {
254 VERB0("Not sending NULL referenced data");
257 errcode = detect_cycle
258 ? xbt_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy)
260 if (errcode == mismatch_error) {
261 VERB1("Sending data referenced at %p", (void*)*ref);
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)));
267 } else if (errcode == no_error) {
268 VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
276 case e_gras_datadesc_type_cat_array: {
277 gras_dd_cat_array_t array_data;
282 array_data = type->category.array_data;
284 /* determine and send the element count */
285 count = array_data.fixed_size;
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));
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) {
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));
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)));
320 xbt_assert0(0, "Invalid type");
327 * gras_datadesc_send:
329 * Copy the data pointed by src and described by type to the socket
332 xbt_error_t gras_datadesc_send(gras_socket_t sock,
333 gras_datadesc_type_t type,
338 xbt_dict_t refs; /* all references already sent */
340 xbt_assert0(type,"called with NULL type descriptor");
342 refs = xbt_dict_new();
343 state = gras_cbps_new();
345 errcode = gras_datadesc_send_rec(sock,state,refs,type,(char*)src, (type->flags & gras_datadesc_flag_cycle));
347 xbt_dict_free(&refs);
348 gras_cbps_free(&state);
354 * gras_datadesc_recv_rec:
356 * Do the data reception job recursively.
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).
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 ;)
366 gras_datadesc_recv_rec(gras_socket_t sock,
369 gras_datadesc_type_t type,
379 gras_datadesc_type_t sub_type;
381 VERB2("Recv a %s @%p", type->name, (void*)l_data);
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));
391 void *ptr = xbt_malloc(type->size[r_arch]);
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));
400 case e_gras_datadesc_type_cat_struct: {
401 gras_dd_cat_struct_t struct_data;
402 gras_dd_cat_field_t field;
404 struct_data = type->category.struct_data;
406 xbt_assert1(struct_data.closed,
407 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
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];
413 sub_type = field->type;
415 TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
418 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
421 field->recv(type,state,(void*)l_data);
424 VERB1("<< Received all fields of the structure %s", type->name);
429 case e_gras_datadesc_type_cat_union: {
430 gras_dd_cat_union_t union_data;
431 gras_dd_cat_field_t field=NULL;
434 union_data = type->category.union_data;
436 xbt_assert1(union_data.closed,
437 "Please call gras_datadesc_declare_union_close on %s before receiving it",
439 /* retrieve the field number */
440 TRY(gras_dd_recv_int(sock, r_arch, &field_num));
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));
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;
453 TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
456 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
458 field->recv(type,state,l_data);
463 case e_gras_datadesc_type_cat_ref: {
466 gras_dd_cat_ref_t ref_data;
468 ref_data = type->category.ref_data;
470 /* Get the referenced type locally or from peer */
471 sub_type = ref_data.type;
472 if (sub_type == NULL) {
474 TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
475 TRY(gras_datadesc_by_id(ref_code, &sub_type));
478 /* Get the actual value of the pointer for cycle handling */
480 pointer_type = gras_datadesc_by_name("data pointer");
481 xbt_assert(pointer_type);
484 r_ref = xbt_malloc(pointer_type->size[r_arch]);
486 TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
487 pointer_type->size[r_arch]));
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",
493 *(void**)l_data = NULL;
498 errcode = detect_cycle
499 ? xbt_dict_get_ext(refs,
500 (char*)r_ref, pointer_type->size[r_arch],
504 if (errcode == mismatch_error) {
506 void *l_referenced=NULL;
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;
516 subsubcount = array_data.fixed_size;
517 if (subsubcount == 0)
518 TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
520 subsub_type = array_data.type;
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,
529 TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
530 r_ref,pointer_type->size[r_arch],
531 (char**)&l_referenced,
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)));
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);
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);
548 *(void**)l_data=*l_ref;
557 case e_gras_datadesc_type_cat_array: {
558 gras_dd_cat_array_t array_data;
563 array_data = type->category.array_data;
564 /* determine element count locally, or from caller, or from peer */
565 count = array_data.fixed_size;
569 TRY(gras_dd_recv_int(sock, r_arch, &count));
571 RAISE1(mismatch_error,
572 "Invalid (=0) array size for type %s",type->name);
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));
585 ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
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));
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;
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));
609 ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
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));
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);
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)));
637 xbt_assert0(0, "Invalid type");
641 type->recv(type,state,l_data);
647 * gras_datadesc_recv:
649 * Get an instance of the datatype described by @type from the @socket,
650 * and store a pointer to it in @dst
654 gras_datadesc_recv(gras_socket_t sock,
655 gras_datadesc_type_t type,
660 gras_cbps_t state; /* callback persistent state */
661 xbt_dict_t refs; /* all references already sent */
663 refs = xbt_dict_new();
664 state = gras_cbps_new();
666 xbt_assert0(type,"called with NULL type descriptor");
667 errcode = gras_datadesc_recv_rec(sock, state, refs, type,
670 (type->flags & gras_datadesc_flag_cycle));
672 xbt_dict_free(&refs);
673 gras_cbps_free(&state);
680 *** IDL compiling functions
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 */
689 gras_datadesc_gen_send_rec(gras_socket_t sock,
692 gras_datadesc_type_t type,
698 gras_datadesc_type_t sub_type; /* type on which we recurse */
700 printf(" VERB2(\"Send a %s (%s)\");\n",
701 type->name, gras_datadesc_cat_names[type->category_code]);
703 xbt_assert0(!type->send, "Callbacks not implemented in IDL compiler");
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]);
710 case e_gras_datadesc_type_cat_struct: {
711 gras_dd_cat_struct_t struct_data;
712 gras_dd_cat_field_t field;
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",
719 printf(" VERB1(\">> Send all fields of the structure %s\");\n",type->name);
720 xbt_dynar_foreach(struct_data.fields, cpt, field) {
722 field_data += field->offset[GRAS_THISARCH];
724 sub_type = field->type;
726 xbt_assert0(!field->send, "Callbacks not implemented in IDL compiler");
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]);
734 xbt_assert0(!field->recv, "Callbacks not implemented in IDL compiler");
736 printf(" VERB1(\"<< Sent all fields of the structure %s\"", type->name);
741 case e_gras_datadesc_type_cat_union: {
742 gras_dd_cat_union_t union_data;
743 gras_dd_cat_field_t field=NULL;
746 union_data = type->category.union_data;
748 xbt_assert1(union_data.closed,
749 "Please call gras_datadesc_declare_union_close on %s before sending it",
751 /* retrieve the field number */
752 printf(" field_num = union_data.selector(state, data);\n");
754 printf(" xbt_assert0(field_num > 0,\n");
755 printf(" \"union field selector of %s gave a negative value\");\n",type->name);
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));
761 /* Send the field number */
762 printf("TRY(gras_dd_send_int(sock, field_num));\n");
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;
769 field->send(state,data);
771 TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, data,
772 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
777 case e_gras_datadesc_type_cat_ref: {
778 gras_dd_cat_ref_t ref_data;
780 void **ref=(void**)data;
783 ref_data = type->category.ref_data;
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));
792 /* Send the actual value of the pointer for cycle handling */
794 pointer_type = gras_datadesc_by_name("data pointer");
795 xbt_assert(pointer_type);
798 TRY(gras_trp_chunk_send(sock, (char*)data,
799 pointer_type->size[GRAS_THISARCH]));
801 /* Send the pointed data only if not already sent */
802 if (*(void**)data == NULL) {
803 VERB0("Not sending NULL referenced data");
806 errcode = detect_cycle
807 ? xbt_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy)
809 if (errcode == mismatch_error) {
810 VERB1("Sending data referenced at %p", (void*)*ref);
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)));
816 } else if (errcode == no_error) {
817 VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
825 case e_gras_datadesc_type_cat_array: {
826 gras_dd_cat_array_t array_data;
831 array_data = type->category.array_data;
833 /* determine and send the element count */
834 count = array_data.fixed_size;
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));
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) {
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));
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)));
869 xbt_assert0(0, "Invalid type");
876 * gras_datadesc_gen_send:
878 * Copy the data pointed by src and described by type to the socket
881 xbt_error_t gras_datadesc_gen_send(gras_socket_t sock,
882 gras_datadesc_type_t type,
887 xbt_dict_t refs; /* all references already sent */
889 refs = xbt_dict_new();
890 state = gras_cbps_new();
892 printf("xbt_error_t gras_%s_send(gras_socket_t sock,void *dst){\n",
894 errcode = gras_datadesc_gen_send_rec(sock,state,refs,type,(char*)src,
895 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle));
898 xbt_dict_free(&refs);
899 gras_cbps_free(&state);
905 * gras_datadesc_gen_recv_rec:
907 * Do the data reception job recursively.
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).
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 ;)
917 gras_datadesc_gen_recv_rec(gras_socket_t sock,
920 gras_datadesc_type_t type,
930 gras_datadesc_type_t sub_type;
932 VERB2("Recv a %s @%p", type->name, (void*)l_data);
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));
942 void *ptr = xbt_malloc(type->size[r_arch]);
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));
951 case e_gras_datadesc_type_cat_struct: {
952 gras_dd_cat_struct_t struct_data;
953 gras_dd_cat_field_t field;
955 struct_data = type->category.struct_data;
957 xbt_assert1(struct_data.closed,
958 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
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];
964 sub_type = field->type;
966 TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
969 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
971 field->recv(type,state,data);
974 VERB1("<< Received all fields of the structure %s", type->name);
979 case e_gras_datadesc_type_cat_union: {
980 gras_dd_cat_union_t union_data;
981 gras_dd_cat_field_t field=NULL;
984 union_data = type->category.union_data;
986 xbt_assert1(union_data.closed,
987 "Please call gras_datadesc_declare_union_close on %s before receiving it",
989 /* retrieve the field number */
990 TRY(gras_dd_recv_int(sock, r_arch, &field_num));
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));
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;
1003 TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1006 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
1008 field->recv(type,state,data);
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;
1018 ref_data = type->category.ref_data;
1020 /* Get the referenced type locally or from peer */
1021 sub_type = ref_data.type;
1022 if (sub_type == NULL) {
1024 TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
1025 TRY(gras_datadesc_by_id(ref_code, &sub_type));
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);
1034 r_ref = xbt_malloc(pointer_type->size[r_arch]);
1036 TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
1037 pointer_type->size[r_arch]));
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",
1043 *(void**)l_data = NULL;
1048 errcode = detect_cycle
1049 ? xbt_dict_get_ext(refs,
1050 (char*)r_ref, pointer_type->size[r_arch],
1054 if (errcode == mismatch_error) {
1055 int subsubcount = 0;
1056 void *l_referenced=NULL;
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;
1066 subsubcount = array_data.fixed_size;
1067 if (subsubcount == 0)
1068 TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
1070 subsub_type = array_data.type;
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,
1079 TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
1080 r_ref,pointer_type->size[r_arch],
1081 (char**)&l_referenced,
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)));
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);
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);
1098 *(void**)l_data=*l_ref;
1107 case e_gras_datadesc_type_cat_array: {
1108 gras_dd_cat_array_t array_data;
1113 array_data = type->category.array_data;
1114 /* determine element count locally, or from caller, or from peer */
1115 count = array_data.fixed_size;
1119 TRY(gras_dd_recv_int(sock, r_arch, &count));
1121 RAISE1(mismatch_error,
1122 "Invalid (=0) array size for type %s",type->name);
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));
1135 ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
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));
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;
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));
1159 ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
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));
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);
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)));
1187 xbt_assert0(0, "Invalid type");
1191 type->recv(type,state,l_data);
1197 * gras_datadesc_gen_recv:
1199 * Get an instance of the datatype described by @type from the @socket,
1200 * and store a pointer to it in @dst
1204 gras_datadesc_gen_recv(gras_socket_t sock,
1205 gras_datadesc_type_t type,
1209 xbt_error_t errcode;
1210 gras_cbps_t state; /* callback persistent state */
1211 xbt_dict_t refs; /* all references already sent */
1213 refs = xbt_dict_new();
1214 state = gras_cbps_new();
1216 printf("xbt_error_t gras_%s_recv(gras_socket_t sock,void *dst){\n",
1219 errcode = gras_datadesc_gen_recv_rec(sock, state, refs, type,
1222 (sub_type->flags & gras_datadesc_flag_cycle));
1225 xbt_dict_free(&refs);
1226 gras_cbps_free(&state);