Mercury
mercury_macros.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013 Argonne National Laboratory, Department of Energy,
3  *                    UChicago Argonne, LLC and The HDF Group.
4  * All rights reserved.
5  *
6  * The full copyright notice, including terms governing use, modification,
7  * and redistribution, is contained in the COPYING file that can be
8  * found at the root of the source code distribution tree.
9  */
10 
11 #ifndef MERCURY_MACROS_H
12 #define MERCURY_MACROS_H
13 
14 #include "mercury.h"
15 #include "mercury_handler.h"
16 #include "mercury_proc.h"
17 
18 #ifdef HG_HAS_BOOST
19 #include <boost/preprocessor.hpp>
20 
21 /* Booleans for MERCURY_GEN_MACROS */
22 #define MERCURY_GEN_FALSE 0
23 #define MERCURY_GEN_TRUE 1
24 
25 /********************** Utility macros **********************/
26 
27 /* Return parameter with fixed name */
28 #define HG_GEN_RET_PARAM(ret_type) ((ret_type)(ret))
29 
30 /* Get type / name */
31 #define HG_GEN_GET_TYPE(field) BOOST_PP_SEQ_HEAD(field)
32 #define HG_GEN_GET_NAME(field) BOOST_PP_SEQ_CAT(BOOST_PP_SEQ_TAIL(field))
33 
34 /* Get struct field */
35 #define HG_GEN_STRUCT_FIELD(r, data, param) \
36  HG_GEN_GET_TYPE(param) HG_GEN_GET_NAME(param);
37 
38 /* Generate structure */
39 #define HG_GEN_STRUCT(struct_type_name, fields) \
40 typedef struct \
41 { \
42  BOOST_PP_SEQ_FOR_EACH(HG_GEN_STRUCT_FIELD, , fields) \
43  \
44 } struct_type_name;
45 
46 /* Generate proc for struct field */
47 #define HG_GEN_PROC(r, struct_name, field) \
48  ret = BOOST_PP_CAT(hg_proc_, HG_GEN_GET_TYPE(field) \
49  (proc, &struct_name->HG_GEN_GET_NAME(field))); \
50  if (ret != HG_SUCCESS) { \
51  HG_ERROR_DEFAULT("Proc error"); \
52  ret = HG_FAIL; \
53  return ret; \
54  }
55 
56 /* Generate proc for struct */
57 #define HG_GEN_STRUCT_PROC(struct_type_name, fields) \
58 static HG_INLINE hg_return_t \
59  BOOST_PP_CAT(hg_proc_, struct_type_name) \
60  (hg_proc_t proc, void *data) \
61 { \
62  hg_return_t ret = HG_SUCCESS; \
63  struct_type_name *struct_data = (struct_type_name *) data; \
64  \
65  BOOST_PP_SEQ_FOR_EACH(HG_GEN_PROC, struct_data, fields) \
66  \
67  return ret; \
68 }
69 
70 /* Generate ((param) (datai)) element */
71 #define HG_GEN_PARAM_NAME(r, prefix, i, param) ((param) (BOOST_PP_CAT(prefix, i)))
72 
73 /* Generate parameter names and ((type) (name)) sequence */
74 #define HG_GEN_PARAM_NAME_SEQ(prefix, type_seq) \
75  BOOST_PP_SEQ_FOR_EACH_I(HG_GEN_PARAM_NAME, prefix, type_seq)
76 
77 /* Extract parameter (type name) element */
78 #define HG_GEN_DECL_FUNC_PARAM(r, is_ref, param) \
79  (HG_GEN_GET_TYPE(param) \
80  BOOST_PP_IF(is_ref, *, BOOST_PP_EMPTY())HG_GEN_GET_NAME(param))
81 
82 /* Extract (type name) sequence */
83 #define HG_GEN_DECL_FUNC_PARAM_SEQ(is_ref, param_seq) \
84  BOOST_PP_SEQ_FOR_EACH(HG_GEN_DECL_FUNC_PARAM, is_ref, param_seq)
85 
86 /* Extract function parameter declarations */
87 #define HG_GEN_DECL_FUNC_PARAMS(with_input, in_params, extra_in_params, \
88  with_output, out_params, extra_out_params) \
89  BOOST_PP_SEQ_TO_TUPLE( \
90  BOOST_PP_IF(BOOST_PP_OR(with_input, with_output), \
91  HG_GEN_DECL_FUNC_PARAM_SEQ(MERCURY_GEN_FALSE, in_params) \
92  HG_GEN_DECL_FUNC_PARAM_SEQ(MERCURY_GEN_FALSE, extra_in_params) \
93  HG_GEN_DECL_FUNC_PARAM_SEQ(MERCURY_GEN_TRUE, out_params) \
94  HG_GEN_DECL_FUNC_PARAM_SEQ(MERCURY_GEN_TRUE, extra_out_params), \
95  (void) \
96  ) \
97  )
98 
99 /* Extract parameter (get_name(param)) element */
100 #define HG_GEN_FUNC_PARAM(r, is_ref, param) \
101  (BOOST_PP_IF(is_ref, &, BOOST_PP_EMPTY())HG_GEN_GET_NAME(param))
102 
103 /* Extract (name) sequence */
104 #define HG_GEN_FUNC_PARAM_SEQ(is_ref, param_seq) \
105  BOOST_PP_SEQ_FOR_EACH(HG_GEN_FUNC_PARAM, is_ref, param_seq)
106 
107 /* Extract function parameters */
108 #define HG_GEN_FUNC_PARAMS(with_input, in_params, extra_in_params, \
109  with_output, out_params, extra_out_params) \
110  BOOST_PP_SEQ_TO_TUPLE( \
111  BOOST_PP_IF(BOOST_PP_OR(with_input, with_output), \
112  HG_GEN_FUNC_PARAM_SEQ(MERCURY_GEN_FALSE, in_params) \
113  HG_GEN_FUNC_PARAM_SEQ(MERCURY_GEN_FALSE, extra_in_params) \
114  HG_GEN_FUNC_PARAM_SEQ(MERCURY_GEN_TRUE, out_params) \
115  HG_GEN_FUNC_PARAM_SEQ(MERCURY_GEN_TRUE, extra_out_params), \
116  () \
117  ) \
118  )
119 
120 /* Generate declaration of parameters --> type name; */
121 #define HG_GEN_DECL_PARAMS(param_seq) \
122  BOOST_PP_SEQ_FOR_EACH(HG_GEN_STRUCT_FIELD, , param_seq)
123 
124 /* Assign param to struct field ( e.g., struct_name.param_1 = param_1; ) */
125 #define HG_SET_STRUCT_PARAM(r, struct_name, param) \
126  struct_name.HG_GEN_GET_NAME(param) = HG_GEN_GET_NAME(param);
127 
128 /* Assign param ((type) (name)) sequence to struct_name */
129 #define HG_SET_STRUCT_PARAMS(struct_name, params) \
130  BOOST_PP_SEQ_FOR_EACH(HG_SET_STRUCT_PARAM, struct_name, params)
131 
132 /* Assign struct_name field to param ( e.g., param_1 = struct_name.param_1; ) */
133 #define HG_GET_STRUCT_PARAM(r, struct_name, param) \
134  HG_GEN_GET_NAME(param) = struct_name.HG_GEN_GET_NAME(param);
135 
136 /* Assign struct_name fields to param ((type) (name)) sequence */
137 #define HG_GET_STRUCT_PARAMS(struct_name, params) \
138  BOOST_PP_SEQ_FOR_EACH(HG_GET_STRUCT_PARAM, struct_name, params)
139 
140 /* Assign struct_name field to out param ( e.g., *param_1 = struct_name.param_1; ) */
141 #define HG_GET_OUT_STRUCT_PARAM(r, struct_name, param) \
142  *HG_GEN_GET_NAME(param) = struct_name.HG_GEN_GET_NAME(param);
143 
144 /* Assign struct_name fields to out parame ((type) (name)) sequence */
145 #define HG_GET_OUT_STRUCT_PARAMS(struct_name, params) \
146  BOOST_PP_SEQ_FOR_EACH(HG_GET_OUT_STRUCT_PARAM, struct_name, params)
147 
148 /********************** Bulk data support boilerplate **********************/
149 
150 /* Initialized parameter */
151 #define HG_BULK_INIT_PARAM ((hg_bool_t)(bulk_initialized))
152 
153 /* Extra input parameters for bulk data */
154 #define HG_BULK_CONST_BUF ((const void*)(bulk_buf))
155 #define HG_BULK_BUF ((void*)(bulk_buf))
156 #define HG_BULK_COUNT ((hg_uint64_t)(bulk_count))
157 
158 #define HG_BULK_EXTRA_IN_PARAM \
159  HG_BULK_BUF HG_BULK_COUNT
160 
161 /* Bulk handle parameter */
162 #define HG_BULK_PARAM ((hg_bulk_t)(bulk_handle))
163 
164 /* Bulk block parameter */
165 #define HG_BULK_BLOCK_PARAM ((hg_bulk_t)(bulk_block_handle))
166 
167 /* Bulk request parameter */
168 #define HG_BULK_REQUEST_PARAM ((hg_bulk_request_t)(bulk_request))
169 
170 /* Bulk addr parameter */
171 #define HG_BULK_ADDR_PARAM ((na_addr_t)(bulk_addr))
172 
173 /* Initialize bulk data interface */
174 #define HG_BULK_INITIALIZE(with_ret, fail_ret) \
175  HG_Bulk_initialized(&HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_INIT_PARAM)), \
176  NULL); \
177  if (!HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_INIT_PARAM))) { \
178  hg_ret = HG_Bulk_init(na_class); \
179  if (hg_ret != HG_SUCCESS) { \
180  HG_ERROR_DEFAULT("Could not initialize bulk data shipper"); \
181  BOOST_PP_IF(with_ret, ret = fail_ret;, BOOST_PP_EMPTY()) \
182  goto done; \
183  } \
184  }
185 
186 /* Register bulk data */
187 #define HG_BULK_REGISTER(with_ret, fail_ret, bulk_read) \
188  hg_ret = HG_Bulk_handle_create( \
189  1, &HG_GEN_GET_NAME(BOOST_PP_SEQ_ELEM(0, HG_BULK_EXTRA_IN_PARAM)),\
190  &HG_GEN_GET_NAME(BOOST_PP_SEQ_ELEM(1, HG_BULK_EXTRA_IN_PARAM)), \
191  BOOST_PP_IF(bulk_read, HG_BULK_READ_ONLY, HG_BULK_READWRITE), \
192  &bulk_handle); \
193  if (hg_ret != HG_SUCCESS) { \
194  HG_ERROR_DEFAULT("Could not create bulk data handle\n"); \
195  BOOST_PP_IF(with_ret, ret = fail_ret;, BOOST_PP_EMPTY()) \
196  goto done; \
197  }
198 
199 /* Free bulk handle */
200 #define HG_BULK_FREE(with_ret, fail_ret) \
201  hg_ret = HG_Bulk_handle_free( \
202  HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_PARAM))); \
203  if (hg_ret != HG_SUCCESS) { \
204  HG_ERROR_DEFAULT("Could not free bulk data handle"); \
205  BOOST_PP_IF(with_ret, ret = fail_ret;, BOOST_PP_EMPTY()) \
206  goto done; \
207  } \
208 
209 /* Declare variables required for bulk data transfers */
210 #define HG_GEN_DECL_BULK_PARAMS \
211  HG_GEN_DECL_PARAMS(HG_BULK_PARAM HG_BULK_BLOCK_PARAM \
212  HG_BULK_REQUEST_PARAM HG_BULK_EXTRA_IN_PARAM HG_BULK_ADDR_PARAM)
213 
214 /* Get addr required for bulk data transfer source / dest */
215 #define HG_BULK_GET_ADDR \
216  HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_ADDR_PARAM)) = \
217  HG_Handler_get_addr(handle);
218 
219 /* Read bulk data and wait for the data to arrive */
220 #define HG_BULK_BLOCK_ALLOCATE \
221  HG_GEN_GET_NAME(BOOST_PP_SEQ_ELEM(1, HG_BULK_EXTRA_IN_PARAM)) = \
222  HG_Bulk_handle_get_size(HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_PARAM))); \
223  HG_GEN_GET_NAME(BOOST_PP_SEQ_ELEM(0, HG_BULK_EXTRA_IN_PARAM)) = \
224  malloc(HG_GEN_GET_NAME(BOOST_PP_SEQ_ELEM(1, HG_BULK_EXTRA_IN_PARAM))); \
225  HG_Bulk_handle_create(1, &HG_GEN_GET_NAME(BOOST_PP_SEQ_ELEM(0, HG_BULK_EXTRA_IN_PARAM)), \
226  &HG_GEN_GET_NAME(BOOST_PP_SEQ_ELEM(1, HG_BULK_EXTRA_IN_PARAM)), \
227  HG_BULK_READWRITE, \
228  &HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_BLOCK_PARAM)));
229 
230 /* Free block handle */
231 #define HG_BULK_BLOCK_FREE \
232  hg_ret = HG_Bulk_handle_free( \
233  HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_BLOCK_PARAM))); \
234  if (hg_ret != HG_SUCCESS) { \
235  HG_ERROR_DEFAULT("Could not free block call"); \
236  goto done; \
237  } \
238  free(bulk_buf);
239 
240 /* Write bulk data here and wait for the data to be there */
241 #define HG_BULK_TRANSFER(bulk_read) \
242  hg_ret = HG_Bulk_transfer(BOOST_PP_IF(bulk_read, HG_BULK_PULL, HG_BULK_PUSH), \
243  HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_ADDR_PARAM)), \
244  HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_PARAM)), \
245  0, \
246  HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_BLOCK_PARAM)), \
247  0, \
248  HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_COUNT)), \
249  &HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_REQUEST_PARAM))); \
250  if (hg_ret != HG_SUCCESS) { \
251  HG_ERROR_DEFAULT("Could not transfer bulk data"); \
252  goto done; \
253  } \
254  hg_ret = HG_Bulk_wait(HG_GEN_GET_NAME(BOOST_PP_SEQ_HEAD(HG_BULK_REQUEST_PARAM)), \
255  HG_MAX_IDLE_TIME, HG_STATUS_IGNORE); \
256  if (hg_ret != HG_SUCCESS) { \
257  HG_ERROR_DEFAULT("Could not complete bulk data transfer"); \
258  goto done; \
259  }
260 
261 /*****************************************************************************
262  * Basic BOOST macros:
263  * - MERCURY_GEN_PROC
264  * - MERCURY_REGISTER
265  *****************************************************************************/
266 
267 /* Generate struct and corresponding struct proc */
268 #define MERCURY_GEN_PROC(struct_type_name, fields) \
269  HG_GEN_STRUCT(struct_type_name, fields) \
270  HG_GEN_STRUCT_PROC(struct_type_name, fields)
271 
272 /* In the case of user defined structures / MERCURY_GEN_STRUCT_PROC can be
273  * used to generate the corresponding proc routine.
274  * E.g., if user defined struct:
275  * typedef struct {
276  * uint64_t cookie;
277  * } bla_handle_t;
278  * MERCURY_GEN_STRUCT_PROC( struct_type_name, field sequence ):
279  * MERCURY_GEN_STRUCT_PROC( bla_handle_t, ((uint64_t)(cookie)) )
280  */
281 #define MERCURY_GEN_STRUCT_PROC(struct_type_name, fields) \
282  HG_GEN_STRUCT_PROC(struct_type_name, fields)
283 
284 /* Register func_name */
285 #define MERCURY_REGISTER(func_name, in_struct_type_name, out_struct_type_name, \
286  rpc_cb) \
287  HG_Register(func_name, BOOST_PP_CAT(hg_proc_, in_struct_type_name), \
288  BOOST_PP_CAT(hg_proc_, out_struct_type_name), rpc_cb)
289 
290 /*****************************************************************************
291  * Advanced BOOST macros:
292  * - MERCURY_GEN_RPC_STUB
293  * - MERCURY_HANDLER_GEN_CALLBACK_STUB
294  *****************************************************************************/
295 
296 /* Custom function that applications can define for log purposes (none by default) */
297 #ifndef MERCURY_HANDLER_GEN_LOG_MESSAGE
298  #define MERCURY_HANDLER_GEN_LOG_MESSAGE(x)
299 #endif
300 
301 /* Generate client RPC stub */
302 #define MERCURY_GEN_RPC_STUB(gen_func_name, func_name, \
303  with_ret, ret_type_name, ret_fail, \
304  with_input, in_struct_type_name, in_params, \
305  with_output, out_struct_type_name, out_params, \
306  with_bulk, bulk_read) \
307  BOOST_PP_IF(with_ret, ret_type_name, void) \
308  gen_func_name HG_GEN_DECL_FUNC_PARAMS(with_input, in_params, \
309  BOOST_PP_IF(with_bulk, HG_BULK_EXTRA_IN_PARAM, BOOST_PP_EMPTY()), \
310  with_output, out_params, ) \
311  { \
312  BOOST_PP_IF(with_input, \
313  in_struct_type_name in_struct;, BOOST_PP_EMPTY()) \
314  BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), \
315  out_struct_type_name out_struct;, BOOST_PP_EMPTY()) \
316  BOOST_PP_IF(with_ret, ret_type_name ret;, BOOST_PP_EMPTY()) \
317  na_class_t *na_class; \
318  char *server_name; \
319  const char *info_string; \
320  na_addr_t addr; \
321  hg_id_t id; \
322  BOOST_PP_IF(with_bulk, HG_GEN_DECL_PARAMS(HG_BULK_PARAM), BOOST_PP_EMPTY()) \
323  hg_request_t request; \
324  hg_status_t status; \
325  hg_bool_t hg_initialized; \
326  hg_bool_t func_registered; \
327  hg_return_t hg_ret; \
328  na_return_t na_ret; \
329  \
330  /* Is mercury library initialized */ \
331  HG_Initialized(&hg_initialized, &na_class); \
332  if (!hg_initialized) { \
333  info_string = getenv(HG_PORT_NAME); \
334  if (!info_string) { /* passing NULL to NA_Initialize is bad! */ \
335  HG_ERROR_DEFAULT(HG_PORT_NAME " env var not set"); \
336  BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
337  goto done; \
338  } \
339  na_class = NA_Initialize(info_string, 0); \
340  hg_ret = HG_Init(na_class); \
341  if (hg_ret != HG_SUCCESS) { \
342  HG_ERROR_DEFAULT("Could not initialize Mercury"); \
343  BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
344  goto done; \
345  } \
346  } \
347  \
348  /* Get server_name if set */ \
349  server_name = getenv(HG_PORT_NAME); \
350  /* Look up addr id */ \
351  na_ret = NA_Addr_lookup_wait(na_class, server_name, &addr); \
352  if (na_ret != NA_SUCCESS) { \
353  HG_ERROR_DEFAULT("Could not lookup addr"); \
354  BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
355  goto done; \
356  } \
357  \
358  /* Check whether call has already been registered or not */ \
359  HG_Registered(BOOST_PP_STRINGIZE(func_name), &func_registered, &id); \
360  if (!func_registered) { \
361  id = MERCURY_REGISTER(BOOST_PP_STRINGIZE(func_name), \
362  BOOST_PP_IF(with_input, in_struct_type_name, void), \
363  BOOST_PP_IF( \
364  BOOST_PP_OR(with_output, with_ret), \
365  out_struct_type_name, \
366  void \
367  ), \
368  NULL \
369  ); \
370  } \
371  \
372  BOOST_PP_IF(with_bulk, HG_BULK_REGISTER(with_ret, ret_fail, bulk_read), \
373  BOOST_PP_EMPTY()) \
374  \
375  /* Fill input structure */ \
376  BOOST_PP_IF(with_input, \
377  HG_SET_STRUCT_PARAMS(in_struct, in_params \
378  BOOST_PP_IF(with_bulk, HG_BULK_PARAM, BOOST_PP_EMPTY())), \
379  BOOST_PP_EMPTY()) \
380  \
381  /* Forward call to remote addr and get a new request */ \
382  hg_ret = HG_Forward(addr, id, \
383  BOOST_PP_IF(with_input, &in_struct, NULL), \
384  BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), &out_struct, NULL), \
385  &request); \
386  if (hg_ret != HG_SUCCESS) { \
387  HG_ERROR_DEFAULT("Could not forward call"); \
388  BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
389  goto done; \
390  } \
391  \
392  /* Wait for call to be executed and return value to be sent back
393  * (Request is freed when the call completes)
394  */ \
395  hg_ret = HG_Wait(request, HG_MAX_IDLE_TIME, &status); \
396  if (hg_ret != HG_SUCCESS) { \
397  HG_ERROR_DEFAULT("Error during wait"); \
398  BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
399  goto done; \
400  } \
401  if (!status) { \
402  HG_ERROR_DEFAULT("Operation did not complete"); \
403  BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
404  goto done; \
405  } \
406  \
407  BOOST_PP_IF(with_bulk, HG_BULK_FREE(with_ret, ret_fail), BOOST_PP_EMPTY()) \
408  \
409  /* Get output parameters */ \
410  BOOST_PP_IF(with_ret, \
411  HG_GET_STRUCT_PARAMS(out_struct, ((ret_type)(ret))), \
412  BOOST_PP_EMPTY()) \
413  BOOST_PP_IF(with_output, \
414  HG_GET_OUT_STRUCT_PARAMS(out_struct, out_params), \
415  BOOST_PP_EMPTY()) \
416  \
417  /* Free request */ \
418  hg_ret = HG_Request_free(request); \
419  if (hg_ret != HG_SUCCESS) { \
420  HG_ERROR_DEFAULT("Could not free request"); \
421  BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
422  goto done; \
423  } \
424  \
425  /* Free addr id */ \
426  na_ret = NA_Addr_free(na_class, addr); \
427  if (na_ret != NA_SUCCESS) { \
428  HG_ERROR_DEFAULT("Could not free addr"); \
429  BOOST_PP_IF(with_ret, ret = ret_fail;, BOOST_PP_EMPTY()) \
430  goto done; \
431  } \
432  \
433  done: \
434  \
435  return BOOST_PP_IF(with_ret, ret, BOOST_PP_EMPTY()); \
436  }
437 
438 /* Generate handler callback */
439 #define MERCURY_HANDLER_GEN_CALLBACK_STUB(gen_func_name, func_name, \
440  with_ret, ret_type, \
441  with_input, in_struct_type_name, in_params, \
442  with_output, out_struct_type_name, out_params, \
443  with_bulk, bulk_read, \
444  with_thread, thread_pool) \
445  static \
446  BOOST_PP_IF(with_thread, \
447  HG_THREAD_RETURN_TYPE BOOST_PP_CAT(gen_func_name, _thread), \
448  hg_return_t gen_func_name) \
449  ( \
450  BOOST_PP_IF(with_thread, void *arg, hg_handle_t handle) \
451  ) \
452  { \
453  BOOST_PP_IF(with_thread, \
454  hg_handle_t handle = (hg_handle_t) arg; \
455  hg_thread_ret_t thread_ret = (hg_thread_ret_t) 0; \
456  ,\
457  BOOST_PP_EMPTY()) \
458  hg_return_t hg_ret = HG_SUCCESS; \
459  BOOST_PP_IF(with_input, \
460  in_struct_type_name in_struct;, BOOST_PP_EMPTY()) \
461  BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), \
462  out_struct_type_name out_struct;, BOOST_PP_EMPTY()) \
463  BOOST_PP_IF(with_input, HG_GEN_DECL_PARAMS(in_params), BOOST_PP_EMPTY()) \
464  BOOST_PP_IF(with_output, HG_GEN_DECL_PARAMS(out_params), BOOST_PP_EMPTY()) \
465  BOOST_PP_IF(with_ret, ret_type ret;, BOOST_PP_EMPTY()) \
466  BOOST_PP_IF(with_bulk, HG_GEN_DECL_BULK_PARAMS, BOOST_PP_EMPTY()) \
467  \
468  BOOST_PP_IF(with_bulk, HG_BULK_GET_ADDR, BOOST_PP_EMPTY()) \
469  \
470  /* Get input buffer */ \
471  BOOST_PP_IF(with_input, \
472  hg_ret = HG_Handler_get_input(handle, &in_struct); \
473  if (hg_ret != HG_SUCCESS) { \
474  HG_ERROR_DEFAULT("Could not get input struct"); \
475  goto done; \
476  } \
477  \
478  /* Get parameters */ \
479  HG_GET_STRUCT_PARAMS(in_struct, in_params \
480  BOOST_PP_IF(with_bulk, HG_BULK_PARAM, BOOST_PP_EMPTY())) \
481  , BOOST_PP_EMPTY()) \
482  \
483  BOOST_PP_IF(with_bulk, HG_BULK_BLOCK_ALLOCATE, BOOST_PP_EMPTY()) \
484  BOOST_PP_IF(with_bulk, \
485  BOOST_PP_IF(bulk_read, \
486  HG_BULK_TRANSFER(bulk_read), BOOST_PP_EMPTY()), \
487  BOOST_PP_EMPTY()) \
488  \
489  /* Call function */ \
490  MERCURY_HANDLER_GEN_LOG_MESSAGE(BOOST_PP_STRINGIZE(func_name)); \
491  BOOST_PP_IF(with_ret, ret =, BOOST_PP_EMPTY()) \
492  func_name HG_GEN_FUNC_PARAMS(with_input, in_params, \
493  BOOST_PP_IF(with_bulk, HG_BULK_EXTRA_IN_PARAM, BOOST_PP_EMPTY()), \
494  with_output, out_params, ); \
495  \
496  BOOST_PP_IF(with_bulk, \
497  BOOST_PP_IF(bulk_read, \
498  BOOST_PP_EMPTY(), HG_BULK_TRANSFER(bulk_read)), \
499  BOOST_PP_EMPTY()) \
500  \
501  BOOST_PP_IF(with_bulk, HG_BULK_BLOCK_FREE, BOOST_PP_EMPTY()) \
502  \
503  /* Fill output structure */ \
504  BOOST_PP_IF(with_ret, \
505  HG_SET_STRUCT_PARAMS(out_struct, ((ret_type)(ret))), \
506  BOOST_PP_EMPTY()) \
507  BOOST_PP_IF(with_output, \
508  HG_SET_STRUCT_PARAMS(out_struct, out_params), \
509  BOOST_PP_EMPTY()) \
510  \
511  /* Free handle and send response back */ \
512  hg_ret = HG_Handler_start_output(handle, \
513  BOOST_PP_IF(BOOST_PP_OR(with_output, with_ret), \
514  &out_struct, \
515  NULL) ); \
516  if (hg_ret != HG_SUCCESS) { \
517  HG_ERROR_DEFAULT("Could not start output"); \
518  goto done; \
519  } \
520  \
521  BOOST_PP_IF(with_input, \
522  hg_ret = HG_Handler_free_input(handle, &in_struct); \
523  if (hg_ret != HG_SUCCESS) { \
524  HG_ERROR_DEFAULT("Could not free input struct"); \
525  goto done; \
526  } \
527  , BOOST_PP_EMPTY()) \
528  \
529  hg_ret = HG_Handler_free(handle); \
530  if (hg_ret != HG_SUCCESS) { \
531  HG_ERROR_DEFAULT("Could not free handle"); \
532  goto done; \
533  } \
534  \
535  done: \
536  \
537  BOOST_PP_IF(with_thread, \
538  return thread_ret; \
539  , return hg_ret;) \
540  \
541  } \
542  BOOST_PP_IF(with_thread, \
543  static hg_return_t \
544  gen_func_name(hg_handle_t handle) \
545  { \
546  hg_return_t ret = HG_SUCCESS; \
547  hg_thread_pool_post(thread_pool, \
548  &BOOST_PP_CAT(gen_func_name, _thread), handle); \
549  return ret; \
550  } \
551  , BOOST_PP_EMPTY())
552 
553 #else /* HG_HAS_BOOST */
554 
555 #define MERCURY_REGISTER(func_name, in_struct_type_name, out_struct_type_name, \
556  rpc_cb) \
557  HG_Register(func_name, hg_proc_ ## in_struct_type_name, \
558  hg_proc_ ## out_struct_type_name, rpc_cb)
559 
560 #endif /* HG_HAS_BOOST */
561 
562 /* If no input args or output args, a void type can be
563  * passed to MERCURY_REGISTER
564  */
565 #define hg_proc_void NULL
566 
567 #endif /* MERCURY_MACROS_H */