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. */
13 #include "gras/DataDesc/datadesc_private.h"
14 #include "gras/Transport/transport_interface.h" /* gras_trp_chunk_send/recv */
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ddt_exchange,datadesc,
17 "Sending data over the network");
18 const char *gras_datadesc_cat_names[9] = {
20 "scalar", "struct", "union", "ref", "array", "ignored",
23 static gras_datadesc_type_t int_type = NULL;
24 static gras_datadesc_type_t pointer_type = NULL;
25 static _XBT_INLINE void gras_dd_send_int(gras_socket_t sock, int i);
26 static _XBT_INLINE void gras_dd_recv_int(gras_socket_t sock, int r_arch, int *i);
28 static _XBT_INLINE xbt_error_t
29 gras_dd_alloc_ref(xbt_dict_t refs, long int size,
30 char **r_ref, long int r_len,
31 char **l_ref, int detect_cycle);
33 static _XBT_INLINE int
34 gras_dd_is_r_null(char **r_ptr, long int length);
36 static _XBT_INLINE void
37 gras_dd_send_int(gras_socket_t sock,int i) {
40 int_type = gras_datadesc_by_name("int");
44 DEBUG1("send_int(%d)",i);
45 gras_trp_chunk_send(sock, (char*)&i, int_type->size[GRAS_THISARCH]);
48 static _XBT_INLINE void
49 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 gras_trp_chunk_recv(sock, (char*)i, int_type->size[r_arch]);
58 if (r_arch != GRAS_THISARCH)
59 gras_dd_convert_elm(int_type,1,r_arch, i,i);
61 void *ptr = xbt_malloc(int_type->size[r_arch]);
63 gras_trp_chunk_recv(sock, (char*)ptr, int_type->size[r_arch]);
64 if (r_arch != GRAS_THISARCH)
65 gras_dd_convert_elm(int_type,1,r_arch, ptr,i);
68 DEBUG1("recv_int(%d)",*i);
72 * Note: here we suppose that the remote NULL is a sequence
73 * of 'length' bytes set to 0.
74 * FIXME: Check in configure?
76 static _XBT_INLINE int
77 gras_dd_is_r_null(char **r_ptr, long int length) {
80 for (i=0; i<length; i++) {
81 if ( ((unsigned char*)r_ptr) [i]) {
89 static _XBT_INLINE xbt_error_t
90 gras_dd_alloc_ref(xbt_dict_t refs,
93 long int r_len, /* pointer_type->size[r_arch] */
98 xbt_assert1(size>0,"Cannot allocate %ld bytes!", size);
99 l_data = xbt_malloc((size_t)size);
102 DEBUG5("alloc_ref: l_data=%p, &l_data=%p; r_ref=%p; *r_ref=%p, r_len=%ld",
103 (void*)l_data,(void*)&l_data,
104 (void*)r_ref, (void*)(r_ref?*r_ref:NULL), r_len);
105 if (detect_cycle && r_ref && !gras_dd_is_r_null( r_ref, r_len)) {
106 void *ptr = xbt_malloc(sizeof(void *));
108 CRITICAL0("Check for cycles");
109 memcpy(ptr,l_ref, sizeof(void *));
111 DEBUG2("Insert l_ref=%p under r_ref=%p",*(void**)ptr, *(void**)r_ref);
114 xbt_dict_set_ext(refs,(const char *) r_ref, r_len, ptr, free);
122 * Copy the data pointed by src and described by type
123 * to a new location, and store a pointer to it in dst.
126 xbt_error_t gras_datadesc_cpy(gras_datadesc_type_t type,
133 *** Direct use functions
137 gras_datadesc_send_rec(gras_socket_t sock,
140 gras_datadesc_type_t type,
146 gras_datadesc_type_t sub_type; /* type on which we recurse */
148 VERB2("Send a %s (%s)",
149 type->name, gras_datadesc_cat_names[type->category_code]);
152 type->send(type,state,data);
155 switch (type->category_code) {
156 case e_gras_datadesc_type_cat_scalar:
157 gras_trp_chunk_send(sock, data, type->size[GRAS_THISARCH]);
160 case e_gras_datadesc_type_cat_struct: {
161 gras_dd_cat_struct_t struct_data;
162 gras_dd_cat_field_t field;
165 struct_data = type->category.struct_data;
166 xbt_assert1(struct_data.closed,
167 "Please call gras_datadesc_declare_struct_close on %s before sending it",
169 VERB1(">> Send all fields of the structure %s",type->name);
170 xbt_dynar_foreach(struct_data.fields, cpt, field) {
172 field_data += field->offset[GRAS_THISARCH];
174 sub_type = field->type;
177 field->send(type,state,field_data);
179 VERB1("Send field %s",field->name);
180 gras_datadesc_send_rec(sock,state,refs,sub_type, field_data,
181 detect_cycle || sub_type->cycle);
184 VERB1("<< Sent all fields of the structure %s", type->name);
189 case e_gras_datadesc_type_cat_union: {
190 gras_dd_cat_union_t union_data;
191 gras_dd_cat_field_t field=NULL;
194 union_data = type->category.union_data;
196 xbt_assert1(union_data.closed,
197 "Please call gras_datadesc_declare_union_close on %s before sending it",
199 /* retrieve the field number */
200 field_num = union_data.selector(type, state, data);
202 xbt_assert1(field_num > 0,
203 "union field selector of %s gave a negative value",
206 xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
207 "union field selector of %s returned %d but there is only %lu fields",
208 type->name, field_num, xbt_dynar_length(union_data.fields));
210 /* Send the field number */
211 gras_dd_send_int(sock, field_num);
213 /* Send the content */
214 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
215 sub_type = field->type;
218 field->send(type,state,data);
220 gras_datadesc_send_rec(sock,state,refs, sub_type, data,
221 detect_cycle || sub_type->cycle);
226 case e_gras_datadesc_type_cat_ref: {
227 gras_dd_cat_ref_t ref_data;
228 void **ref=(void**)data;
229 int reference_is_to_send;
231 ref_data = type->category.ref_data;
233 /* Detect the referenced type and send it to peer if needed */
234 sub_type = ref_data.type;
235 if (sub_type == NULL) {
236 sub_type = (*ref_data.selector)(type,state,data);
237 gras_dd_send_int(sock, sub_type->code);
240 /* Send the actual value of the pointer for cycle handling */
242 pointer_type = gras_datadesc_by_name("data pointer");
243 xbt_assert(pointer_type);
246 gras_trp_chunk_send(sock, (char*)data,
247 pointer_type->size[GRAS_THISARCH]);
249 /* Send the pointed data only if not already sent */
250 if (*(void**)data == NULL) {
251 VERB0("Not sending NULL referenced data");
255 reference_is_to_send = 0;
258 /* return ignored. Just checking whether it's known or not */
259 xbt_dict_get_ext(refs,(char*)ref, sizeof(void*));
261 reference_is_to_send = 1;
263 if (e.category != mismatch_error)
265 reference_is_to_send = 1;
269 if (reference_is_to_send) {
270 VERB1("Sending data referenced at %p", (void*)*ref);
272 xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
273 gras_datadesc_send_rec(sock,state,refs, sub_type, *ref,
274 detect_cycle || sub_type->cycle);
277 VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
283 case e_gras_datadesc_type_cat_array: {
284 gras_dd_cat_array_t array_data;
289 array_data = type->category.array_data;
291 /* determine and send the element count */
292 count = array_data.fixed_size;
294 count = array_data.dynamic_size(type,state,data);
295 xbt_assert1(count >=0,
296 "Invalid (negative) array size for type %s",type->name);
297 gras_dd_send_int(sock, count);
300 /* send the content */
301 sub_type = array_data.type;
302 elm_size = sub_type->aligned_size[GRAS_THISARCH];
303 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
304 VERB1("Array of %ld scalars, send it in one shot",count);
305 gras_trp_chunk_send(sock, data,
306 sub_type->aligned_size[GRAS_THISARCH] * count);
307 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
308 sub_type->category.array_data.fixed_size > 0 &&
309 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
311 VERB1("Array of %ld fixed array of scalars, send it in one shot",count);
312 gras_trp_chunk_send(sock, data,
313 sub_type->category.array_data.type->aligned_size[GRAS_THISARCH]
314 * count * sub_type->category.array_data.fixed_size);
317 for (cpt=0; cpt<count; cpt++) {
318 gras_datadesc_send_rec(sock,state,refs, sub_type, ptr,
319 detect_cycle || sub_type->cycle);
327 xbt_assert0(0, "Invalid type");
332 * gras_datadesc_send:
334 * Copy the data pointed by src and described by type to the socket
337 void gras_datadesc_send(gras_socket_t sock,
338 gras_datadesc_type_t type,
343 xbt_dict_t refs; /* all references already sent */
345 xbt_assert0(type,"called with NULL type descriptor");
347 refs = xbt_dict_new();
348 state = gras_cbps_new();
351 gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
353 xbt_dict_free(&refs);
354 gras_cbps_free(&state);
361 * gras_datadesc_recv_rec:
363 * Do the data reception job recursively.
365 * subsize used only to deal with vicious case of reference to dynamic array.
366 * This size is needed at the reference reception level (to allocate enough
367 * space) and at the array reception level (to fill enough room).
369 * Having this size passed as an argument of the recursive function is a crude
370 * hack, but I was told that working code is sometimes better than neat one ;)
373 gras_datadesc_recv_rec(gras_socket_t sock,
376 gras_datadesc_type_t type,
385 gras_datadesc_type_t sub_type;
388 VERB2("Recv a %s @%p", type->name, (void*)l_data);
391 switch (type->category_code) {
392 case e_gras_datadesc_type_cat_scalar:
393 if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
394 gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]);
395 if (r_arch != GRAS_THISARCH)
396 gras_dd_convert_elm(type,1,r_arch, l_data,l_data);
398 void *ptr = xbt_malloc(type->size[r_arch]);
400 gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]);
401 if (r_arch != GRAS_THISARCH)
402 gras_dd_convert_elm(type,1,r_arch, ptr,l_data);
407 case e_gras_datadesc_type_cat_struct: {
408 gras_dd_cat_struct_t struct_data;
409 gras_dd_cat_field_t field;
411 struct_data = type->category.struct_data;
413 xbt_assert1(struct_data.closed,
414 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
416 VERB1(">> Receive all fields of the structure %s",type->name);
417 xbt_dynar_foreach(struct_data.fields, cpt, field) {
418 char *field_data = l_data + field->offset[GRAS_THISARCH];
420 sub_type = field->type;
422 gras_datadesc_recv_rec(sock,state,refs, sub_type,
425 detect_cycle || sub_type->cycle);
428 field->recv(type,state,(void*)l_data);
431 VERB1("<< Received all fields of the structure %s", type->name);
436 case e_gras_datadesc_type_cat_union: {
437 gras_dd_cat_union_t union_data;
438 gras_dd_cat_field_t field=NULL;
441 union_data = type->category.union_data;
443 xbt_assert1(union_data.closed,
444 "Please call gras_datadesc_declare_union_close on %s before receiving it",
446 /* retrieve the field number */
447 gras_dd_recv_int(sock, r_arch, &field_num);
449 THROW1(mismatch_error,0,
450 "Received union field for %s is negative", type->name);
451 if (field_num < xbt_dynar_length(union_data.fields))
452 THROW3(mismatch_error,0,
453 "Received union field for %s is said to be #%d but there is only %lu fields",
454 type->name, field_num, xbt_dynar_length(union_data.fields));
456 /* Recv the content */
457 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
458 sub_type = field->type;
460 gras_datadesc_recv_rec(sock,state,refs, sub_type,
463 detect_cycle || sub_type->cycle);
465 field->recv(type,state,l_data);
470 case e_gras_datadesc_type_cat_ref: {
473 gras_dd_cat_ref_t ref_data;
474 int reference_is_to_recv = 0;
476 ref_data = type->category.ref_data;
478 /* Get the referenced type locally or from peer */
479 sub_type = ref_data.type;
480 if (sub_type == NULL) {
482 gras_dd_recv_int(sock, r_arch, &ref_code);
483 sub_type = gras_datadesc_by_id(ref_code);
486 /* Get the actual value of the pointer for cycle handling */
488 pointer_type = gras_datadesc_by_name("data pointer");
489 xbt_assert(pointer_type);
492 r_ref = xbt_malloc(pointer_type->size[r_arch]);
494 gras_trp_chunk_recv(sock, (char*)r_ref,
495 pointer_type->size[r_arch]);
497 /* Receive the pointed data only if not already sent */
498 if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
499 VERB1("Not receiving data remotely referenced @%p since it's NULL",
501 *(void**)l_data = NULL;
506 reference_is_to_recv = 0;
509 l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
511 reference_is_to_recv = 1;
513 if (e.category != mismatch_error)
515 reference_is_to_recv = 1;
518 if (reference_is_to_recv) {
520 void *l_referenced=NULL;
522 VERB2("Receiving a ref to '%s', remotely @%p",
523 sub_type->name, *(void**)r_ref);
524 if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
525 /* Damn. Reference to a dynamic array. Allocating the space for it
526 is more complicated */
527 gras_dd_cat_array_t array_data = sub_type->category.array_data;
528 gras_datadesc_type_t subsub_type;
530 subsubcount = array_data.fixed_size;
531 if (subsubcount == 0)
532 gras_dd_recv_int(sock, r_arch, &subsubcount);
534 subsub_type = array_data.type;
537 gras_dd_alloc_ref(refs,
538 subsub_type->size[GRAS_THISARCH] * subsubcount,
539 r_ref,pointer_type->size[r_arch],
540 (char**)&l_referenced,
543 gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
544 r_ref,pointer_type->size[r_arch],
545 (char**)&l_referenced,
549 gras_datadesc_recv_rec(sock,state,refs, sub_type,
550 r_arch,r_ref,pointer_type->size[r_arch],
551 (char*)l_referenced, subsubcount,
552 detect_cycle || sub_type->cycle);
554 *(void**)l_data=l_referenced;
555 VERB3("'%s' remotely referenced at %p locally at %p",
556 sub_type->name, *(void**)r_ref, l_referenced);
559 VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
560 *(void**)r_ref, *(void**)l_ref);
562 *(void**)l_data=*l_ref;
569 case e_gras_datadesc_type_cat_array: {
570 gras_dd_cat_array_t array_data;
575 array_data = type->category.array_data;
576 /* determine element count locally, or from caller, or from peer */
577 count = array_data.fixed_size;
581 gras_dd_recv_int(sock, r_arch, &count);
583 THROW1(mismatch_error,0,
584 "Invalid (=0) array size for type %s",type->name);
586 /* receive the content */
587 sub_type = array_data.type;
588 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
589 VERB1("Array of %d scalars, get it in one shoot", count);
590 if (sub_type->aligned_size[GRAS_THISARCH] >=
591 sub_type->aligned_size[r_arch]) {
592 gras_trp_chunk_recv(sock, (char*)l_data,
593 sub_type->aligned_size[r_arch] * count);
594 if (r_arch != GRAS_THISARCH)
595 gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data);
597 ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
599 gras_trp_chunk_recv(sock, (char*)ptr,
600 sub_type->size[r_arch] * count);
601 if (r_arch != GRAS_THISARCH)
602 gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data);
605 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
606 sub_type->category.array_data.fixed_size > 0 &&
607 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
608 gras_datadesc_type_t subsub_type;
609 array_data = sub_type->category.array_data;
610 subsub_type = array_data.type;
612 VERB1("Array of %d fixed array of scalars, get it in one shot",count);
613 if (subsub_type->aligned_size[GRAS_THISARCH] >=
614 subsub_type->aligned_size[r_arch]) {
615 gras_trp_chunk_recv(sock, (char*)l_data,
616 subsub_type->aligned_size[r_arch] * count *
617 array_data.fixed_size);
618 if (r_arch != GRAS_THISARCH)
619 gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data);
621 ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
623 gras_trp_chunk_recv(sock, (char*)ptr,
624 subsub_type->size[r_arch] * count*array_data.fixed_size);
625 if (r_arch != GRAS_THISARCH)
626 gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data);
632 /* not scalar content, get it recursively (may contain pointers) */
633 elm_size = sub_type->aligned_size[GRAS_THISARCH];
634 VERB2("Receive a %d-long array of %s",count, sub_type->name);
637 for (cpt=0; cpt<count; cpt++) {
638 gras_datadesc_recv_rec(sock,state,refs, sub_type,
639 r_arch, NULL, 0, ptr,-1,
640 detect_cycle || sub_type->cycle);
649 xbt_assert0(0, "Invalid type");
653 type->recv(type,state,l_data);
658 * gras_datadesc_recv:
660 * Get an instance of the datatype described by @type from the @socket,
661 * and store a pointer to it in @dst
665 gras_datadesc_recv(gras_socket_t sock,
666 gras_datadesc_type_t type,
671 gras_cbps_t state; /* callback persistent state */
672 xbt_dict_t refs; /* all references already sent */
674 refs = xbt_dict_new();
675 state = gras_cbps_new();
677 xbt_assert0(type,"called with NULL type descriptor");
679 gras_datadesc_recv_rec(sock, state, refs, type,
684 xbt_dict_free(&refs);
685 gras_cbps_free(&state);
693 *** IDL compiling functions
696 #define gras_datadesc_send_rec foo /* Just to make sure the copypast was ok */
697 #define gras_datadesc_send foo /* Just to make sure the copypast was ok */
698 #define gras_datadesc_recv_rec foo /* Just to make sure the copypast was ok */
699 #define gras_datadesc_recv foo /* Just to make sure the copypast was ok */
702 gras_datadesc_gen_send_rec(gras_socket_t sock,
705 gras_datadesc_type_t type,
711 gras_datadesc_type_t sub_type; /* type on which we recurse */
713 printf(" VERB2(\"Send a %s (%s)\");\n",
714 type->name, gras_datadesc_cat_names[type->category_code]);
716 xbt_assert0(!type->send, "Callbacks not implemented in IDL compiler");
718 switch (type->category_code) {
719 case e_gras_datadesc_type_cat_scalar:
720 printf(" TRYOLD(gras_trp_chunk_send(sock, data, %lu));\n",type->size[GRAS_THISARCH]);
723 case e_gras_datadesc_type_cat_struct: {
724 gras_dd_cat_struct_t struct_data;
725 gras_dd_cat_field_t field;
728 struct_data = type->category.struct_data;
729 xbt_assert1(struct_data.closed,
730 "Please call gras_datadesc_declare_struct_close on %s before sending it",
732 printf(" VERB1(\">> Send all fields of the structure %s\");\n",type->name);
733 xbt_dynar_foreach(struct_data.fields, cpt, field) {
735 field_data += field->offset[GRAS_THISARCH];
737 sub_type = field->type;
739 xbt_assert0(!field->send, "Callbacks not implemented in IDL compiler");
741 printf(" VERB1(\"Send field %s\");\n",field->name);
742 printf(" data += %lu;\n",field->offset[GRAS_THISARCH]);
743 TRYOLD(gras_datadesc_gen_send_rec(sock,state,refs,sub_type, field_data,
744 detect_cycle || sub_type->cycle));
745 printf(" data -= %lu;\n",field->offset[GRAS_THISARCH]);
747 xbt_assert0(!field->recv, "Callbacks not implemented in IDL compiler");
749 printf(" VERB1(\"<< Sent all fields of the structure %s\"", type->name);
754 case e_gras_datadesc_type_cat_union: {
755 gras_dd_cat_union_t union_data;
756 gras_dd_cat_field_t field=NULL;
759 union_data = type->category.union_data;
761 xbt_assert1(union_data.closed,
762 "Please call gras_datadesc_declare_union_close on %s before sending it",
764 /* retrieve the field number */
765 printf(" field_num = union_data.selector(state, data);\n");
767 printf(" xbt_assert0(field_num > 0,\n");
768 printf(" \"union field selector of %s gave a negative value\");\n",type->name);
770 printf(" xbt_assert3(field_num < xbt_dynar_length(union_data.fields),\n");
771 printf(" \"union field selector of %s returned %%d but there is only %lu fields\",field_num);\n",
772 type->name, xbt_dynar_length(union_data.fields));
774 /* Send the field number */
775 printf("TRYOLD(gras_dd_send_int(sock, field_num));\n");
777 /* Send the content */
778 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
779 sub_type = field->type;
782 field->send(state,data);
784 TRYOLD(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, data,
785 detect_cycle || sub_type->cycle));
790 case e_gras_datadesc_type_cat_ref: {
791 gras_dd_cat_ref_t ref_data;
793 void **ref=(void**)data;
796 ref_data = type->category.ref_data;
798 /* Detect the referenced type and send it to peer if needed */
799 sub_type = ref_data.type;
800 if (sub_type == NULL) {
801 sub_type = (*ref_data.selector)(state,data);
802 TRYOLD(gras_dd_send_int(sock, sub_type->code));
805 /* Send the actual value of the pointer for cycle handling */
807 pointer_type = gras_datadesc_by_name("data pointer");
808 xbt_assert(pointer_type);
811 TRYOLD(gras_trp_chunk_send(sock, (char*)data,
812 pointer_type->size[GRAS_THISARCH]));
814 /* Send the pointed data only if not already sent */
815 if (*(void**)data == NULL) {
816 VERB0("Not sending NULL referenced data");
819 errcode = detect_cycle
820 ? xbt_dict_get_ext(refs,(char*)ref, sizeof(void*), &dummy)
822 if (errcode == mismatch_error) {
823 VERB1("Sending data referenced at %p", (void*)*ref);
825 xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
826 TRYOLD(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, *ref,
827 detect_cycle || sub_type->cycle));
829 } else if (errcode == no_error) {
830 VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
838 case e_gras_datadesc_type_cat_array: {
839 gras_dd_cat_array_t array_data;
844 array_data = type->category.array_data;
846 /* determine and send the element count */
847 count = array_data.fixed_size;
849 count = array_data.dynamic_size(state,data);
850 xbt_assert1(count >=0,
851 "Invalid (negative) array size for type %s",type->name);
852 TRYOLD(gras_dd_send_int(sock, count));
855 /* send the content */
856 sub_type = array_data.type;
857 elm_size = sub_type->aligned_size[GRAS_THISARCH];
858 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
859 VERB1("Array of %ld scalars, send it in one shot",count);
860 TRYOLD(gras_trp_chunk_send(sock, data,
861 sub_type->aligned_size[GRAS_THISARCH] * count));
862 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
863 sub_type->category.array_data.fixed_size > 0 &&
864 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
866 VERB1("Array of %ld fixed array of scalars, send it in one shot",count);
867 TRYOLD(gras_trp_chunk_send(sock, data,
868 sub_type->category.array_data.type->aligned_size[GRAS_THISARCH]
869 * count * sub_type->category.array_data.fixed_size));
872 for (cpt=0; cpt<count; cpt++) {
873 TRYOLD(gras_datadesc_gen_send_rec(sock,state,refs, sub_type, ptr,
874 detect_cycle || sub_type->cycle));
882 xbt_assert0(0, "Invalid type");
889 * gras_datadesc_gen_send:
891 * Copy the data pointed by src and described by type to the socket
894 xbt_error_t gras_datadesc_gen_send(gras_socket_t sock,
895 gras_datadesc_type_t type,
900 xbt_dict_t refs; /* all references already sent */
902 refs = xbt_dict_new();
903 state = gras_cbps_new();
905 printf("xbt_error_t gras_%s_send(gras_socket_t sock,void *dst){\n",
907 errcode = gras_datadesc_gen_send_rec(sock,state,refs,type,(char*)src,
908 detect_cycle || sub_type->cycle);
911 xbt_dict_free(&refs);
912 gras_cbps_free(&state);
918 * gras_datadesc_gen_recv_rec:
920 * Do the data reception job recursively.
922 * subsize used only to deal with vicious case of reference to dynamic array.
923 * This size is needed at the reference reception level (to allocate enough
924 * space) and at the array reception level (to fill enough room).
926 * Having this size passed as an argument of the recursive function is a crude
927 * hack, but I was told that working code is sometimes better than neat one ;)
930 gras_datadesc_gen_recv_rec(gras_socket_t sock,
933 gras_datadesc_type_t type,
943 gras_datadesc_type_t sub_type;
945 VERB2("Recv a %s @%p", type->name, (void*)l_data);
948 switch (type->category_code) {
949 case e_gras_datadesc_type_cat_scalar:
950 if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
951 TRYOLD(gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]));
952 if (r_arch != GRAS_THISARCH)
953 TRYOLD(gras_dd_convert_elm(type,1,r_arch, l_data,l_data));
955 void *ptr = xbt_malloc(type->size[r_arch]);
957 TRYOLD(gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]));
958 if (r_arch != GRAS_THISARCH)
959 TRYOLD(gras_dd_convert_elm(type,1,r_arch, ptr,l_data));
964 case e_gras_datadesc_type_cat_struct: {
965 gras_dd_cat_struct_t struct_data;
966 gras_dd_cat_field_t field;
968 struct_data = type->category.struct_data;
970 xbt_assert1(struct_data.closed,
971 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
973 VERB1(">> Receive all fields of the structure %s",type->name);
974 xbt_dynar_foreach(struct_data.fields, cpt, field) {
975 char *field_data = l_data + field->offset[GRAS_THISARCH];
977 sub_type = field->type;
979 TRYOLD(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
982 detect_cycle || sub_type->cycle));
984 field->recv(type,state,data);
987 VERB1("<< Received all fields of the structure %s", type->name);
992 case e_gras_datadesc_type_cat_union: {
993 gras_dd_cat_union_t union_data;
994 gras_dd_cat_field_t field=NULL;
997 union_data = type->category.union_data;
999 xbt_assert1(union_data.closed,
1000 "Please call gras_datadesc_declare_union_close on %s before receiving it",
1002 /* retrieve the field number */
1003 TRYOLD(gras_dd_recv_int(sock, r_arch, &field_num));
1005 RAISE1(mismatch_error,
1006 "Received union field for %s is negative", type->name);
1007 if (field_num < xbt_dynar_length(union_data.fields))
1008 RAISE3(mismatch_error,
1009 "Received union field for %s is %d but there is only %lu fields",
1010 type->name, field_num, xbt_dynar_length(union_data.fields));
1012 /* Recv the content */
1013 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
1014 sub_type = field->type;
1016 TRYOLD(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1019 detect_cycle || sub_type->cycle));
1021 field->recv(type,state,data);
1026 case e_gras_datadesc_type_cat_ref: {
1027 char **r_ref = NULL;
1028 char **l_ref = NULL;
1029 gras_dd_cat_ref_t ref_data;
1031 ref_data = type->category.ref_data;
1033 /* Get the referenced type locally or from peer */
1034 sub_type = ref_data.type;
1035 if (sub_type == NULL) {
1037 TRYOLD(gras_dd_recv_int(sock, r_arch, &ref_code));
1038 TRYOLD(gras_datadesc_by_id(ref_code, &sub_type));
1041 /* Get the actual value of the pointer for cycle handling */
1042 if (!pointer_type) {
1043 pointer_type = gras_datadesc_by_name("data pointer");
1044 xbt_assert(pointer_type);
1047 r_ref = xbt_malloc(pointer_type->size[r_arch]);
1049 TRYOLD(gras_trp_chunk_recv(sock, (char*)r_ref,
1050 pointer_type->size[r_arch]));
1052 /* Receive the pointed data only if not already sent */
1053 if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
1054 VERB1("Not receiving data remotely referenced @%p since it's NULL",
1056 *(void**)l_data = NULL;
1061 errcode = detect_cycle
1062 ? xbt_dict_get_ext(refs,
1063 (char*)r_ref, pointer_type->size[r_arch],
1067 if (errcode == mismatch_error) {
1068 int subsubcount = 0;
1069 void *l_referenced=NULL;
1071 VERB2("Receiving a ref to '%s', remotely @%p",
1072 sub_type->name, *(void**)r_ref);
1073 if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
1074 /* Damn. Reference to a dynamic array. Allocating the size for it
1075 is more complicated */
1076 gras_dd_cat_array_t array_data = sub_type->category.array_data;
1077 gras_datadesc_type_t subsub_type;
1079 subsubcount = array_data.fixed_size;
1080 if (subsubcount == 0)
1081 TRYOLD(gras_dd_recv_int(sock, r_arch, &subsubcount));
1083 subsub_type = array_data.type;
1086 TRYOLD(gras_dd_alloc_ref(refs,
1087 subsub_type->size[GRAS_THISARCH] * subsubcount,
1088 r_ref,pointer_type->size[r_arch],
1089 (char**)&l_referenced,
1092 TRYOLD(gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
1093 r_ref,pointer_type->size[r_arch],
1094 (char**)&l_referenced,
1098 TRYOLD(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1099 r_arch,r_ref,pointer_type->size[r_arch],
1100 (char*)l_referenced, subsubcount,
1101 detect_cycle || sub_type->cycle));
1103 *(void**)l_data=l_referenced;
1104 VERB3("'%s' remotely referenced at %p locally at %p",
1105 sub_type->name, *(void**)r_ref, l_referenced);
1107 } else if (errcode == no_error) {
1108 VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
1109 *(void**)r_ref, *(void**)l_ref);
1111 *(void**)l_data=*l_ref;
1120 case e_gras_datadesc_type_cat_array: {
1121 gras_dd_cat_array_t array_data;
1126 array_data = type->category.array_data;
1127 /* determine element count locally, or from caller, or from peer */
1128 count = array_data.fixed_size;
1132 TRYOLD(gras_dd_recv_int(sock, r_arch, &count));
1134 RAISE1(mismatch_error,
1135 "Invalid (=0) array size for type %s",type->name);
1137 /* receive the content */
1138 sub_type = array_data.type;
1139 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
1140 VERB1("Array of %d scalars, get it in one shoot", count);
1141 if (sub_type->aligned_size[GRAS_THISARCH] >=
1142 sub_type->aligned_size[r_arch]) {
1143 TRYOLD(gras_trp_chunk_recv(sock, (char*)l_data,
1144 sub_type->aligned_size[r_arch] * count));
1145 if (r_arch != GRAS_THISARCH)
1146 TRYOLD(gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data));
1148 ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
1150 TRYOLD(gras_trp_chunk_recv(sock, (char*)ptr,
1151 sub_type->size[r_arch] * count));
1152 if (r_arch != GRAS_THISARCH)
1153 TRYOLD(gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data));
1156 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
1157 sub_type->category.array_data.fixed_size > 0 &&
1158 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
1159 gras_datadesc_type_t subsub_type;
1160 array_data = sub_type->category.array_data;
1161 subsub_type = array_data.type;
1163 VERB1("Array of %d fixed array of scalars, get it in one shot",count);
1164 if (subsub_type->aligned_size[GRAS_THISARCH] >=
1165 subsub_type->aligned_size[r_arch]) {
1166 TRYOLD(gras_trp_chunk_recv(sock, (char*)l_data,
1167 subsub_type->aligned_size[r_arch] * count *
1168 array_data.fixed_size));
1169 if (r_arch != GRAS_THISARCH)
1170 TRYOLD(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data));
1172 ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
1174 TRYOLD(gras_trp_chunk_recv(sock, (char*)ptr,
1175 subsub_type->size[r_arch] * count*array_data.fixed_size));
1176 if (r_arch != GRAS_THISARCH)
1177 TRYOLD(gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data));
1183 /* not scalar content, get it recursively (may contain pointers) */
1184 elm_size = sub_type->aligned_size[GRAS_THISARCH];
1185 VERB2("Receive a %d-long array of %s",count, sub_type->name);
1188 for (cpt=0; cpt<count; cpt++) {
1189 TRYOLD(gras_datadesc_gen_recv_rec(sock,state,refs, sub_type,
1190 r_arch, NULL, 0, ptr,-1,
1191 detect_cycle || sub_type->cycle));
1200 xbt_assert0(0, "Invalid type");
1204 type->recv(type,state,l_data);
1210 * gras_datadesc_gen_recv:
1212 * Get an instance of the datatype described by @type from the @socket,
1213 * and store a pointer to it in @dst
1217 gras_datadesc_gen_recv(gras_socket_t sock,
1218 gras_datadesc_type_t type,
1222 xbt_error_t errcode;
1223 gras_cbps_t state; /* callback persistent state */
1224 xbt_dict_t refs; /* all references already sent */
1226 refs = xbt_dict_new();
1227 state = gras_cbps_new();
1229 printf("xbt_error_t gras_%s_recv(gras_socket_t sock,void *dst){\n",
1232 errcode = gras_datadesc_gen_recv_rec(sock, state, refs, type,
1238 xbt_dict_free(&refs);
1239 gras_cbps_free(&state);