Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Last bits of convertion from xbt_error_t to exceptions. Some more cleanups (mainly...
[simgrid.git] / src / gras / DataDesc / ddt_exchange.c
1 /* $Id$ */
2
3 /* ddt_exchange - send/recv data described                                  */
4
5 /* Copyright (c) 2003 Olivier Aumage.                                       */
6 /* Copyright (c) 2003, 2004, 2005 Martin Quinson.                           */
7 /* All rights reserved.                                                     */
8
9 /* This program is free software; you can redistribute it and/or modify it
10  * under the terms of the license (GNU LGPL) which comes with this package. */
11
12 #include "xbt/ex.h"
13 #include "gras/DataDesc/datadesc_private.h"
14 #include "gras/Transport/transport_interface.h" /* gras_trp_chunk_send/recv */
15
16 XBT_LOG_NEW_DEFAULT_SUBCATEGORY(ddt_exchange,datadesc,
17                                  "Sending data over the network");
18 const char *gras_datadesc_cat_names[9] = { 
19   "undefined", 
20   "scalar", "struct", "union", "ref", "array", "ignored",
21   "invalid"};
22
23 static gras_datadesc_type_t 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);
27
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);
32
33 static _XBT_INLINE int
34 gras_dd_is_r_null(char **r_ptr, long int length);
35
36 static _XBT_INLINE void
37 gras_dd_send_int(gras_socket_t sock,int i) {
38
39   if (!int_type) {
40     int_type = gras_datadesc_by_name("int");
41      xbt_assert(int_type);  
42   }
43    
44   DEBUG1("send_int(%d)",i);
45   gras_trp_chunk_send(sock, (char*)&i, int_type->size[GRAS_THISARCH]);
46 }
47
48 static _XBT_INLINE void
49 gras_dd_recv_int(gras_socket_t sock, int r_arch, int *i) {
50
51   if (!int_type) {
52      int_type = gras_datadesc_by_name("int");
53      xbt_assert(int_type);
54   }
55
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);
60   } else {
61     void *ptr = xbt_malloc(int_type->size[r_arch]);
62
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);
66     free(ptr);
67   }
68   DEBUG1("recv_int(%d)",*i);
69 }
70
71 /*
72  * Note: here we suppose that the remote NULL is a sequence 
73  *       of 'length' bytes set to 0.
74  * FIXME: Check in configure?
75  */
76 static _XBT_INLINE int 
77 gras_dd_is_r_null(char **r_ptr, long int length) {
78   int i;
79
80   for (i=0; i<length; i++) {
81     if ( ((unsigned char*)r_ptr) [i]) {
82       return 0;
83     }
84   }
85
86   return 1;
87 }
88
89 static _XBT_INLINE void
90 gras_dd_alloc_ref(xbt_dict_t  refs,
91                   long int     size,
92                   char       **r_ref,
93                   long int     r_len, /* pointer_type->size[r_arch] */
94                   char       **l_ref,
95                   int          detect_cycle) {
96   char *l_data = NULL;
97
98   xbt_assert1(size>0,"Cannot allocate %ld bytes!", size);
99   l_data = xbt_malloc((size_t)size);
100
101   *l_ref = l_data;
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 *));
107
108     CRITICAL0("Check for cycles");
109     memcpy(ptr,l_ref, sizeof(void *));
110
111     DEBUG2("Insert l_ref=%p under r_ref=%p",*(void**)ptr, *(void**)r_ref);
112
113     if (detect_cycle)
114        xbt_dict_set_ext(refs,(const char *) r_ref, r_len, ptr, free);
115   }
116 }
117
118 /**
119  * gras_datadesc_cpy:
120  *
121  * Copy the data pointed by src and described by type 
122  * to a new location, and store a pointer to it in dst.
123  *
124  */
125 void gras_datadesc_cpy(gras_datadesc_type_t type, 
126                        void *src, 
127                        void **dst) {
128   THROW_UNIMPLEMENTED;
129 }
130
131 /***
132  *** Direct use functions
133  ***/
134
135 static void
136 gras_datadesc_send_rec(gras_socket_t         sock,
137                        gras_cbps_t           state,
138                        xbt_dict_t           refs,
139                        gras_datadesc_type_t  type, 
140                        char                 *data,
141                        int                   detect_cycle) {
142
143   xbt_ex_t             e;
144   int                  cpt;
145   gras_datadesc_type_t sub_type; /* type on which we recurse */
146   
147   VERB2("Send a %s (%s)", 
148         type->name, gras_datadesc_cat_names[type->category_code]);
149
150   if (type->send) {
151     type->send(type,state,data);
152   }
153
154   switch (type->category_code) {
155   case e_gras_datadesc_type_cat_scalar:
156     gras_trp_chunk_send(sock, data, type->size[GRAS_THISARCH]);
157     break;
158
159   case e_gras_datadesc_type_cat_struct: {
160     gras_dd_cat_struct_t struct_data;
161     gras_dd_cat_field_t  field;
162     char                *field_data;
163     
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",
167                 type->name);
168     VERB1(">> Send all fields of the structure %s",type->name);
169     xbt_dynar_foreach(struct_data.fields, cpt, field) {
170       field_data = data;
171       field_data += field->offset[GRAS_THISARCH];
172       
173       sub_type = field->type;
174       
175       if (field->send)
176         field->send(type,state,field_data);
177       
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);
181       
182     }
183     VERB1("<< Sent all fields of the structure %s", type->name);
184     
185     break;
186   }
187
188   case e_gras_datadesc_type_cat_union: {
189     gras_dd_cat_union_t union_data;
190     gras_dd_cat_field_t field=NULL;
191     int                 field_num;
192     
193     union_data = type->category.union_data;
194     
195     xbt_assert1(union_data.closed,
196                 "Please call gras_datadesc_declare_union_close on %s before sending it",
197                 type->name);
198     /* retrieve the field number */
199     field_num = union_data.selector(type, state, data);
200     
201     xbt_assert1(field_num > 0,
202                  "union field selector of %s gave a negative value", 
203                  type->name);
204     
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));
208
209     /* Send the field number */
210     gras_dd_send_int(sock, field_num);
211     
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;
215     
216     if (field->send)
217       field->send(type,state,data);
218     
219     gras_datadesc_send_rec(sock,state,refs, sub_type, data, 
220                            detect_cycle || sub_type->cycle);
221           
222     break;
223   }
224     
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;
229     
230     ref_data = type->category.ref_data;
231     
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);
237     }
238     
239     /* Send the actual value of the pointer for cycle handling */
240     if (!pointer_type) {
241       pointer_type = gras_datadesc_by_name("data pointer");
242       xbt_assert(pointer_type);
243     }
244      
245     gras_trp_chunk_send(sock, (char*)data,
246                         pointer_type->size[GRAS_THISARCH]);
247     
248     /* Send the pointed data only if not already sent */
249     if (*(void**)data == NULL) {
250       VERB0("Not sending NULL referenced data");
251       break;
252     }
253
254     reference_is_to_send = 0;
255     TRY {
256       if (detect_cycle)
257         /* return ignored. Just checking whether it's known or not */
258         xbt_dict_get_ext(refs,(char*)ref, sizeof(char*));
259       else 
260         reference_is_to_send = 1;
261     } CATCH(e) {
262       if (e.category != not_found_error)
263         RETHROW;
264       reference_is_to_send = 1;
265       xbt_ex_free(e);
266     }
267
268     if (reference_is_to_send) {
269        VERB1("Sending data referenced at %p", (void*)*ref);
270        if (detect_cycle)
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);
274           
275     } else {
276        VERB1("Not sending data referenced at %p (already done)", (void*)*ref);
277     } 
278     
279     break;
280   }
281
282   case e_gras_datadesc_type_cat_array: {
283     gras_dd_cat_array_t    array_data;
284     long int               count;
285     char                  *ptr=data;
286     long int               elm_size;
287     
288     array_data = type->category.array_data;
289     
290     /* determine and send the element count */
291     count = array_data.fixed_size;
292     if (count == 0) {
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);
297     }
298     
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) {
309        
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);
314        
315     } else {
316       for (cpt=0; cpt<count; cpt++) {
317         gras_datadesc_send_rec(sock,state,refs, sub_type, ptr, 
318                                detect_cycle || sub_type->cycle);
319         ptr += elm_size;
320       }
321     }
322     break;
323   }
324
325   default:
326     xbt_assert0(0, "Invalid type");
327   }
328 }
329
330 /**
331  * gras_datadesc_send:
332  *
333  * Copy the data pointed by src and described by type to the socket
334  *
335  */
336 void gras_datadesc_send(gras_socket_t        sock, 
337                         gras_datadesc_type_t type, 
338                         void *src) {
339
340   xbt_ex_t e;
341   gras_cbps_t  state;
342   xbt_dict_t  refs; /* all references already sent */
343  
344   xbt_assert0(type,"called with NULL type descriptor");
345
346   refs = xbt_dict_new();
347   state = gras_cbps_new();
348   
349   TRY {
350     gras_datadesc_send_rec(sock,state,refs,type,(char*)src, type->cycle);
351   } CLEANUP {
352     xbt_dict_free(&refs);
353     gras_cbps_free(&state);
354   } CATCH(e) {
355     RETHROW;
356   }
357 }
358
359 /**
360  * gras_datadesc_recv_rec:
361  *
362  * Do the data reception job recursively.
363  *
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). 
367  * 
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 ;)
370  */
371 static void
372 gras_datadesc_recv_rec(gras_socket_t         sock, 
373                        gras_cbps_t           state,
374                        xbt_dict_t           refs,
375                        gras_datadesc_type_t  type,
376                        int                   r_arch,
377                        char                **r_data,
378                        long int              r_lgr,
379                        char                 *l_data,
380                        int                   subsize,
381                        int                   detect_cycle) {
382
383   int                  cpt;
384   gras_datadesc_type_t sub_type;
385   xbt_ex_t e;
386
387   VERB2("Recv a %s @%p", type->name, (void*)l_data);
388   xbt_assert(l_data);
389
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);
396     } else {
397       void *ptr = xbt_malloc(type->size[r_arch]);
398
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);
402       free(ptr);
403     }
404     break;
405
406   case e_gras_datadesc_type_cat_struct: {
407     gras_dd_cat_struct_t struct_data;
408     gras_dd_cat_field_t  field;
409
410     struct_data = type->category.struct_data;
411
412     xbt_assert1(struct_data.closed,
413                 "Please call gras_datadesc_declare_struct_close on %s before receiving it",
414                 type->name);
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];
418
419       sub_type = field->type;
420
421       gras_datadesc_recv_rec(sock,state,refs, sub_type,
422                              r_arch,NULL,0,
423                              field_data,-1, 
424                              detect_cycle || sub_type->cycle);
425        
426       if (field->recv)
427         field->recv(type,state,(void*)l_data);
428     
429     }
430     VERB1("<< Received all fields of the structure %s", type->name);
431     
432     break;
433   }
434
435   case e_gras_datadesc_type_cat_union: {
436     gras_dd_cat_union_t union_data;
437     gras_dd_cat_field_t field=NULL;
438     int                 field_num;
439
440     union_data = type->category.union_data;
441
442     xbt_assert1(union_data.closed,
443                 "Please call gras_datadesc_declare_union_close on %s before receiving it",
444                 type->name);
445     /* retrieve the field number */
446     gras_dd_recv_int(sock, r_arch, &field_num);
447     if (field_num < 0)
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));
454     
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;
458     
459     gras_datadesc_recv_rec(sock,state,refs, sub_type,
460                            r_arch,NULL,0,
461                            l_data,-1,
462                            detect_cycle || sub_type->cycle);
463     if (field->recv)
464        field->recv(type,state,l_data);
465
466     break;
467   }
468
469   case e_gras_datadesc_type_cat_ref: {
470     char             **r_ref = NULL;
471     char             **l_ref = NULL;
472     gras_dd_cat_ref_t  ref_data;
473     int reference_is_to_recv = 0;
474     
475     ref_data = type->category.ref_data;
476
477     /* Get the referenced type locally or from peer */
478     sub_type = ref_data.type;
479     if (sub_type == NULL) {
480       int ref_code;
481       gras_dd_recv_int(sock, r_arch, &ref_code);
482       sub_type = gras_datadesc_by_id(ref_code);
483     }
484
485     /* Get the actual value of the pointer for cycle handling */
486     if (!pointer_type) {
487       pointer_type = gras_datadesc_by_name("data pointer");
488       xbt_assert(pointer_type);
489     }
490
491     r_ref = xbt_malloc(pointer_type->size[r_arch]);
492
493     gras_trp_chunk_recv(sock, (char*)r_ref,
494                         pointer_type->size[r_arch]);
495
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",
499             *(void **)r_ref);
500       *(void**)l_data = NULL;
501       free(r_ref);
502       break;
503     }
504          
505     reference_is_to_recv = 0;
506     TRY {
507       if (detect_cycle)
508         l_ref = xbt_dict_get_ext(refs, (char*)r_ref, pointer_type->size[r_arch]);
509       else 
510         reference_is_to_recv = 1;
511     } CATCH(e) {
512       if (e.category != not_found_error)
513         RETHROW;
514       reference_is_to_recv = 1;
515       xbt_ex_free(e);
516     }
517     if (reference_is_to_recv) {
518       int subsubcount = 0;
519       void *l_referenced=NULL;
520
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;
528
529         subsubcount = array_data.fixed_size;
530         if (subsubcount == 0)
531           gras_dd_recv_int(sock, r_arch, &subsubcount);
532
533         subsub_type = array_data.type;
534
535
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,
540                           detect_cycle);
541       } else {
542         gras_dd_alloc_ref(refs,sub_type->size[GRAS_THISARCH], 
543                           r_ref,pointer_type->size[r_arch], 
544                           (char**)&l_referenced,
545                           detect_cycle);
546       }
547
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);
552                                
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);
556       
557     } else {
558       VERB2("NOT receiving data remotely referenced @%p (already done, @%p here)",
559             *(void**)r_ref, *(void**)l_ref);
560
561       *(void**)l_data=*l_ref;
562
563     } 
564     free(r_ref);
565     break;
566   }
567
568   case e_gras_datadesc_type_cat_array: {
569     gras_dd_cat_array_t    array_data;
570     int       count;
571     char     *ptr;
572     long int  elm_size;
573
574     array_data = type->category.array_data;
575     /* determine element count locally, or from caller, or from peer */
576     count = array_data.fixed_size;
577     if (count == 0)
578       count = subsize;
579     if (count == 0)
580       gras_dd_recv_int(sock, r_arch, &count);
581     if (count == 0)
582       THROW1(mismatch_error,0,
583              "Invalid (=0) array size for type %s",type->name);
584
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);
595       } else {
596         ptr = xbt_malloc(sub_type->aligned_size[r_arch] * count);
597
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);
602         free(ptr);
603       }
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;
610        
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);
619       } else {
620         ptr = xbt_malloc(subsub_type->aligned_size[r_arch] * count*array_data.fixed_size);
621
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);
626         free(ptr);
627       }
628       
629        
630     } else {
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);
634
635       ptr = l_data;
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);
640                                    
641         ptr += elm_size;
642       }
643     }
644     break;
645   }
646         
647   default:
648     xbt_assert0(0, "Invalid type");
649   }
650   
651   if (type->recv)
652     type->recv(type,state,l_data);
653
654 }
655
656 /**
657  * gras_datadesc_recv:
658  *
659  * Get an instance of the datatype described by @type from the @socket, 
660  * and store a pointer to it in @dst
661  *
662  */
663 void
664 gras_datadesc_recv(gras_socket_t         sock, 
665                    gras_datadesc_type_t  type,
666                    int                   r_arch,
667                    void                 *dst) {
668
669   xbt_ex_t e;
670   gras_cbps_t  state; /* callback persistent state */
671   xbt_dict_t  refs;  /* all references already sent */
672
673   refs = xbt_dict_new();
674   state = gras_cbps_new();
675
676   xbt_assert0(type,"called with NULL type descriptor");
677   TRY {
678     gras_datadesc_recv_rec(sock, state, refs, type, 
679                            r_arch, NULL, 0,
680                            (char *) dst,-1, 
681                            type->cycle);
682   } CLEANUP {
683     xbt_dict_free(&refs);
684     gras_cbps_free(&state);
685   } CATCH(e) {
686     RETHROW;
687   }
688 }
689