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 refs = xbt_dict_new();
341 state = gras_cbps_new();
343 xbt_assert0(type,"called with NULL type descriptor");
344 errcode = gras_datadesc_send_rec(sock,state,refs,type,(char*)src, (type->flags & gras_datadesc_flag_cycle));
346 xbt_dict_free(&refs);
347 gras_cbps_free(&state);
353 * gras_datadesc_recv_rec:
355 * Do the data reception job recursively.
357 * subsize used only to deal with vicious case of reference to dynamic array.
358 * This size is needed at the reference reception level (to allocate enough
359 * space) and at the array reception level (to fill enough room).
361 * Having this size passed as an argument of the recursive function is a crude
362 * hack, but I was told that working code is sometimes better than neat one ;)
365 gras_datadesc_recv_rec(gras_socket_t sock,
368 gras_datadesc_type_t type,
378 gras_datadesc_type_t sub_type;
380 VERB2("Recv a %s @%p", type->name, (void*)l_data);
383 switch (type->category_code) {
384 case e_gras_datadesc_type_cat_scalar:
385 if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
386 TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
387 if (r_arch != GRAS_THISARCH)
388 TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
390 void *ptr = xbt_malloc(type->size[r_arch]);
392 TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
393 if (r_arch != GRAS_THISARCH)
394 TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
399 case e_gras_datadesc_type_cat_struct: {
400 gras_dd_cat_struct_t struct_data;
401 gras_dd_cat_field_t field;
403 struct_data = type->category.struct_data;
405 xbt_assert1(struct_data.closed,
406 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
408 VERB1(">> Receive all fields of the structure %s",type->name);
409 xbt_dynar_foreach(struct_data.fields, cpt, field) {
410 char *field_data = l_data + field->offset[GRAS_THISARCH];
412 sub_type = field->type;
414 TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
417 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
420 field->recv(type,state,(void*)l_data);
423 VERB1("<< Received all fields of the structure %s", type->name);
428 case e_gras_datadesc_type_cat_union: {
429 gras_dd_cat_union_t union_data;
430 gras_dd_cat_field_t field=NULL;
433 union_data = type->category.union_data;
435 xbt_assert1(union_data.closed,
436 "Please call gras_datadesc_declare_union_close on %s before receiving it",
438 /* retrieve the field number */
439 TRY(gras_dd_recv_int(sock, r_arch, &field_num));
441 RAISE1(mismatch_error,
442 "Received union field for %s is negative", type->name);
443 if (field_num < xbt_dynar_length(union_data.fields))
444 RAISE3(mismatch_error,
445 "Received union field for %s is %d but there is only %lu fields",
446 type->name, field_num, xbt_dynar_length(union_data.fields));
448 /* Recv the content */
449 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
450 sub_type = field->type;
452 TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
455 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
457 field->recv(type,state,l_data);
462 case e_gras_datadesc_type_cat_ref: {
465 gras_dd_cat_ref_t ref_data;
467 ref_data = type->category.ref_data;
469 /* Get the referenced type locally or from peer */
470 sub_type = ref_data.type;
471 if (sub_type == NULL) {
473 TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
474 TRY(gras_datadesc_by_id(ref_code, &sub_type));
477 /* Get the actual value of the pointer for cycle handling */
479 pointer_type = gras_datadesc_by_name("data pointer");
480 xbt_assert(pointer_type);
483 r_ref = xbt_malloc(pointer_type->size[r_arch]);
485 TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
486 pointer_type->size[r_arch]));
488 /* Receive the pointed data only if not already sent */
489 if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
490 VERB1("Not receiving data remotely referenced @%p since it's NULL",
492 *(void**)l_data = NULL;
497 errcode = detect_cycle
498 ? xbt_dict_get_ext(refs,
499 (char*)r_ref, pointer_type->size[r_arch],
503 if (errcode == mismatch_error) {
505 void *l_referenced=NULL;
507 VERB2("Receiving a ref to '%s', remotely @%p",
508 sub_type->name, *(void**)r_ref);
509 if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
510 /* Damn. Reference to a dynamic array. Allocating the size for it
511 is more complicated */
512 gras_dd_cat_array_t array_data = sub_type->category.array_data;
513 gras_datadesc_type_t subsub_type;
515 subsubcount = array_data.fixed_size;
516 if (subsubcount == 0)
517 TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
519 subsub_type = array_data.type;
522 TRY(gras_dd_alloc_ref(refs,
523 subsub_type->size[GRAS_THISARCH] * subsubcount,
524 r_ref,pointer_type->size[r_arch],
525 (char**)&l_referenced,
528 TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
529 r_ref,pointer_type->size[r_arch],
530 (char**)&l_referenced,
534 TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
535 r_arch,r_ref,pointer_type->size[r_arch],
536 (char*)l_referenced, subsubcount,
537 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
539 *(void**)l_data=l_referenced;
540 VERB3("'%s' remotely referenced at %p locally at %p",
541 sub_type->name, *(void**)r_ref, l_referenced);
543 } else if (errcode == no_error) {
544 VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
545 *(void**)r_ref, *(void**)l_ref);
547 *(void**)l_data=*l_ref;
556 case e_gras_datadesc_type_cat_array: {
557 gras_dd_cat_array_t array_data;
562 array_data = type->category.array_data;
563 /* determine element count locally, or from caller, or from peer */
564 count = array_data.fixed_size;
568 TRY(gras_dd_recv_int(sock, r_arch, &count));
570 RAISE1(mismatch_error,
571 "Invalid (=0) array size for type %s",type->name);
573 /* receive the content */
574 sub_type = array_data.type;
575 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
576 VERB1("Array of %d scalars, get it in one shoot", count);
577 if (sub_type->aligned_size[GRAS_THISARCH] >=
578 sub_type->aligned_size[r_arch]) {
579 TRY(gras_trp_chunk_recv(sock, (char*)l_data,
580 sub_type->aligned_size[r_arch] * count));
581 if (r_arch != GRAS_THISARCH)
582 TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
584 ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
586 TRY(gras_trp_chunk_recv(sock, (char*)ptr,
587 sub_type->size[r_arch] * count));
588 if (r_arch != GRAS_THISARCH)
589 TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
592 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
593 sub_type->category.array_data.fixed_size > 0 &&
594 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
595 gras_datadesc_type_t subsub_type;
596 array_data = sub_type->category.array_data;
597 subsub_type = array_data.type;
599 VERB1("Array of %d fixed array of scalars, get it in one shot",count);
600 if (subsub_type->aligned_size[GRAS_THISARCH] >=
601 subsub_type->aligned_size[r_arch]) {
602 TRY(gras_trp_chunk_recv(sock, (char*)l_data,
603 subsub_type->aligned_size[r_arch] * count *
604 array_data.fixed_size));
605 if (r_arch != GRAS_THISARCH)
606 TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data));
608 ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
610 TRY(gras_trp_chunk_recv(sock, (char*)ptr,
611 subsub_type->size[r_arch] * count*array_data.fixed_size));
612 if (r_arch != GRAS_THISARCH)
613 TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data));
619 /* not scalar content, get it recursively (may contain pointers) */
620 elm_size = sub_type->aligned_size[GRAS_THISARCH];
621 VERB2("Receive a %d-long array of %s",count, sub_type->name);
624 for (cpt=0; cpt<count; cpt++) {
625 TRY(gras_datadesc_recv_rec(sock,state,refs, sub_type,
626 r_arch, NULL, 0, ptr,-1,
627 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
636 xbt_assert0(0, "Invalid type");
640 type->recv(type,state,l_data);
646 * gras_datadesc_recv:
648 * Get an instance of the datatype described by @type from the @socket,
649 * and store a pointer to it in @dst
653 gras_datadesc_recv(gras_socket_t sock,
654 gras_datadesc_type_t type,
659 gras_cbps_t state; /* callback persistent state */
660 xbt_dict_t refs; /* all references already sent */
662 refs = xbt_dict_new();
663 state = gras_cbps_new();
665 xbt_assert0(type,"called with NULL type descriptor");
666 errcode = gras_datadesc_recv_rec(sock, state, refs, type,
669 (type->flags & gras_datadesc_flag_cycle));
671 xbt_dict_free(&refs);
672 gras_cbps_free(&state);
679 *** IDL compiling functions
682 #define gras_datadesc_send_rec foo /* Just to make sure the copypast was ok */
683 #define gras_datadesc_send foo /* Just to make sure the copypast was ok */
684 #define gras_datadesc_recv_rec foo /* Just to make sure the copypast was ok */
685 #define gras_datadesc_recv foo /* Just to make sure the copypast was ok */
688 gras_datadesc_gen_send_rec(gras_socket_t sock,
691 gras_datadesc_type_t type,
697 gras_datadesc_type_t sub_type; /* type on which we recurse */
699 printf(" VERB2(\"Send a %s (%s)\");\n",
700 type->name, gras_datadesc_cat_names[type->category_code]);
702 xbt_assert0(!type->send, "Callbacks not implemented in IDL compiler");
704 switch (type->category_code) {
705 case e_gras_datadesc_type_cat_scalar:
706 printf(" TRY(gras_trp_chunk_send(sock, data, %lu));\n",type->size[GRAS_THISARCH]);
709 case e_gras_datadesc_type_cat_struct: {
710 gras_dd_cat_struct_t struct_data;
711 gras_dd_cat_field_t field;
714 struct_data = type->category.struct_data;
715 xbt_assert1(struct_data.closed,
716 "Please call gras_datadesc_declare_struct_close on %s before sending it",
718 printf(" VERB1(\">> Send all fields of the structure %s\");\n",type->name);
719 xbt_dynar_foreach(struct_data.fields, cpt, field) {
721 field_data += field->offset[GRAS_THISARCH];
723 sub_type = field->type;
725 xbt_assert0(!field->send, "Callbacks not implemented in IDL compiler");
727 printf(" VERB1(\"Send field %s\");\n",field->name);
728 printf(" data += %lu;\n",field->offset[GRAS_THISARCH]);
729 TRY(gras_datadesc_gen_send_rec(sock,state,refs,sub_type, field_data,
730 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
731 printf(" data -= %lu;\n",field->offset[GRAS_THISARCH]);
733 xbt_assert0(!field->recv, "Callbacks not implemented in IDL compiler");
735 printf(" VERB1(\"<< Sent all fields of the structure %s\"", type->name);
740 case e_gras_datadesc_type_cat_union: {
741 gras_dd_cat_union_t union_data;
742 gras_dd_cat_field_t field=NULL;
745 union_data = type->category.union_data;
747 xbt_assert1(union_data.closed,
748 "Please call gras_datadesc_declare_union_close on %s before sending it",
750 /* retrieve the field number */
751 printf(" field_num = union_data.selector(state, data);\n");
753 printf(" xbt_assert0(field_num > 0,\n");
754 printf(" \"union field selector of %s gave a negative value\");\n",type->name);
756 printf(" xbt_assert3(field_num < xbt_dynar_length(union_data.fields),\n");
757 printf(" \"union field selector of %s returned %%d but there is only %lu fields\",field_num);\n",
758 type->name, xbt_dynar_length(union_data.fields));
760 /* Send the field number */
761 printf("TRY(gras_dd_send_int(sock, field_num));\n");
763 /* Send the content */
764 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
765 sub_type = field->type;
768 field->send(state,data);
770 TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, data,
771 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
776 case e_gras_datadesc_type_cat_ref: {
777 gras_dd_cat_ref_t ref_data;
779 void **ref=(void**)data;
782 ref_data = type->category.ref_data;
784 /* Detect the referenced type and send it to peer if needed */
785 sub_type = ref_data.type;
786 if (sub_type == NULL) {
787 sub_type = (*ref_data.selector)(state,data);
788 TRY(gras_dd_send_int(sock, sub_type->code));
791 /* Send the actual value of the pointer for cycle handling */
793 pointer_type = gras_datadesc_by_name("data pointer");
794 xbt_assert(pointer_type);
797 TRY(gras_trp_chunk_send(sock, (char*)data,
798 pointer_type->size[GRAS_THISARCH]));
800 /* Send the pointed data only if not already sent */
801 if (*(void**)data == NULL) {
802 VERB0("Not sending NULL referenced data");
805 errcode = detect_cycle
806 ? xbt_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy)
808 if (errcode == mismatch_error) {
809 VERB1("Sending data referenced at %p", (void*)*ref);
811 xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
812 TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, *ref,
813 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
815 } else if (errcode == no_error) {
816 VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
824 case e_gras_datadesc_type_cat_array: {
825 gras_dd_cat_array_t array_data;
830 array_data = type->category.array_data;
832 /* determine and send the element count */
833 count = array_data.fixed_size;
835 count = array_data.dynamic_size(state,data);
836 xbt_assert1(count >=0,
837 "Invalid (negative) array size for type %s",type->name);
838 TRY(gras_dd_send_int(sock, count));
841 /* send the content */
842 sub_type = array_data.type;
843 elm_size = sub_type->aligned_size[GRAS_THISARCH];
844 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
845 VERB1("Array of %ld scalars, send it in one shot",count);
846 TRY(gras_trp_chunk_send(sock, data,
847 sub_type->aligned_size[GRAS_THISARCH] * count));
848 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
849 sub_type->category.array_data.fixed_size > 0 &&
850 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
852 VERB1("Array of %ld fixed array of scalars, send it in one shot",count);
853 TRY(gras_trp_chunk_send(sock, data,
854 sub_type->category.array_data.type->aligned_size[GRAS_THISARCH]
855 * count * sub_type->category.array_data.fixed_size));
858 for (cpt=0; cpt<count; cpt++) {
859 TRY(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, ptr,
860 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
868 xbt_assert0(0, "Invalid type");
875 * gras_datadesc_gen_send:
877 * Copy the data pointed by src and described by type to the socket
880 xbt_error_t gras_datadesc_gen_send(gras_socket_t sock,
881 gras_datadesc_type_t type,
886 xbt_dict_t refs; /* all references already sent */
888 refs = xbt_dict_new();
889 state = gras_cbps_new();
891 printf("xbt_error_t gras_%s_send(gras_socket_t sock,void *dst){\n",
893 errcode = gras_datadesc_gen_send_rec(sock,state,refs,type,(char*)src,
894 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle));
897 xbt_dict_free(&refs);
898 gras_cbps_free(&state);
904 * gras_datadesc_gen_recv_rec:
906 * Do the data reception job recursively.
908 * subsize used only to deal with vicious case of reference to dynamic array.
909 * This size is needed at the reference reception level (to allocate enough
910 * space) and at the array reception level (to fill enough room).
912 * Having this size passed as an argument of the recursive function is a crude
913 * hack, but I was told that working code is sometimes better than neat one ;)
916 gras_datadesc_gen_recv_rec(gras_socket_t sock,
919 gras_datadesc_type_t type,
929 gras_datadesc_type_t sub_type;
931 VERB2("Recv a %s @%p", type->name, (void*)l_data);
934 switch (type->category_code) {
935 case e_gras_datadesc_type_cat_scalar:
936 if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
937 TRY(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
938 if (r_arch != GRAS_THISARCH)
939 TRY(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
941 void *ptr = xbt_malloc(type->size[r_arch]);
943 TRY(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
944 if (r_arch != GRAS_THISARCH)
945 TRY(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
950 case e_gras_datadesc_type_cat_struct: {
951 gras_dd_cat_struct_t struct_data;
952 gras_dd_cat_field_t field;
954 struct_data = type->category.struct_data;
956 xbt_assert1(struct_data.closed,
957 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
959 VERB1(">> Receive all fields of the structure %s",type->name);
960 xbt_dynar_foreach(struct_data.fields, cpt, field) {
961 char *field_data = l_data + field->offset[GRAS_THISARCH];
963 sub_type = field->type;
965 TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
968 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
970 field->recv(type,state,data);
973 VERB1("<< Received all fields of the structure %s", type->name);
978 case e_gras_datadesc_type_cat_union: {
979 gras_dd_cat_union_t union_data;
980 gras_dd_cat_field_t field=NULL;
983 union_data = type->category.union_data;
985 xbt_assert1(union_data.closed,
986 "Please call gras_datadesc_declare_union_close on %s before receiving it",
988 /* retrieve the field number */
989 TRY(gras_dd_recv_int(sock, r_arch, &field_num));
991 RAISE1(mismatch_error,
992 "Received union field for %s is negative", type->name);
993 if (field_num < xbt_dynar_length(union_data.fields))
994 RAISE3(mismatch_error,
995 "Received union field for %s is %d but there is only %lu fields",
996 type->name, field_num, xbt_dynar_length(union_data.fields));
998 /* Recv the content */
999 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
1000 sub_type = field->type;
1002 TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1005 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
1007 field->recv(type,state,data);
1012 case e_gras_datadesc_type_cat_ref: {
1013 char **r_ref = NULL;
1014 char **l_ref = NULL;
1015 gras_dd_cat_ref_t ref_data;
1017 ref_data = type->category.ref_data;
1019 /* Get the referenced type locally or from peer */
1020 sub_type = ref_data.type;
1021 if (sub_type == NULL) {
1023 TRY(gras_dd_recv_int(sock, r_arch, &ref_code));
1024 TRY(gras_datadesc_by_id(ref_code, &sub_type));
1027 /* Get the actual value of the pointer for cycle handling */
1028 if (!pointer_type) {
1029 pointer_type = gras_datadesc_by_name("data pointer");
1030 xbt_assert(pointer_type);
1033 r_ref = xbt_malloc(pointer_type->size[r_arch]);
1035 TRY(gras_trp_chunk_recv(sock, (char*)r_ref,
1036 pointer_type->size[r_arch]));
1038 /* Receive the pointed data only if not already sent */
1039 if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
1040 VERB1("Not receiving data remotely referenced @%p since it's NULL",
1042 *(void**)l_data = NULL;
1047 errcode = detect_cycle
1048 ? xbt_dict_get_ext(refs,
1049 (char*)r_ref, pointer_type->size[r_arch],
1053 if (errcode == mismatch_error) {
1054 int subsubcount = 0;
1055 void *l_referenced=NULL;
1057 VERB2("Receiving a ref to '%s', remotely @%p",
1058 sub_type->name, *(void**)r_ref);
1059 if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
1060 /* Damn. Reference to a dynamic array. Allocating the size for it
1061 is more complicated */
1062 gras_dd_cat_array_t array_data = sub_type->category.array_data;
1063 gras_datadesc_type_t subsub_type;
1065 subsubcount = array_data.fixed_size;
1066 if (subsubcount == 0)
1067 TRY(gras_dd_recv_int(sock, r_arch, &subsubcount));
1069 subsub_type = array_data.type;
1072 TRY(gras_dd_alloc_ref(refs,
1073 subsub_type->size[GRAS_THISARCH] * subsubcount,
1074 r_ref,pointer_type->size[r_arch],
1075 (char**)&l_referenced,
1078 TRY(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
1079 r_ref,pointer_type->size[r_arch],
1080 (char**)&l_referenced,
1084 TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1085 r_arch,r_ref,pointer_type->size[r_arch],
1086 (char*)l_referenced, subsubcount,
1087 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
1089 *(void**)l_data=l_referenced;
1090 VERB3("'%s' remotely referenced at %p locally at %p",
1091 sub_type->name, *(void**)r_ref, l_referenced);
1093 } else if (errcode == no_error) {
1094 VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
1095 *(void**)r_ref, *(void**)l_ref);
1097 *(void**)l_data=*l_ref;
1106 case e_gras_datadesc_type_cat_array: {
1107 gras_dd_cat_array_t array_data;
1112 array_data = type->category.array_data;
1113 /* determine element count locally, or from caller, or from peer */
1114 count = array_data.fixed_size;
1118 TRY(gras_dd_recv_int(sock, r_arch, &count));
1120 RAISE1(mismatch_error,
1121 "Invalid (=0) array size for type %s",type->name);
1123 /* receive the content */
1124 sub_type = array_data.type;
1125 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
1126 VERB1("Array of %d scalars, get it in one shoot", count);
1127 if (sub_type->aligned_size[GRAS_THISARCH] >=
1128 sub_type->aligned_size[r_arch]) {
1129 TRY(gras_trp_chunk_recv(sock, (char*)l_data,
1130 sub_type->aligned_size[r_arch] * count));
1131 if (r_arch != GRAS_THISARCH)
1132 TRY(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
1134 ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
1136 TRY(gras_trp_chunk_recv(sock, (char*)ptr,
1137 sub_type->size[r_arch] * count));
1138 if (r_arch != GRAS_THISARCH)
1139 TRY(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
1142 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
1143 sub_type->category.array_data.fixed_size > 0 &&
1144 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
1145 gras_datadesc_type_t subsub_type;
1146 array_data = sub_type->category.array_data;
1147 subsub_type = array_data.type;
1149 VERB1("Array of %d fixed array of scalars, get it in one shot",count);
1150 if (subsub_type->aligned_size[GRAS_THISARCH] >=
1151 subsub_type->aligned_size[r_arch]) {
1152 TRY(gras_trp_chunk_recv(sock, (char*)l_data,
1153 subsub_type->aligned_size[r_arch] * count *
1154 array_data.fixed_size));
1155 if (r_arch != GRAS_THISARCH)
1156 TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data));
1158 ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
1160 TRY(gras_trp_chunk_recv(sock, (char*)ptr,
1161 subsub_type->size[r_arch] * count*array_data.fixed_size));
1162 if (r_arch != GRAS_THISARCH)
1163 TRY(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data));
1169 /* not scalar content, get it recursively (may contain pointers) */
1170 elm_size = sub_type->aligned_size[GRAS_THISARCH];
1171 VERB2("Receive a %d-long array of %s",count, sub_type->name);
1174 for (cpt=0; cpt<count; cpt++) {
1175 TRY(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1176 r_arch, NULL, 0, ptr,-1,
1177 detect_cycle || (sub_type->flags & gras_datadesc_flag_cycle)));
1186 xbt_assert0(0, "Invalid type");
1190 type->recv(type,state,l_data);
1196 * gras_datadesc_gen_recv:
1198 * Get an instance of the datatype described by @type from the @socket,
1199 * and store a pointer to it in @dst
1203 gras_datadesc_gen_recv(gras_socket_t sock,
1204 gras_datadesc_type_t type,
1208 xbt_error_t errcode;
1209 gras_cbps_t state; /* callback persistent state */
1210 xbt_dict_t refs; /* all references already sent */
1212 refs = xbt_dict_new();
1213 state = gras_cbps_new();
1215 printf("xbt_error_t gras_%s_recv(gras_socket_t sock,void *dst){\n",
1218 errcode = gras_datadesc_gen_recv_rec(sock, state, refs, type,
1221 (sub_type->flags & gras_datadesc_flag_cycle));
1224 xbt_dict_free(&refs);
1225 gras_cbps_free(&state);