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 void
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 void
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);
121 * Copy the data pointed by src and described by type
122 * to a new location, and store a pointer to it in dst.
125 void gras_datadesc_cpy(gras_datadesc_type_t type,
132 *** Direct use functions
136 gras_datadesc_send_rec(gras_socket_t sock,
139 gras_datadesc_type_t type,
145 gras_datadesc_type_t sub_type; /* type on which we recurse */
147 VERB2("Send a %s (%s)",
148 type->name, gras_datadesc_cat_names[type->category_code]);
151 type->send(type,state,data);
154 switch (type->category_code) {
155 case e_gras_datadesc_type_cat_scalar:
156 gras_trp_chunk_send(sock, data, type->size[GRAS_THISARCH]);
159 case e_gras_datadesc_type_cat_struct: {
160 gras_dd_cat_struct_t struct_data;
161 gras_dd_cat_field_t field;
164 struct_data = type->category.struct_data;
165 xbt_assert1(struct_data.closed,
166 "Please call gras_datadesc_declare_struct_close on %s before sending it",
168 VERB1(">> Send all fields of the structure %s",type->name);
169 xbt_dynar_foreach(struct_data.fields, cpt, field) {
171 field_data += field->offset[GRAS_THISARCH];
173 sub_type = field->type;
176 field->send(type,state,field_data);
178 VERB1("Send field %s",field->name);
179 gras_datadesc_send_rec(sock,state,refs,sub_type, field_data,
180 detect_cycle || sub_type->cycle);
183 VERB1("<< Sent all fields of the structure %s", type->name);
188 case e_gras_datadesc_type_cat_union: {
189 gras_dd_cat_union_t union_data;
190 gras_dd_cat_field_t field=NULL;
193 union_data = type->category.union_data;
195 xbt_assert1(union_data.closed,
196 "Please call gras_datadesc_declare_union_close on %s before sending it",
198 /* retrieve the field number */
199 field_num = union_data.selector(type, state, data);
201 xbt_assert1(field_num > 0,
202 "union field selector of %s gave a negative value",
205 xbt_assert3(field_num < xbt_dynar_length(union_data.fields),
206 "union field selector of %s returned %d but there is only %lu fields",
207 type->name, field_num, xbt_dynar_length(union_data.fields));
209 /* Send the field number */
210 gras_dd_send_int(sock, field_num);
212 /* Send the content */
213 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
214 sub_type = field->type;
217 field->send(type,state,data);
219 gras_datadesc_send_rec(sock,state,refs, sub_type, data,
220 detect_cycle || sub_type->cycle);
225 case e_gras_datadesc_type_cat_ref: {
226 gras_dd_cat_ref_t ref_data;
227 void **ref=(void**)data;
228 int reference_is_to_send;
230 ref_data = type->category.ref_data;
232 /* Detect the referenced type and send it to peer if needed */
233 sub_type = ref_data.type;
234 if (sub_type == NULL) {
235 sub_type = (*ref_data.selector)(type,state,data);
236 gras_dd_send_int(sock, sub_type->code);
239 /* Send the actual value of the pointer for cycle handling */
241 pointer_type = gras_datadesc_by_name("data pointer");
242 xbt_assert(pointer_type);
245 gras_trp_chunk_send(sock, (char*)data,
246 pointer_type->size[GRAS_THISARCH]);
248 /* Send the pointed data only if not already sent */
249 if (*(void**)data == NULL) {
250 VERB0("Not sending NULL referenced data");
254 reference_is_to_send = 0;
257 /* return ignored. Just checking whether it's known or not */
258 xbt_dict_get_ext(refs,(char*)ref, sizeof(char*));
260 reference_is_to_send = 1;
262 if (e.category != not_found_error)
264 reference_is_to_send = 1;
268 if (reference_is_to_send) {
269 VERB1("Sending data referenced at %p", (void*)*ref);
271 xbt_dict_set_ext(refs, (char*)ref, sizeof(void*), ref, NULL);
272 gras_datadesc_send_rec(sock,state,refs, sub_type, *ref,
273 detect_cycle || sub_type->cycle);
276 VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
282 case e_gras_datadesc_type_cat_array: {
283 gras_dd_cat_array_t array_data;
288 array_data = type->category.array_data;
290 /* determine and send the element count */
291 count = array_data.fixed_size;
293 count = array_data.dynamic_size(type,state,data);
294 xbt_assert1(count >=0,
295 "Invalid (negative) array size for type %s",type->name);
296 gras_dd_send_int(sock, count);
299 /* send the content */
300 sub_type = array_data.type;
301 elm_size = sub_type->aligned_size[GRAS_THISARCH];
302 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
303 VERB1("Array of %ld scalars, send it in one shot",count);
304 gras_trp_chunk_send(sock, data,
305 sub_type->aligned_size[GRAS_THISARCH] * count);
306 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
307 sub_type->category.array_data.fixed_size > 0 &&
308 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
310 VERB1("Array of %ld fixed array of scalars, send it in one shot",count);
311 gras_trp_chunk_send(sock, data,
312 sub_type->category.array_data.type->aligned_size[GRAS_THISARCH]
313 * count * sub_type->category.array_data.fixed_size);
316 for (cpt=0; cpt<count; cpt++) {
317 gras_datadesc_send_rec(sock,state,refs, sub_type, ptr,
318 detect_cycle || sub_type->cycle);
326 xbt_assert0(0, "Invalid type");
331 * gras_datadesc_send:
333 * Copy the data pointed by src and described by type to the socket
336 void gras_datadesc_send(gras_socket_t sock,
337 gras_datadesc_type_t type,
342 xbt_dict_t refs; /* all references already sent */
344 xbt_assert0(type,"called with NULL type descriptor");
346 refs = xbt_dict_new();
347 state = gras_cbps_new();
350 gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
352 xbt_dict_free(&refs);
353 gras_cbps_free(&state);
360 * gras_datadesc_recv_rec:
362 * Do the data reception job recursively.
364 * subsize used only to deal with vicious case of reference to dynamic array.
365 * This size is needed at the reference reception level (to allocate enough
366 * space) and at the array reception level (to fill enough room).
368 * Having this size passed as an argument of the recursive function is a crude
369 * hack, but I was told that working code is sometimes better than neat one ;)
372 gras_datadesc_recv_rec(gras_socket_t sock,
375 gras_datadesc_type_t type,
384 gras_datadesc_type_t sub_type;
387 VERB2("Recv a %s @%p", type->name, (void*)l_data);
390 switch (type->category_code) {
391 case e_gras_datadesc_type_cat_scalar:
392 if (type->size[GRAS_THISARCH] == type->size[r_arch]) {
393 gras_trp_chunk_recv(sock, (char*)l_data, type->size[r_arch]);
394 if (r_arch != GRAS_THISARCH)
395 gras_dd_convert_elm(type,1,r_arch, l_data,l_data);
397 void *ptr = xbt_malloc(type->size[r_arch]);
399 gras_trp_chunk_recv(sock, (char*)ptr, type->size[r_arch]);
400 if (r_arch != GRAS_THISARCH)
401 gras_dd_convert_elm(type,1,r_arch, ptr,l_data);
406 case e_gras_datadesc_type_cat_struct: {
407 gras_dd_cat_struct_t struct_data;
408 gras_dd_cat_field_t field;
410 struct_data = type->category.struct_data;
412 xbt_assert1(struct_data.closed,
413 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
415 VERB1(">> Receive all fields of the structure %s",type->name);
416 xbt_dynar_foreach(struct_data.fields, cpt, field) {
417 char *field_data = l_data + field->offset[GRAS_THISARCH];
419 sub_type = field->type;
421 gras_datadesc_recv_rec(sock,state,refs, sub_type,
424 detect_cycle || sub_type->cycle);
427 field->recv(type,state,(void*)l_data);
430 VERB1("<< Received all fields of the structure %s", type->name);
435 case e_gras_datadesc_type_cat_union: {
436 gras_dd_cat_union_t union_data;
437 gras_dd_cat_field_t field=NULL;
440 union_data = type->category.union_data;
442 xbt_assert1(union_data.closed,
443 "Please call gras_datadesc_declare_union_close on %s before receiving it",
445 /* retrieve the field number */
446 gras_dd_recv_int(sock, r_arch, &field_num);
448 THROW1(mismatch_error,0,
449 "Received union field for %s is negative", type->name);
450 if (field_num < xbt_dynar_length(union_data.fields))
451 THROW3(mismatch_error,0,
452 "Received union field for %s is said to be #%d but there is only %lu fields",
453 type->name, field_num, xbt_dynar_length(union_data.fields));
455 /* Recv the content */
456 field = xbt_dynar_get_as(union_data.fields, field_num, gras_dd_cat_field_t);
457 sub_type = field->type;
459 gras_datadesc_recv_rec(sock,state,refs, sub_type,
462 detect_cycle || sub_type->cycle);
464 field->recv(type,state,l_data);
469 case e_gras_datadesc_type_cat_ref: {
472 gras_dd_cat_ref_t ref_data;
473 int reference_is_to_recv = 0;
475 ref_data = type->category.ref_data;
477 /* Get the referenced type locally or from peer */
478 sub_type = ref_data.type;
479 if (sub_type == NULL) {
481 gras_dd_recv_int(sock, r_arch, &ref_code);
482 sub_type = gras_datadesc_by_id(ref_code);
485 /* Get the actual value of the pointer for cycle handling */
487 pointer_type = gras_datadesc_by_name("data pointer");
488 xbt_assert(pointer_type);
491 r_ref = xbt_malloc(pointer_type->size[r_arch]);
493 gras_trp_chunk_recv(sock, (char*)r_ref,
494 pointer_type->size[r_arch]);
496 /* Receive the pointed data only if not already sent */
497 if (gras_dd_is_r_null(r_ref, pointer_type->size[r_arch])) {
498 VERB1("Not receiving data remotely referenced @%p since it's NULL",
500 *(void**)l_data = NULL;
505 reference_is_to_recv = 0;
508 l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
510 reference_is_to_recv = 1;
512 if (e.category != not_found_error)
514 reference_is_to_recv = 1;
517 if (reference_is_to_recv) {
519 void *l_referenced=NULL;
521 VERB2("Receiving a ref to '%s', remotely @%p",
522 sub_type->name, *(void**)r_ref);
523 if (sub_type->category_code == e_gras_datadesc_type_cat_array) {
524 /* Damn. Reference to a dynamic array. Allocating the space for it
525 is more complicated */
526 gras_dd_cat_array_t array_data = sub_type->category.array_data;
527 gras_datadesc_type_t subsub_type;
529 subsubcount = array_data.fixed_size;
530 if (subsubcount == 0)
531 gras_dd_recv_int(sock, r_arch, &subsubcount);
533 subsub_type = array_data.type;
536 gras_dd_alloc_ref(refs,
537 subsub_type->size[GRAS_THISARCH] * subsubcount,
538 r_ref,pointer_type->size[r_arch],
539 (char**)&l_referenced,
542 gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH],
543 r_ref,pointer_type->size[r_arch],
544 (char**)&l_referenced,
548 gras_datadesc_recv_rec(sock,state,refs, sub_type,
549 r_arch,r_ref,pointer_type->size[r_arch],
550 (char*)l_referenced, subsubcount,
551 detect_cycle || sub_type->cycle);
553 *(void**)l_data=l_referenced;
554 VERB3("'%s' remotely referenced at %p locally at %p",
555 sub_type->name, *(void**)r_ref, l_referenced);
558 VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
559 *(void**)r_ref, *(void**)l_ref);
561 *(void**)l_data=*l_ref;
568 case e_gras_datadesc_type_cat_array: {
569 gras_dd_cat_array_t array_data;
574 array_data = type->category.array_data;
575 /* determine element count locally, or from caller, or from peer */
576 count = array_data.fixed_size;
580 gras_dd_recv_int(sock, r_arch, &count);
582 THROW1(mismatch_error,0,
583 "Invalid (=0) array size for type %s",type->name);
585 /* receive the content */
586 sub_type = array_data.type;
587 if (sub_type->category_code == e_gras_datadesc_type_cat_scalar) {
588 VERB1("Array of %d scalars, get it in one shoot", count);
589 if (sub_type->aligned_size[GRAS_THISARCH] >=
590 sub_type->aligned_size[r_arch]) {
591 gras_trp_chunk_recv(sock, (char*)l_data,
592 sub_type->aligned_size[r_arch] * count);
593 if (r_arch != GRAS_THISARCH)
594 gras_dd_convert_elm(sub_type,count,r_arch, l_data,l_data);
596 ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
598 gras_trp_chunk_recv(sock, (char*)ptr,
599 sub_type->size[r_arch] * count);
600 if (r_arch != GRAS_THISARCH)
601 gras_dd_convert_elm(sub_type,count,r_arch, ptr,l_data);
604 } else if (sub_type->category_code == e_gras_datadesc_type_cat_array &&
605 sub_type->category.array_data.fixed_size > 0 &&
606 sub_type->category.array_data.type->category_code == e_gras_datadesc_type_cat_scalar) {
607 gras_datadesc_type_t subsub_type;
608 array_data = sub_type->category.array_data;
609 subsub_type = array_data.type;
611 VERB1("Array of %d fixed array of scalars, get it in one shot",count);
612 if (subsub_type->aligned_size[GRAS_THISARCH] >=
613 subsub_type->aligned_size[r_arch]) {
614 gras_trp_chunk_recv(sock, (char*)l_data,
615 subsub_type->aligned_size[r_arch] * count *
616 array_data.fixed_size);
617 if (r_arch != GRAS_THISARCH)
618 gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, l_data,l_data);
620 ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
622 gras_trp_chunk_recv(sock, (char*)ptr,
623 subsub_type->size[r_arch] * count*array_data.fixed_size);
624 if (r_arch != GRAS_THISARCH)
625 gras_dd_convert_elm(subsub_type,count*array_data.fixed_size,r_arch, ptr,l_data);
631 /* not scalar content, get it recursively (may contain pointers) */
632 elm_size = sub_type->aligned_size[GRAS_THISARCH];
633 VERB2("Receive a %d-long array of %s",count, sub_type->name);
636 for (cpt=0; cpt<count; cpt++) {
637 gras_datadesc_recv_rec(sock,state,refs, sub_type,
638 r_arch, NULL, 0, ptr,-1,
639 detect_cycle || sub_type->cycle);
648 xbt_assert0(0, "Invalid type");
652 type->recv(type,state,l_data);
657 * gras_datadesc_recv:
659 * Get an instance of the datatype described by @type from the @socket,
660 * and store a pointer to it in @dst
664 gras_datadesc_recv(gras_socket_t sock,
665 gras_datadesc_type_t type,
670 gras_cbps_t state; /* callback persistent state */
671 xbt_dict_t refs; /* all references already sent */
673 refs = xbt_dict_new();
674 state = gras_cbps_new();
676 xbt_assert0(type,"called with NULL type descriptor");
678 gras_datadesc_recv_rec(sock, state, refs, type,
683 xbt_dict_free(&refs);
684 gras_cbps_free(&state);