text: /*
   * Copyright (c) 2010, ETH Zurich.
   * All rights reserved.
   * 
   * INTERFACE NAME: xmplthc
   * INTEFACE FILE: ../if/xmplthc.if
   * INTERFACE DESCRIPTION: Example thc interface
   * 
   * This file is distributed under the terms in the attached LICENSE
   * file. If you do not find this file, copies can be found by
   * writing to:
   * ETH Zurich D-INFK, Universitaetstr.6, CH-8092 Zurich.
   * Attn: Systems Group.
   * 
   * THIS FILE IS AUTOMATICALLY GENERATED BY FLOUNDER: DO NOT EDIT!
   */
  
  #include <barrelfish/barrelfish.h>
  #include <flounder/flounder_support.h>
  #include <if/xmplthc_defs.h>
  
  /*
   * Export function
   */
   errval_t xmplthc_export(void *st, idc_export_callback_fn *export_cb, xmplthc_connect_fn *connect_cb, struct waitset *ws, idc_export_flags_t flags)
  {
      struct xmplthc_export *e = malloc(sizeof(struct xmplthc_export ));
      if (e == NULL) {
          return(LIB_ERR_MALLOC_FAIL);
      }
      
      // fill in common parts of export struct
      e->connect_cb = connect_cb;
      e->waitset = ws;
      e->st = st;
      (e->common).export_callback = export_cb;
      (e->common).flags = flags;
      (e->common).connect_cb_st = e;
      (e->common).export_cb_st = st;
      
      // fill in connect handler for each enabled backend
      #ifdef CONFIG_FLOUNDER_BACKEND_LMP
      (e->common).lmp_connect_callback = xmplthc_lmp_connect_handler;
      #endif // CONFIG_FLOUNDER_BACKEND_LMP
      #ifdef CONFIG_FLOUNDER_BACKEND_UMP
      (e->common).ump_connect_callback = xmplthc_ump_connect_handler;
      #endif // CONFIG_FLOUNDER_BACKEND_UMP
      #ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
      (e->common).ump_connect_callback = xmplthc_ump_ipi_connect_handler;
      #endif // CONFIG_FLOUNDER_BACKEND_UMP_IPI
      #ifdef CONFIG_FLOUNDER_BACKEND_MULTIHOP
      (e->common).multihop_connect_callback = xmplthc_multihop_connect_handler;
      #endif // CONFIG_FLOUNDER_BACKEND_MULTIHOP
      
      return(idc_export_service(&(e->common)));
  }
  
  
  /*
   * Generic bind function
   */
  static  void xmplthc_bind_continuation_direct(void *st, errval_t err, struct xmplthc_binding *_binding)
  {
      // This bind cont function uses the different backends in the following order:
      // lmp ump_ipi ump multihop
      
      struct flounder_generic_bind_attempt *b = st;
      switch (b->driver_num) {
      case 0:
          (b->driver_num)++;
          #ifdef CONFIG_FLOUNDER_BACKEND_LMP
          // try next backend
          b->binding = malloc(sizeof(struct xmplthc_lmp_binding ));
          assert((b->binding) != NULL);
          err = xmplthc_lmp_bind(b->binding, b->iref, xmplthc_bind_continuation_direct, b, b->waitset, b->flags, DEFAULT_LMP_BUF_WORDS);
          if (err_is_fail(err)) {
              free(b->binding);
              _binding = NULL;
              goto out;
          } else {
              return;
          }
          #else
          // skip non-enabled backend (fall through)
          #endif // CONFIG_FLOUNDER_BACKEND_LMP
      case 1:
          #ifdef CONFIG_FLOUNDER_BACKEND_LMP
          if (err_is_ok(err)) {
              goto out;
          } else {
              free(b->binding);
              if (err_no(err) == MON_ERR_IDC_BIND_NOT_SAME_CORE) {
                  goto try_next_1;
              } else {
                  // report permanent failure to user
                  _binding = NULL;
                  goto out;
              }
          }
          try_next_1:
          #endif // CONFIG_FLOUNDER_BACKEND_LMP
          (b->driver_num)++;
          #ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
          // try next backend
          b->binding = malloc(sizeof(struct xmplthc_ump_ipi_binding ));
          assert((b->binding) != NULL);
          err = xmplthc_ump_ipi_bind(b->binding, b->iref, xmplthc_bind_continuation_direct, b, b->waitset, b->flags, DEFAULT_UMP_BUFLEN, DEFAULT_UMP_BUFLEN);
          if (err_is_fail(err)) {
              free(b->binding);
              _binding = NULL;
              goto out;
          } else {
              return;
          }
          #else
          // skip non-enabled backend (fall through)
          #endif // CONFIG_FLOUNDER_BACKEND_UMP_IPI
      case 2:
          #ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
          if (err_is_ok(err)) {
              goto out;
          } else {
              free(b->binding);
              if (true) {
                  goto try_next_2;
              } else {
                  // report permanent failure to user
                  _binding = NULL;
                  goto out;
              }
          }
          try_next_2:
          #endif // CONFIG_FLOUNDER_BACKEND_UMP_IPI
          (b->driver_num)++;
          #ifdef CONFIG_FLOUNDER_BACKEND_UMP
          // try next backend
          b->binding = malloc(sizeof(struct xmplthc_ump_binding ));
          assert((b->binding) != NULL);
          err = xmplthc_ump_bind(b->binding, b->iref, xmplthc_bind_continuation_direct, b, b->waitset, b->flags, DEFAULT_UMP_BUFLEN, DEFAULT_UMP_BUFLEN);
          if (err_is_fail(err)) {
              free(b->binding);
              _binding = NULL;
              goto out;
          } else {
              return;
          }
          #else
          // skip non-enabled backend (fall through)
          #endif // CONFIG_FLOUNDER_BACKEND_UMP
      case 3:
          #ifdef CONFIG_FLOUNDER_BACKEND_UMP
          if (err_is_ok(err)) {
              goto out;
          } else {
              free(b->binding);
              if (true) {
                  goto try_next_3;
              } else {
                  // report permanent failure to user
                  _binding = NULL;
                  goto out;
              }
          }
          try_next_3:
          #endif // CONFIG_FLOUNDER_BACKEND_UMP
          (b->driver_num)++;
          #ifdef CONFIG_FLOUNDER_BACKEND_MULTIHOP
          // try next backend
          b->binding = malloc(sizeof(struct xmplthc_multihop_binding ));
          assert((b->binding) != NULL);
          err = xmplthc_multihop_bind(b->binding, b->iref, xmplthc_bind_continuation_direct, b, b->waitset, b->flags);
          if (err_is_fail(err)) {
              free(b->binding);
              _binding = NULL;
              goto out;
          } else {
              return;
          }
          #else
          // skip non-enabled backend (fall through)
          #endif // CONFIG_FLOUNDER_BACKEND_MULTIHOP
      case 4:
          #ifdef CONFIG_FLOUNDER_BACKEND_MULTIHOP
          if (err_is_ok(err)) {
              goto out;
          } else {
              free(b->binding);
              if (!true) {
                  _binding = NULL;
                  goto out;
              }
          }
          #endif // CONFIG_FLOUNDER_BACKEND_MULTIHOP
          err = FLOUNDER_ERR_GENERIC_BIND_NO_MORE_DRIVERS;
          _binding = NULL;
          goto out;
      default:
          assert(!("invalid state"));
      }
      
      out:
      ((xmplthc_bind_continuation_fn *)(b->callback))(b->st, err, _binding);
      free(b);
  }
  
  static  void xmplthc_bind_contination_multihop(void *st, errval_t err, struct xmplthc_binding *_binding)
  {
      // This bind cont function uses the different backends in the following order:
      // lmp multihop ump_ipi ump
      
      struct flounder_generic_bind_attempt *b = st;
      switch (b->driver_num) {
      case 0:
          (b->driver_num)++;
          #ifdef CONFIG_FLOUNDER_BACKEND_LMP
          // try next backend
          b->binding = malloc(sizeof(struct xmplthc_lmp_binding ));
          assert((b->binding) != NULL);
          err = xmplthc_lmp_bind(b->binding, b->iref, xmplthc_bind_contination_multihop, b, b->waitset, b->flags, DEFAULT_LMP_BUF_WORDS);
          if (err_is_fail(err)) {
              free(b->binding);
              _binding = NULL;
              goto out;
          } else {
              return;
          }
          #else
          // skip non-enabled backend (fall through)
          #endif // CONFIG_FLOUNDER_BACKEND_LMP
      case 1:
          #ifdef CONFIG_FLOUNDER_BACKEND_LMP
          if (err_is_ok(err)) {
              goto out;
          } else {
              free(b->binding);
              if (err_no(err) == MON_ERR_IDC_BIND_NOT_SAME_CORE) {
                  goto try_next_1;
              } else {
                  // report permanent failure to user
                  _binding = NULL;
                  goto out;
              }
          }
          try_next_1:
          #endif // CONFIG_FLOUNDER_BACKEND_LMP
          (b->driver_num)++;
          #ifdef CONFIG_FLOUNDER_BACKEND_MULTIHOP
          // try next backend
          b->binding = malloc(sizeof(struct xmplthc_multihop_binding ));
          assert((b->binding) != NULL);
          err = xmplthc_multihop_bind(b->binding, b->iref, xmplthc_bind_contination_multihop, b, b->waitset, b->flags);
          if (err_is_fail(err)) {
              free(b->binding);
              _binding = NULL;
              goto out;
          } else {
              return;
          }
          #else
          // skip non-enabled backend (fall through)
          #endif // CONFIG_FLOUNDER_BACKEND_MULTIHOP
      case 2:
          #ifdef CONFIG_FLOUNDER_BACKEND_MULTIHOP
          if (err_is_ok(err)) {
              goto out;
          } else {
              free(b->binding);
              if (true) {
                  goto try_next_2;
              } else {
                  // report permanent failure to user
                  _binding = NULL;
                  goto out;
              }
          }
          try_next_2:
          #endif // CONFIG_FLOUNDER_BACKEND_MULTIHOP
          (b->driver_num)++;
          #ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
          // try next backend
          b->binding = malloc(sizeof(struct xmplthc_ump_ipi_binding ));
          assert((b->binding) != NULL);
          err = xmplthc_ump_ipi_bind(b->binding, b->iref, xmplthc_bind_contination_multihop, b, b->waitset, b->flags, DEFAULT_UMP_BUFLEN, DEFAULT_UMP_BUFLEN);
          if (err_is_fail(err)) {
              free(b->binding);
              _binding = NULL;
              goto out;
          } else {
              return;
          }
          #else
          // skip non-enabled backend (fall through)
          #endif // CONFIG_FLOUNDER_BACKEND_UMP_IPI
      case 3:
          #ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
          if (err_is_ok(err)) {
              goto out;
          } else {
              free(b->binding);
              if (true) {
                  goto try_next_3;
              } else {
                  // report permanent failure to user
                  _binding = NULL;
                  goto out;
              }
          }
          try_next_3:
          #endif // CONFIG_FLOUNDER_BACKEND_UMP_IPI
          (b->driver_num)++;
          #ifdef CONFIG_FLOUNDER_BACKEND_UMP
          // try next backend
          b->binding = malloc(sizeof(struct xmplthc_ump_binding ));
          assert((b->binding) != NULL);
          err = xmplthc_ump_bind(b->binding, b->iref, xmplthc_bind_contination_multihop, b, b->waitset, b->flags, DEFAULT_UMP_BUFLEN, DEFAULT_UMP_BUFLEN);
          if (err_is_fail(err)) {
              free(b->binding);
              _binding = NULL;
              goto out;
          } else {
              return;
          }
          #else
          // skip non-enabled backend (fall through)
          #endif // CONFIG_FLOUNDER_BACKEND_UMP
      case 4:
          #ifdef CONFIG_FLOUNDER_BACKEND_UMP
          if (err_is_ok(err)) {
              goto out;
          } else {
              free(b->binding);
              if (!true) {
                  _binding = NULL;
                  goto out;
              }
          }
          #endif // CONFIG_FLOUNDER_BACKEND_UMP
          err = FLOUNDER_ERR_GENERIC_BIND_NO_MORE_DRIVERS;
          _binding = NULL;
          goto out;
      default:
          assert(!("invalid state"));
      }
      
      out:
      ((xmplthc_bind_continuation_fn *)(b->callback))(b->st, err, _binding);
      free(b);
  }
  
   errval_t xmplthc_bind(iref_t iref, xmplthc_bind_continuation_fn *_continuation, void *st, struct waitset *waitset, idc_bind_flags_t flags)
  {
      // allocate state
      struct flounder_generic_bind_attempt *b = malloc(sizeof(struct flounder_generic_bind_attempt ));
      if (b == NULL) {
          return(LIB_ERR_MALLOC_FAIL);
      }
      
      // fill in binding state
      b->iref = iref;
      b->waitset = waitset;
      b->driver_num = 0;
      b->callback = _continuation;
      b->st = st;
      b->flags = flags;
      
      if (flags & IDC_BIND_FLAG_MULTIHOP) {
          xmplthc_bind_contination_multihop(b, SYS_ERR_OK, NULL);
      } else {
          xmplthc_bind_continuation_direct(b, SYS_ERR_OK, NULL);
      }
      
      return(SYS_ERR_OK);
  }
  
  /*
   * Copyright (c) 2010, ETH Zurich.
   * All rights reserved.
   * 
   * INTERFACE NAME: xmplthc
   * INTEFACE FILE: ../if/xmplthc.if
   * INTERFACE DESCRIPTION: Example thc interface
   * 
   * This file is distributed under the terms in the attached LICENSE
   * file. If you do not find this file, copies can be found by
   * writing to:
   * ETH Zurich D-INFK, Universitaetstr.6, CH-8092 Zurich.
   * Attn: Systems Group.
   * 
   * THIS FILE IS AUTOMATICALLY GENERATED BY FLOUNDER: DO NOT EDIT!
   */
  
  /*
   * Generated Stub for LMP on x86_64
   */
  
  #include <string.h>
  #include <barrelfish/barrelfish.h>
  #include <flounder/flounder_support.h>
  #include <flounder/flounder_support_lmp.h>
  #include <if/xmplthc_defs.h>
  
  /*
   * Send handler functions
   */
  static  void xmplthc_mymsg__lmp_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_lmp_binding *b = arg;
      errval_t err;
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          err = lmp_chan_send1(&(b->chan), b->flags, NULL_CAP, xmplthc_mymsg__msgnum | (((uintptr_t )(((_binding->tx_union).mymsg).i)) << 16));
          if (err_is_ok(err)) {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          } else {
              break;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      if (lmp_err_is_transient(err)) {
          // Construct retry closure and register it
          struct event_closure retry_closure = (struct event_closure){  .handler = xmplthc_mymsg__lmp_send_handler,  .arg = arg };
          err = lmp_chan_register_send(&(b->chan), _binding->waitset, retry_closure);
          assert(err_is_ok(err));
      } else {
          // Report error to user
          (_binding->error_handler)(_binding, err);
          _binding->tx_msgnum = 0;
          flounder_support_trigger_chan(&(_binding->register_chanstate));
          flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
      }
  }
  
  static  void xmplthc_mycall__lmp_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_lmp_binding *b = arg;
      errval_t err;
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          err = lmp_chan_send1(&(b->chan), b->flags, NULL_CAP, xmplthc_mycall__msgnum | (((uintptr_t )(((_binding->tx_union).mycall).i)) << 16));
          if (err_is_ok(err)) {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          } else {
              break;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      if (lmp_err_is_transient(err)) {
          // Construct retry closure and register it
          struct event_closure retry_closure = (struct event_closure){  .handler = xmplthc_mycall__lmp_send_handler,  .arg = arg };
          err = lmp_chan_register_send(&(b->chan), _binding->waitset, retry_closure);
          assert(err_is_ok(err));
      } else {
          // Report error to user
          (_binding->error_handler)(_binding, err);
          _binding->tx_msgnum = 0;
          flounder_support_trigger_chan(&(_binding->register_chanstate));
          flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
      }
  }
  
  static  void xmplthc_myresponse__lmp_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_lmp_binding *b = arg;
      errval_t err;
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          err = lmp_chan_send1(&(b->chan), (b->flags) & (~LMP_FLAG_SYNC), NULL_CAP, xmplthc_myresponse__msgnum);
          if (err_is_ok(err)) {
              (_binding->tx_msg_fragment)++;
              // fall through to next fragment
          } else {
              break;
          }
      case 1:
          err = flounder_stub_lmp_send_string(&(b->chan), b->flags, ((_binding->tx_union).myresponse).s, &(_binding->tx_str_pos), &(_binding->tx_str_len));
          if (err_is_ok(err)) {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          } else {
              break;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      if (lmp_err_is_transient(err)) {
          // Construct retry closure and register it
          struct event_closure retry_closure = (struct event_closure){  .handler = xmplthc_myresponse__lmp_send_handler,  .arg = arg };
          err = lmp_chan_register_send(&(b->chan), _binding->waitset, retry_closure);
          assert(err_is_ok(err));
      } else {
          // Report error to user
          (_binding->error_handler)(_binding, err);
          _binding->tx_msgnum = 0;
          flounder_support_trigger_chan(&(_binding->register_chanstate));
          flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
      }
  }
  
  static  void xmplthc_myrpc_call__lmp_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_lmp_binding *b = arg;
      errval_t err;
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          err = lmp_chan_send1(&(b->chan), b->flags, NULL_CAP, xmplthc_myrpc_call__msgnum | (((uintptr_t )(((_binding->tx_union).myrpc_call).i)) << 16));
          if (err_is_ok(err)) {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          } else {
              break;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      if (lmp_err_is_transient(err)) {
          // Construct retry closure and register it
          struct event_closure retry_closure = (struct event_closure){  .handler = xmplthc_myrpc_call__lmp_send_handler,  .arg = arg };
          err = lmp_chan_register_send(&(b->chan), _binding->waitset, retry_closure);
          assert(err_is_ok(err));
      } else {
          // Report error to user
          (_binding->error_handler)(_binding, err);
          _binding->tx_msgnum = 0;
          flounder_support_trigger_chan(&(_binding->register_chanstate));
          flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
      }
  }
  
  static  void xmplthc_myrpc_response__lmp_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_lmp_binding *b = arg;
      errval_t err;
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          err = lmp_chan_send1(&(b->chan), (b->flags) & (~LMP_FLAG_SYNC), NULL_CAP, xmplthc_myrpc_response__msgnum);
          if (err_is_ok(err)) {
              (_binding->tx_msg_fragment)++;
              // fall through to next fragment
          } else {
              break;
          }
      case 1:
          err = flounder_stub_lmp_send_string(&(b->chan), b->flags, ((_binding->tx_union).myrpc_response).s, &(_binding->tx_str_pos), &(_binding->tx_str_len));
          if (err_is_ok(err)) {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          } else {
              break;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      if (lmp_err_is_transient(err)) {
          // Construct retry closure and register it
          struct event_closure retry_closure = (struct event_closure){  .handler = xmplthc_myrpc_response__lmp_send_handler,  .arg = arg };
          err = lmp_chan_register_send(&(b->chan), _binding->waitset, retry_closure);
          assert(err_is_ok(err));
      } else {
          // Report error to user
          (_binding->error_handler)(_binding, err);
          _binding->tx_msgnum = 0;
          flounder_support_trigger_chan(&(_binding->register_chanstate));
          flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
      }
  }
  
  
  /*
   * Message sender functions
   */
  static  errval_t xmplthc_mymsg__lmp_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_mymsg__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).mymsg).i = i;
      FL_DEBUG("lmp TX xmplthc.mymsg\n");
      
      // try to send!
      xmplthc_mymsg__lmp_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_mycall__lmp_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_mycall__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).mycall).i = i;
      FL_DEBUG("lmp TX xmplthc.mycall\n");
      
      // try to send!
      xmplthc_mycall__lmp_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myresponse__lmp_send(struct xmplthc_binding *_binding, struct event_closure _continuation, const char *s)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_myresponse__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myresponse).s = ((char *)(s));
      FL_DEBUG("lmp TX xmplthc.myresponse\n");
      
      // try to send!
      xmplthc_myresponse__lmp_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myrpc_call__lmp_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_myrpc_call__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myrpc_call).i = i;
      FL_DEBUG("lmp TX xmplthc.myrpc_call\n");
      
      // try to send!
      xmplthc_myrpc_call__lmp_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myrpc_response__lmp_send(struct xmplthc_binding *_binding, struct event_closure _continuation, const char *s)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_myrpc_response__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myrpc_response).s = ((char *)(s));
      FL_DEBUG("lmp TX xmplthc.myrpc_response\n");
      
      // try to send!
      xmplthc_myrpc_response__lmp_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  
  /*
   * Send vtable
   */
  static  struct xmplthc_tx_vtbl xmplthc_lmp_tx_vtbl = {
      .mymsg = xmplthc_mymsg__lmp_send,
      .mycall = xmplthc_mycall__lmp_send,
      .myresponse = xmplthc_myresponse__lmp_send,
      .myrpc_call = xmplthc_myrpc_call__lmp_send,
      .myrpc_response = xmplthc_myrpc_response__lmp_send,
  };
  /*
   * Receive handler
   */
   void xmplthc_lmp_rx_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_lmp_binding *b = arg;
      errval_t err;
      
      struct lmp_recv_msg msg = LMP_RECV_MSG_INIT;
      struct capref cap;
      struct event_closure recv_closure = (struct event_closure){  .handler = xmplthc_lmp_rx_handler,  .arg = arg };
      
      do {
          // try to retrieve a message from the channel
          err = lmp_chan_recv(&(b->chan), &msg, &cap);
          // check if we succeeded
          if (err_is_fail(err)) {
              if (err_no(err) == LIB_ERR_NO_LMP_MSG) {
                  // no message
                  break;
              } else {
                  // real error
                  (_binding->error_handler)(_binding, err_push(err, LIB_ERR_LMP_CHAN_RECV));
                  return;
              }
          }
          
          // allocate a new receive slot if needed
          if (!capref_is_null(cap)) {
              err = lmp_chan_alloc_recv_slot(&(b->chan));
              if (err_is_fail(err)) {
                  (_binding->error_handler)(_binding, err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT));
              }
          }
          
          // is this the start of a new message?
          if ((_binding->rx_msgnum) == 0) {
              // check message length
              if (((msg.buf).msglen) == 0) {
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_EMPTY_MSG);
                  break;
              }
              // unmarshall message number from first word, set fragment to 0
              _binding->rx_msgnum = (((msg.words)[0]) & 0xffff);
              _binding->rx_msg_fragment = 0;
          }
          
          // switch on message number and fragment number
          switch (_binding->rx_msgnum) {
          case xmplthc_mymsg__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  // check length
                  if (((msg.buf).msglen) > 4) {
                      (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_LENGTH);
                      goto out;
                  }
                  
                  ((_binding->rx_union).mymsg).i = ((((msg.words)[0]) >> 16) & 0xffffffff);
                  
                  FL_DEBUG("lmp RX xmplthc.mymsg\n");
                  assert(((_binding->rx_vtbl).mymsg) != NULL);
                  ((_binding->rx_vtbl).mymsg)(_binding, ((_binding->rx_union).mymsg).i);
                  _binding->rx_msgnum = 0;
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          case xmplthc_mycall__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  // check length
                  if (((msg.buf).msglen) > 4) {
                      (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_LENGTH);
                      goto out;
                  }
                  
                  ((_binding->rx_union).mycall).i = ((((msg.words)[0]) >> 16) & 0xffffffff);
                  
                  FL_DEBUG("lmp RX xmplthc.mycall\n");
                  assert(((_binding->rx_vtbl).mycall) != NULL);
                  ((_binding->rx_vtbl).mycall)(_binding, ((_binding->rx_union).mycall).i);
                  _binding->rx_msgnum = 0;
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          case xmplthc_myresponse__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  // check length
                  if (((msg.buf).msglen) > 4) {
                      (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_LENGTH);
                      goto out;
                  }
                  
                  
                  (_binding->rx_msg_fragment)++;
                  break;
              case 1:
                  err = flounder_stub_lmp_recv_string(&msg, &(((_binding->rx_union).myresponse).s), &(_binding->rx_str_pos), &(_binding->rx_str_len));
                  if (err_is_ok(err)) {
                      FL_DEBUG("lmp RX xmplthc.myresponse\n");
                      assert(((_binding->rx_vtbl).myresponse) != NULL);
                      ((_binding->rx_vtbl).myresponse)(_binding, ((_binding->rx_union).myresponse).s);
                      _binding->rx_msgnum = 0;
                  } else {
                      if (err_no(err) != FLOUNDER_ERR_BUF_RECV_MORE) {
                          (_binding->error_handler)(_binding, err);
                      }
                  }
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          case xmplthc_myrpc_call__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  // check length
                  if (((msg.buf).msglen) > 4) {
                      (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_LENGTH);
                      goto out;
                  }
                  
                  ((_binding->rx_union).myrpc_call).i = ((((msg.words)[0]) >> 16) & 0xffffffff);
                  
                  FL_DEBUG("lmp RX xmplthc.myrpc_call\n");
                  assert(((_binding->rx_vtbl).myrpc_call) != NULL);
                  ((_binding->rx_vtbl).myrpc_call)(_binding, ((_binding->rx_union).myrpc_call).i);
                  _binding->rx_msgnum = 0;
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          case xmplthc_myrpc_response__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  // check length
                  if (((msg.buf).msglen) > 4) {
                      (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_LENGTH);
                      goto out;
                  }
                  
                  
                  (_binding->rx_msg_fragment)++;
                  break;
              case 1:
                  err = flounder_stub_lmp_recv_string(&msg, &(((_binding->rx_union).myrpc_response).s), &(_binding->rx_str_pos), &(_binding->rx_str_len));
                  if (err_is_ok(err)) {
                      FL_DEBUG("lmp RX xmplthc.myrpc_response\n");
                      assert(((_binding->rx_vtbl).myrpc_response) != NULL);
                      ((_binding->rx_vtbl).myrpc_response)(_binding, ((_binding->rx_union).myrpc_response).s);
                      _binding->rx_msgnum = 0;
                  } else {
                      if (err_no(err) != FLOUNDER_ERR_BUF_RECV_MORE) {
                          (_binding->error_handler)(_binding, err);
                      }
                  }
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          default:
              (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_MSGNUM);
              goto out;
          }
      } while (err_is_ok(err));
      out:
      // re-register for another receive notification
      err = lmp_chan_register_recv(&(b->chan), _binding->waitset, recv_closure);
      assert(err_is_ok(err));
  }
  
  
  /*
   * Control functions
   */
  static  bool xmplthc_lmp_can_send(struct xmplthc_binding *b)
  {
      return((b->tx_msgnum) == 0);
  }
  
  static  errval_t xmplthc_lmp_register_send(struct xmplthc_binding *b, struct waitset *ws, struct event_closure _continuation)
  {
      return(flounder_support_register(ws, &(b->register_chanstate), _continuation, xmplthc_lmp_can_send(b)));
  }
  
  static  void xmplthc_lmp_default_error_handler(struct xmplthc_binding *b, errval_t err)
  {
      DEBUG_ERR(err, "asynchronous error in Flounder-generated xmplthc lmp binding (default handler)");
      abort();
  }
  
  static  errval_t xmplthc_lmp_change_waitset(struct xmplthc_binding *_binding, struct waitset *ws)
  {
      struct xmplthc_lmp_binding *b = (void *)(_binding);
      
      // Migrate register and TX continuation notifications
      flounder_support_migrate_notify(&(_binding->register_chanstate), ws);
      flounder_support_migrate_notify(&(_binding->tx_cont_chanstate), ws);
      
      // change waitset on binding
      _binding->waitset = ws;
      
      // Migrate send and receive notifications
      lmp_chan_migrate_recv(&(b->chan), ws);
      lmp_chan_migrate_send(&(b->chan), ws);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_lmp_control(struct xmplthc_binding *_binding, idc_control_t control)
  {
      struct xmplthc_lmp_binding *b = (void *)(_binding);
      
      b->flags = idc_control_to_lmp_flags(control, b->flags);
      
      return(SYS_ERR_OK);
  }
  
  /*
   * Functions to initialise/destroy the binding state
   */
   void xmplthc_lmp_init(struct xmplthc_lmp_binding *b, struct waitset *waitset)
  {
      (b->b).st = NULL;
      (b->b).waitset = waitset;
      event_mutex_init(&((b->b).mutex), waitset);
      (b->b).can_send = xmplthc_lmp_can_send;
      (b->b).register_send = xmplthc_lmp_register_send;
      (b->b).error_handler = xmplthc_lmp_default_error_handler;
      (b->b).tx_vtbl = xmplthc_lmp_tx_vtbl;
      memset(&((b->b).rx_vtbl), 0, sizeof((b->b).rx_vtbl));
      flounder_support_waitset_chanstate_init(&((b->b).register_chanstate));
      flounder_support_waitset_chanstate_init(&((b->b).tx_cont_chanstate));
      (b->b).tx_msgnum = 0;
      (b->b).rx_msgnum = 0;
      (b->b).tx_msg_fragment = 0;
      (b->b).rx_msg_fragment = 0;
      (b->b).tx_str_pos = 0;
      (b->b).rx_str_pos = 0;
      (b->b).tx_str_len = 0;
      (b->b).rx_str_len = 0;
      (b->b).bind_cont = NULL;
      lmp_chan_init(&(b->chan));
      (b->b).change_waitset = xmplthc_lmp_change_waitset;
      (b->b).control = xmplthc_lmp_control;
      b->flags = LMP_SEND_FLAGS_DEFAULT;
  }
  
   void xmplthc_lmp_destroy(struct xmplthc_lmp_binding *b)
  {
      flounder_support_waitset_chanstate_destroy(&((b->b).register_chanstate));
      flounder_support_waitset_chanstate_destroy(&((b->b).tx_cont_chanstate));
      lmp_chan_destroy(&(b->chan));
  }
  
  
  /*
   * Bind function
   */
  static  void xmplthc_lmp_bind_continuation(void *st, errval_t err, struct lmp_chan *chan)
  {
      struct xmplthc_lmp_binding *b = st;
      
      if (err_is_ok(err)) {
          // allocate a cap receive slot
          err = lmp_chan_alloc_recv_slot(chan);
          if (err_is_fail(err)) {
              err = err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT);
              goto fail;
          }
          
          // register for receive
          err = lmp_chan_register_recv(chan, (b->b).waitset, (struct event_closure){  .handler = xmplthc_lmp_rx_handler,  .arg = b });
          if (err_is_fail(err)) {
              err = err_push(err, LIB_ERR_CHAN_REGISTER_RECV);
              goto fail;
          }
      } else {
          fail:
          xmplthc_lmp_destroy(b);
      }
      
      ((b->b).bind_cont)((b->b).st, err, &(b->b));
  }
  
   errval_t xmplthc_lmp_bind(struct xmplthc_lmp_binding *b, iref_t iref, xmplthc_bind_continuation_fn *_continuation, void *st, struct waitset *waitset, idc_bind_flags_t flags, size_t lmp_buflen)
  {
      errval_t err;
      xmplthc_lmp_init(b, waitset);
      (b->b).st = st;
      (b->b).bind_cont = _continuation;
      err = lmp_chan_bind(&(b->chan), (struct lmp_bind_continuation){  .handler = xmplthc_lmp_bind_continuation,  .st = b }, &((b->b).event_qnode), iref, lmp_buflen);
      if (err_is_fail(err)) {
          xmplthc_lmp_destroy(b);
      }
      return(err);
  }
  
  
  /*
   * Connect callback for export
   */
   errval_t xmplthc_lmp_connect_handler(void *st, size_t buflen_words, struct capref endpoint, struct lmp_chan **retchan)
  {
      struct xmplthc_export *e = st;
      errval_t err;
      
      // allocate storage for binding
      struct xmplthc_lmp_binding *b = malloc(sizeof(struct xmplthc_lmp_binding ));
      if (b == NULL) {
          return(LIB_ERR_MALLOC_FAIL);
      }
      
      struct xmplthc_binding *_binding = &(b->b);
      xmplthc_lmp_init(b, e->waitset);
      
      // run user's connect handler
      err = ((e->connect_cb)(e->st, _binding));
      if (err_is_fail(err)) {
          // connection refused
          xmplthc_lmp_destroy(b);
          return(err);
      }
      
      // accept the connection and setup the channel
      // FIXME: user policy needed to decide on the size of the message buffer?
      err = lmp_chan_accept(&(b->chan), buflen_words, endpoint);
      if (err_is_fail(err)) {
          err = err_push(err, LIB_ERR_LMP_CHAN_ACCEPT);
          (_binding->error_handler)(_binding, err);
          return(err);
      }
      
      // allocate a cap receive slot
      err = lmp_chan_alloc_recv_slot(&(b->chan));
      if (err_is_fail(err)) {
          err = err_push(err, LIB_ERR_LMP_ALLOC_RECV_SLOT);
          (_binding->error_handler)(_binding, err);
          return(err);
      }
      
      // register for receive
      err = lmp_chan_register_recv(&(b->chan), _binding->waitset, (struct event_closure){  .handler = xmplthc_lmp_rx_handler,  .arg = b });
      if (err_is_fail(err)) {
          err = err_push(err, LIB_ERR_CHAN_REGISTER_RECV);
          (_binding->error_handler)(_binding, err);
          return(err);
      }
      
      *retchan = (&(b->chan));
      
      return(SYS_ERR_OK);
  }
  
  /*
   * Copyright (c) 2010, ETH Zurich.
   * All rights reserved.
   * 
   * INTERFACE NAME: xmplthc
   * INTEFACE FILE: ../if/xmplthc.if
   * INTERFACE DESCRIPTION: Example thc interface
   * 
   * This file is distributed under the terms in the attached LICENSE
   * file. If you do not find this file, copies can be found by
   * writing to:
   * ETH Zurich D-INFK, Universitaetstr.6, CH-8092 Zurich.
   * Attn: Systems Group.
   * 
   * THIS FILE IS AUTOMATICALLY GENERATED BY FLOUNDER: DO NOT EDIT!
   */
  
  #ifdef CONFIG_FLOUNDER_BACKEND_UMP
  
  /*
   * Generated Stub for UMP
   */
  
  #include <barrelfish/barrelfish.h>
  #include <barrelfish/monitor_client.h>
  #include <flounder/flounder_support.h>
  #include <flounder/flounder_support_ump.h>
  #include <if/xmplthc_defs.h>
  
  /*
   * Send handler function
   */
  static  void xmplthc_ump_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_ump_binding *b = arg;
      errval_t err;
      err = SYS_ERR_OK;
      
      volatile struct ump_message *msg;
      struct ump_control ctrl;
      bool tx_notify = false;
      
      // do we need to (and can we) send a cap ack?
      if ((((b->ump_state).capst).tx_cap_ack) && flounder_stub_ump_can_send(&(b->ump_state))) {
          flounder_stub_ump_send_cap_ack(&(b->ump_state));
          ((b->ump_state).capst).tx_cap_ack = false;
          tx_notify = true;
      }
      
      // Switch on current outgoing message number
      switch (_binding->tx_msgnum) {
      case 0:
          break;
      case xmplthc_mymsg__msgnum:
          // Switch on current outgoing message fragment
          switch (_binding->tx_msg_fragment) {
          case 0:
              // check if we can send another message
              if (!flounder_stub_ump_can_send(&(b->ump_state))) {
                  tx_notify = true;
                  break;
              }
              
              // send the next fragment
              msg = ump_chan_get_next(&((b->ump_state).chan), &ctrl);
              flounder_stub_ump_control_fill(&(b->ump_state), &ctrl, xmplthc_mymsg__msgnum);
              (msg->data)[0] = (((_binding->tx_union).mymsg).i);
              flounder_stub_ump_barrier();
              (msg->header).control = ctrl;
              (_binding->tx_msg_fragment)++;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          case 1:
              // we've sent all the fragments, we must just be waiting for caps
              assert((((b->ump_state).capst).tx_capnum) <= 0);
              break;
          default:
              assert(!("invalid fragment"));
              (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
          }
          break;
      case xmplthc_mycall__msgnum:
          // Switch on current outgoing message fragment
          switch (_binding->tx_msg_fragment) {
          case 0:
              // check if we can send another message
              if (!flounder_stub_ump_can_send(&(b->ump_state))) {
                  tx_notify = true;
                  break;
              }
              
              // send the next fragment
              msg = ump_chan_get_next(&((b->ump_state).chan), &ctrl);
              flounder_stub_ump_control_fill(&(b->ump_state), &ctrl, xmplthc_mycall__msgnum);
              (msg->data)[0] = (((_binding->tx_union).mycall).i);
              flounder_stub_ump_barrier();
              (msg->header).control = ctrl;
              (_binding->tx_msg_fragment)++;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          case 1:
              // we've sent all the fragments, we must just be waiting for caps
              assert((((b->ump_state).capst).tx_capnum) <= 0);
              break;
          default:
              assert(!("invalid fragment"));
              (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
          }
          break;
      case xmplthc_myresponse__msgnum:
          // Switch on current outgoing message fragment
          switch (_binding->tx_msg_fragment) {
          case 0:
              err = flounder_stub_ump_send_string(&(b->ump_state), xmplthc_myresponse__msgnum, ((_binding->tx_union).myresponse).s, &(_binding->tx_str_pos), &(_binding->tx_str_len));
              if (err_is_fail(err)) {
                  if (err_no(err) == FLOUNDER_ERR_BUF_SEND_MORE) {
                      tx_notify = true;
                  } else {
                      // Permanent error, report to user
                      (_binding->error_handler)(_binding, err);
                      _binding->tx_msgnum = 0;
                      flounder_support_trigger_chan(&(_binding->register_chanstate));
                      flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
                  }
                  break;
              }
              (_binding->tx_msg_fragment)++;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          case 1:
              // we've sent all the fragments, we must just be waiting for caps
              assert((((b->ump_state).capst).tx_capnum) <= 0);
              break;
          default:
              assert(!("invalid fragment"));
              (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
          }
          break;
      case xmplthc_myrpc_call__msgnum:
          // Switch on current outgoing message fragment
          switch (_binding->tx_msg_fragment) {
          case 0:
              // check if we can send another message
              if (!flounder_stub_ump_can_send(&(b->ump_state))) {
                  tx_notify = true;
                  break;
              }
              
              // send the next fragment
              msg = ump_chan_get_next(&((b->ump_state).chan), &ctrl);
              flounder_stub_ump_control_fill(&(b->ump_state), &ctrl, xmplthc_myrpc_call__msgnum);
              (msg->data)[0] = (((_binding->tx_union).myrpc_call).i);
              flounder_stub_ump_barrier();
              (msg->header).control = ctrl;
              (_binding->tx_msg_fragment)++;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          case 1:
              // we've sent all the fragments, we must just be waiting for caps
              assert((((b->ump_state).capst).tx_capnum) <= 0);
              break;
          default:
              assert(!("invalid fragment"));
              (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
          }
          break;
      case xmplthc_myrpc_response__msgnum:
          // Switch on current outgoing message fragment
          switch (_binding->tx_msg_fragment) {
          case 0:
              err = flounder_stub_ump_send_string(&(b->ump_state), xmplthc_myrpc_response__msgnum, ((_binding->tx_union).myrpc_response).s, &(_binding->tx_str_pos), &(_binding->tx_str_len));
              if (err_is_fail(err)) {
                  if (err_no(err) == FLOUNDER_ERR_BUF_SEND_MORE) {
                      tx_notify = true;
                  } else {
                      // Permanent error, report to user
                      (_binding->error_handler)(_binding, err);
                      _binding->tx_msgnum = 0;
                      flounder_support_trigger_chan(&(_binding->register_chanstate));
                      flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
                  }
                  break;
              }
              (_binding->tx_msg_fragment)++;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          case 1:
              // we've sent all the fragments, we must just be waiting for caps
              assert((((b->ump_state).capst).tx_capnum) <= 0);
              break;
          default:
              assert(!("invalid fragment"));
              (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
          }
          break;
      default:
          assert(!("invalid msgnum"));
          (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
      }
      
      // Send a notification if necessary
      if (tx_notify) {
      }
  }
  
  
  /*
   * Capability sender function
   */
  static  void xmplthc_ump_cap_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_ump_binding *b = arg;
      errval_t err;
      err = SYS_ERR_OK;
      
      assert(((b->ump_state).capst).rx_cap_ack);
      assert(((b->ump_state).capst).monitor_mutex_held);
      
      // Switch on current outgoing message
      switch (_binding->tx_msgnum) {
      default:
          assert(!("invalid message number"));
          (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
      }
  }
  
  
  /*
   * Receive handler
   */
   void xmplthc_ump_rx_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_ump_binding *b = arg;
      errval_t err;
      err = SYS_ERR_OK;
      
      volatile struct ump_message *msg;
      int msgnum;
      
      while (true) {
          // try to retrieve a message from the channel
          err = ump_chan_recv(&((b->ump_state).chan), &msg);
          // check if we succeeded
          if (err_is_fail(err)) {
              if (err_no(err) == LIB_ERR_NO_UMP_MSG) {
                  // no message
                  break;
              } else {
                  // real error
                  (_binding->error_handler)(_binding, err_push(err, LIB_ERR_UMP_CHAN_RECV));
                  return;
              }
          }
          
          // process control word
          msgnum = flounder_stub_ump_control_process(&(b->ump_state), (msg->header).control);
          
          // is this a dummy message (ACK)?
          if (msgnum == FL_UMP_ACK) {
              goto loopnext;
          }
          
          // is this a cap ack for a pending tx message
          if (msgnum == FL_UMP_CAP_ACK) {
              assert(!(((b->ump_state).capst).rx_cap_ack));
              ((b->ump_state).capst).rx_cap_ack = true;
              if (((b->ump_state).capst).monitor_mutex_held) {
                  xmplthc_ump_cap_send_handler(b);
              }
              goto loopnext;
          }
          
          // is this the start of a new message?
          if ((_binding->rx_msgnum) == 0) {
              _binding->rx_msgnum = msgnum;
              _binding->rx_msg_fragment = 0;
          }
          
          // switch on message number and fragment number
          switch (_binding->rx_msgnum) {
          case xmplthc_mymsg__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  ((_binding->rx_union).mymsg).i = (((msg->data)[0]) & 0xffffffff);
                  
                  FL_DEBUG("ump RX xmplthc.mymsg\n");
                  assert(((_binding->rx_vtbl).mymsg) != NULL);
                  ((_binding->rx_vtbl).mymsg)(_binding, ((_binding->rx_union).mymsg).i);
                  _binding->rx_msgnum = 0;
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          case xmplthc_mycall__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  ((_binding->rx_union).mycall).i = (((msg->data)[0]) & 0xffffffff);
                  
                  FL_DEBUG("ump RX xmplthc.mycall\n");
                  assert(((_binding->rx_vtbl).mycall) != NULL);
                  ((_binding->rx_vtbl).mycall)(_binding, ((_binding->rx_union).mycall).i);
                  _binding->rx_msgnum = 0;
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          case xmplthc_myresponse__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  err = flounder_stub_ump_recv_string(msg, &(((_binding->rx_union).myresponse).s), &(_binding->rx_str_pos), &(_binding->rx_str_len));
                  if (err_is_ok(err)) {
                      FL_DEBUG("ump RX xmplthc.myresponse\n");
                      assert(((_binding->rx_vtbl).myresponse) != NULL);
                      ((_binding->rx_vtbl).myresponse)(_binding, ((_binding->rx_union).myresponse).s);
                      _binding->rx_msgnum = 0;
                  } else {
                      if (err_no(err) != FLOUNDER_ERR_BUF_RECV_MORE) {
                          (_binding->error_handler)(_binding, err);
                      }
                  }
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          case xmplthc_myrpc_call__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  ((_binding->rx_union).myrpc_call).i = (((msg->data)[0]) & 0xffffffff);
                  
                  FL_DEBUG("ump RX xmplthc.myrpc_call\n");
                  assert(((_binding->rx_vtbl).myrpc_call) != NULL);
                  ((_binding->rx_vtbl).myrpc_call)(_binding, ((_binding->rx_union).myrpc_call).i);
                  _binding->rx_msgnum = 0;
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          case xmplthc_myrpc_response__msgnum:
              switch (_binding->rx_msg_fragment) {
              case 0:
                  err = flounder_stub_ump_recv_string(msg, &(((_binding->rx_union).myrpc_response).s), &(_binding->rx_str_pos), &(_binding->rx_str_len));
                  if (err_is_ok(err)) {
                      FL_DEBUG("ump RX xmplthc.myrpc_response\n");
                      assert(((_binding->rx_vtbl).myrpc_response) != NULL);
                      ((_binding->rx_vtbl).myrpc_response)(_binding, ((_binding->rx_union).myrpc_response).s);
                      _binding->rx_msgnum = 0;
                  } else {
                      if (err_no(err) != FLOUNDER_ERR_BUF_RECV_MORE) {
                          (_binding->error_handler)(_binding, err);
                      }
                  }
                  break;
              default:
                  (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                  goto out;
              }
              break;
          default:
              (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_MSGNUM);
              goto out;
          }
          
          loopnext:
          // send an ack if the channel is now full
          if (flounder_stub_ump_needs_ack(&(b->ump_state))) {
              // run our send process if we need to
              if ((((b->ump_state).capst).tx_cap_ack) || ((_binding->tx_msgnum) != 0)) {
                  xmplthc_ump_send_handler(b);
              } else {
                  flounder_stub_ump_send_ack(&(b->ump_state));
              }
          }
      }
      
      out:
      // register for receive notification
      err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = xmplthc_ump_rx_handler,  .arg = _binding });
      if (err_is_fail(err)) {
          (_binding->error_handler)(_binding, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
      }
      
      out_no_reregister:
      __attribute__((unused));
      // run our send process, if we need to
      if ((((b->ump_state).capst).tx_cap_ack) || ((_binding->tx_msgnum) != 0)) {
          xmplthc_ump_send_handler(b);
      } else {
          // otherwise send a forced ack if the channel is now full
          if (flounder_stub_ump_needs_ack(&(b->ump_state))) {
              flounder_stub_ump_send_ack(&(b->ump_state));
          }
      }
  }
  
  
  /*
   * Cap send/receive handlers
   */
  static  void xmplthc_ump_cap_rx_handler(void *arg, errval_t success, struct capref cap, uint32_t capid)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_ump_binding *b = arg;
      errval_t err;
      err = SYS_ERR_OK;
      
      assert(capid == (((b->ump_state).capst).rx_capnum));
      
      // Check if there's an associated error
      // FIXME: how should we report this to the user? at present we just deliver a NULL capref
      if (err_is_fail(success)) {
          DEBUG_ERR(err, "error in cap transfer");
      }
      
      // Switch on current incoming message
      switch (_binding->rx_msgnum) {
      default:
          assert(!("invalid message number"));
          (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
      }
  }
  
  
  /*
   * Message sender functions
   */
  static  errval_t xmplthc_mymsg__ump_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_mymsg__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).mymsg).i = i;
      FL_DEBUG("ump TX xmplthc.mymsg\n");
      
      // try to send!
      xmplthc_ump_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_mycall__ump_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_mycall__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).mycall).i = i;
      FL_DEBUG("ump TX xmplthc.mycall\n");
      
      // try to send!
      xmplthc_ump_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myresponse__ump_send(struct xmplthc_binding *_binding, struct event_closure _continuation, const char *s)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_myresponse__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myresponse).s = ((char *)(s));
      FL_DEBUG("ump TX xmplthc.myresponse\n");
      
      // try to send!
      xmplthc_ump_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myrpc_call__ump_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_myrpc_call__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myrpc_call).i = i;
      FL_DEBUG("ump TX xmplthc.myrpc_call\n");
      
      // try to send!
      xmplthc_ump_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myrpc_response__ump_send(struct xmplthc_binding *_binding, struct event_closure _continuation, const char *s)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and arguments
      _binding->tx_msgnum = xmplthc_myrpc_response__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myrpc_response).s = ((char *)(s));
      FL_DEBUG("ump TX xmplthc.myrpc_response\n");
      
      // try to send!
      xmplthc_ump_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  
  /*
   * Send vtable
   */
  static  struct xmplthc_tx_vtbl xmplthc_ump_tx_vtbl = {
      .mymsg = xmplthc_mymsg__ump_send,
      .mycall = xmplthc_mycall__ump_send,
      .myresponse = xmplthc_myresponse__ump_send,
      .myrpc_call = xmplthc_myrpc_call__ump_send,
      .myrpc_response = xmplthc_myrpc_response__ump_send,
  };
  /*
   * Control functions
   */
  static  bool xmplthc_ump_can_send(struct xmplthc_binding *b)
  {
      return((b->tx_msgnum) == 0);
  }
  
  static  errval_t xmplthc_ump_register_send(struct xmplthc_binding *b, struct waitset *ws, struct event_closure _continuation)
  {
      return(flounder_support_register(ws, &(b->register_chanstate), _continuation, xmplthc_ump_can_send(b)));
  }
  
  static  void xmplthc_ump_default_error_handler(struct xmplthc_binding *b, errval_t err)
  {
      DEBUG_ERR(err, "asynchronous error in Flounder-generated xmplthc ump binding (default handler)");
      abort();
  }
  
  static  errval_t xmplthc_ump_change_waitset(struct xmplthc_binding *_binding, struct waitset *ws)
  {
      struct xmplthc_ump_binding *b = (void *)(_binding);
      errval_t err;
      
      // change waitset on private monitor binding if we have one
      if ((((b->ump_state).chan).monitor_binding) != get_monitor_binding()) {
          err = flounder_support_change_monitor_waitset(((b->ump_state).chan).monitor_binding, ws);
          if (err_is_fail(err)) {
              return(err_push(err, FLOUNDER_ERR_CHANGE_MONITOR_WAITSET));
          }
      }
      
      // change waitset on binding
      _binding->waitset = ws;
      
      // re-register for receive (if previously registered)
      err = ump_chan_deregister_recv(&((b->ump_state).chan));
      if (err_is_fail(err) && (err_no(err) != LIB_ERR_CHAN_NOT_REGISTERED)) {
          return(err_push(err, LIB_ERR_CHAN_DEREGISTER_RECV));
      }
      if (err_is_ok(err)) {
          err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = xmplthc_ump_rx_handler,  .arg = _binding });
          if (err_is_fail(err)) {
              return(err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
          }
      }
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_ump_control(struct xmplthc_binding *_binding, idc_control_t control)
  {
      // no control flags are supported
      return(SYS_ERR_OK);
  }
  
  
  /*
   * Function to destroy the binding state
   */
   void xmplthc_ump_destroy(struct xmplthc_ump_binding *b)
  {
      flounder_support_waitset_chanstate_destroy(&((b->b).register_chanstate));
      flounder_support_waitset_chanstate_destroy(&((b->b).tx_cont_chanstate));
      ump_chan_destroy(&((b->ump_state).chan));
  }
  
  
  /*
   * Bind function
   */
  static  void xmplthc_ump_bind_continuation(void *st, errval_t err, struct ump_chan *chan, struct capref notify_cap)
  {
      struct xmplthc_binding *_binding = st;
      struct xmplthc_ump_binding *b = st;
      
      if (err_is_ok(err)) {
          // notify cap ignored
          // setup cap handlers
          (((b->ump_state).chan).cap_handlers).st = b;
          (((b->ump_state).chan).cap_handlers).cap_receive_handler = xmplthc_ump_cap_rx_handler;
          // register for receive notification
          err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = xmplthc_ump_rx_handler,  .arg = _binding });
          if (err_is_fail(err)) {
              (_binding->error_handler)(_binding, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
          }
      } else {
          xmplthc_ump_destroy(b);
      }
      
      (_binding->bind_cont)(_binding->st, err, _binding);
  }
  
   errval_t xmplthc_ump_init(struct xmplthc_ump_binding *b, struct waitset *waitset, volatile void *inbuf, size_t inbufsize, volatile void *outbuf, size_t outbufsize)
  {
      errval_t err;
      struct xmplthc_binding *_binding = &(b->b);
      (b->b).st = NULL;
      (b->b).waitset = waitset;
      event_mutex_init(&((b->b).mutex), waitset);
      (b->b).can_send = xmplthc_ump_can_send;
      (b->b).register_send = xmplthc_ump_register_send;
      (b->b).error_handler = xmplthc_ump_default_error_handler;
      (b->b).tx_vtbl = xmplthc_ump_tx_vtbl;
      memset(&((b->b).rx_vtbl), 0, sizeof((b->b).rx_vtbl));
      flounder_support_waitset_chanstate_init(&((b->b).register_chanstate));
      flounder_support_waitset_chanstate_init(&((b->b).tx_cont_chanstate));
      (b->b).tx_msgnum = 0;
      (b->b).rx_msgnum = 0;
      (b->b).tx_msg_fragment = 0;
      (b->b).rx_msg_fragment = 0;
      (b->b).tx_str_pos = 0;
      (b->b).rx_str_pos = 0;
      (b->b).tx_str_len = 0;
      (b->b).rx_str_len = 0;
      (b->b).bind_cont = NULL;
      flounder_stub_ump_state_init(&(b->ump_state), b);
      err = ump_chan_init(&((b->ump_state).chan), inbuf, inbufsize, outbuf, outbufsize);
      if (err_is_fail(err)) {
          xmplthc_ump_destroy(b);
          return(err_push(err, LIB_ERR_UMP_CHAN_INIT));
      }
      
      (b->b).change_waitset = xmplthc_ump_change_waitset;
      (b->b).control = xmplthc_ump_control;
      // register for receive notification
      err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = xmplthc_ump_rx_handler,  .arg = _binding });
      if (err_is_fail(err)) {
          (_binding->error_handler)(_binding, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
      }
      
      return(err);
  }
  
  static  void xmplthc_ump_new_monitor_binding_continuation(void *st, errval_t err, struct monitor_binding *monitor_binding)
  {
      struct xmplthc_binding *_binding = st;
      struct xmplthc_ump_binding *b = st;
      
      if (err_is_fail(err)) {
          err = err_push(err, LIB_ERR_MONITOR_CLIENT_BIND);
          goto out;
      }
      
      ((b->ump_state).chan).monitor_binding = monitor_binding;
      // start the bind on the new monitor binding
      err = ump_chan_bind(&((b->ump_state).chan), (struct ump_bind_continuation){  .handler = xmplthc_ump_bind_continuation,  .st = b }, &(_binding->event_qnode), b->iref, monitor_binding, b->inchanlen, b->outchanlen, NULL_CAP);
      
      out:
      if (err_is_fail(err)) {
          (_binding->bind_cont)(_binding->st, err, _binding);
          xmplthc_ump_destroy(b);
      }
  }
  
   errval_t xmplthc_ump_bind(struct xmplthc_ump_binding *b, iref_t iref, xmplthc_bind_continuation_fn *_continuation, void *st, struct waitset *waitset, idc_bind_flags_t flags, size_t inchanlen, size_t outchanlen)
  {
      errval_t err;
      (b->b).st = NULL;
      (b->b).waitset = waitset;
      event_mutex_init(&((b->b).mutex), waitset);
      (b->b).can_send = xmplthc_ump_can_send;
      (b->b).register_send = xmplthc_ump_register_send;
      (b->b).error_handler = xmplthc_ump_default_error_handler;
      (b->b).tx_vtbl = xmplthc_ump_tx_vtbl;
      memset(&((b->b).rx_vtbl), 0, sizeof((b->b).rx_vtbl));
      flounder_support_waitset_chanstate_init(&((b->b).register_chanstate));
      flounder_support_waitset_chanstate_init(&((b->b).tx_cont_chanstate));
      (b->b).tx_msgnum = 0;
      (b->b).rx_msgnum = 0;
      (b->b).tx_msg_fragment = 0;
      (b->b).rx_msg_fragment = 0;
      (b->b).tx_str_pos = 0;
      (b->b).rx_str_pos = 0;
      (b->b).tx_str_len = 0;
      (b->b).rx_str_len = 0;
      (b->b).bind_cont = NULL;
      flounder_stub_ump_state_init(&(b->ump_state), b);
      (b->b).change_waitset = xmplthc_ump_change_waitset;
      (b->b).control = xmplthc_ump_control;
      (b->b).st = st;
      (b->b).bind_cont = _continuation;
      b->iref = iref;
      b->inchanlen = inchanlen;
      b->outchanlen = outchanlen;
      
      // do we need a new monitor binding?
      if (flags & IDC_BIND_FLAG_RPC_CAP_TRANSFER) {
          err = monitor_client_new_binding(xmplthc_ump_new_monitor_binding_continuation, b, waitset, DEFAULT_LMP_BUF_WORDS);
      } else {
          err = ump_chan_bind(&((b->ump_state).chan), (struct ump_bind_continuation){  .handler = xmplthc_ump_bind_continuation,  .st = b }, &((b->b).event_qnode), iref, get_monitor_binding(), inchanlen, outchanlen, NULL_CAP);
      }
      
      if (err_is_fail(err)) {
          xmplthc_ump_destroy(b);
      }
      return(err);
  }
  
  
  /*
   * Connect callback for export
   */
   errval_t xmplthc_ump_connect_handler(void *st, struct monitor_binding *mb, uintptr_t mon_id, struct capref frame, size_t inchanlen, size_t outchanlen, struct capref notify_cap)
  {
      struct xmplthc_export *e = st;
      errval_t err;
      
      // allocate storage for binding
      struct xmplthc_ump_binding *b = malloc(sizeof(struct xmplthc_ump_binding ));
      if (b == NULL) {
          return(LIB_ERR_MALLOC_FAIL);
      }
      
      struct xmplthc_binding *_binding = &(b->b);
      (b->b).st = NULL;
      (b->b).waitset = (e->waitset);
      event_mutex_init(&((b->b).mutex), e->waitset);
      (b->b).can_send = xmplthc_ump_can_send;
      (b->b).register_send = xmplthc_ump_register_send;
      (b->b).error_handler = xmplthc_ump_default_error_handler;
      (b->b).tx_vtbl = xmplthc_ump_tx_vtbl;
      memset(&((b->b).rx_vtbl), 0, sizeof((b->b).rx_vtbl));
      flounder_support_waitset_chanstate_init(&((b->b).register_chanstate));
      flounder_support_waitset_chanstate_init(&((b->b).tx_cont_chanstate));
      (b->b).tx_msgnum = 0;
      (b->b).rx_msgnum = 0;
      (b->b).tx_msg_fragment = 0;
      (b->b).rx_msg_fragment = 0;
      (b->b).tx_str_pos = 0;
      (b->b).rx_str_pos = 0;
      (b->b).tx_str_len = 0;
      (b->b).rx_str_len = 0;
      (b->b).bind_cont = NULL;
      flounder_stub_ump_state_init(&(b->ump_state), b);
      (b->b).change_waitset = xmplthc_ump_change_waitset;
      (b->b).control = xmplthc_ump_control;
      
      // run user's connect handler
      err = ((e->connect_cb)(e->st, _binding));
      if (err_is_fail(err)) {
          // connection refused
          xmplthc_ump_destroy(b);
          return(err);
      }
      
      // accept the connection and setup the channel
      err = ump_chan_accept(&((b->ump_state).chan), mon_id, frame, inchanlen, outchanlen);
      if (err_is_fail(err)) {
          err = err_push(err, LIB_ERR_UMP_CHAN_ACCEPT);
          (_binding->error_handler)(_binding, err);
          return(err);
      }
      
      // notify cap ignored
      // setup cap handlers
      (((b->ump_state).chan).cap_handlers).st = b;
      (((b->ump_state).chan).cap_handlers).cap_receive_handler = xmplthc_ump_cap_rx_handler;
      
      // register for receive notification
      err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = xmplthc_ump_rx_handler,  .arg = _binding });
      if (err_is_fail(err)) {
          (_binding->error_handler)(_binding, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
      }
      
      // send back bind reply
      ump_chan_send_bind_reply(mb, &((b->ump_state).chan), SYS_ERR_OK, mon_id, NULL_CAP);
      
      return(SYS_ERR_OK);
  }
  
  #endif // CONFIG_FLOUNDER_BACKEND_UMP
  /*
   * Copyright (c) 2010, ETH Zurich.
   * All rights reserved.
   * 
   * INTERFACE NAME: xmplthc
   * INTEFACE FILE: ../if/xmplthc.if
   * INTERFACE DESCRIPTION: Example thc interface
   * 
   * This file is distributed under the terms in the attached LICENSE
   * file. If you do not find this file, copies can be found by
   * writing to:
   * ETH Zurich D-INFK, Universitaetstr.6, CH-8092 Zurich.
   * Attn: Systems Group.
   * 
   * THIS FILE IS AUTOMATICALLY GENERATED BY FLOUNDER: DO NOT EDIT!
   */
  
  #ifdef CONFIG_FLOUNDER_BACKEND_MULTIHOP
  /*
   * Generated Stub for Multihop on x86_64
   */
  
  #include <string.h>
  #include <barrelfish/barrelfish.h>
  #include <flounder/flounder_support.h>
  #include <if/xmplthc_defs.h>
  
  /*
   * Capability sender function
   */
  
  /*
   * Send handler functions
   */
  static  void xmplthc_mymsg__multihop_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_multihop_binding *mb = arg;
      
      errval_t err = SYS_ERR_OK;
      uint64_t *msg;
      uint64_t msg_size;
      
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          // Calculate size of message & allocate it
          msg_size = 8;
          assert(msg_size != 0);
          msg = malloc(msg_size);
          
          // copy words from fixed size fragments
          // [[MsgCode,ArgFieldFragment int32 [NamedField "i"] 0]]
          msg[0] = (xmplthc_mymsg__msgnum | (((uint64_t )(((_binding->tx_union).mymsg).i)) << 16));
          
          
          // copy strings
          
          // copy buffers
          
          // try to send!
          (_binding->tx_msg_fragment)++;
          mb->message = msg;
          err = multihop_send_message(&(mb->chan), MKCONT(xmplthc_mymsg__multihop_send_handler, _binding), msg, msg_size);
          if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
              (_binding->tx_msg_fragment)--;
              err = multihop_chan_register_send(&(mb->chan), _binding->waitset, MKCONT(xmplthc_mymsg__multihop_send_handler, _binding));
              assert(err_is_ok(err));
          }
          if (err_is_fail(err)) {
              break;
          } else {
              return;
          }
      case 1:
          // all fragments are sent
          free(mb->message);
          if (multihop_chan_is_window_full(&(mb->chan))) {
              mb->trigger_chan = true;
              return;
          } else {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      
      // Report error to user
      (_binding->error_handler)(_binding, err);
      _binding->tx_msgnum = 0;
      flounder_support_trigger_chan(&(_binding->register_chanstate));
      flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
  }
  
  static  void xmplthc_mycall__multihop_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_multihop_binding *mb = arg;
      
      errval_t err = SYS_ERR_OK;
      uint64_t *msg;
      uint64_t msg_size;
      
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          // Calculate size of message & allocate it
          msg_size = 8;
          assert(msg_size != 0);
          msg = malloc(msg_size);
          
          // copy words from fixed size fragments
          // [[MsgCode,ArgFieldFragment int32 [NamedField "i"] 0]]
          msg[0] = (xmplthc_mycall__msgnum | (((uint64_t )(((_binding->tx_union).mycall).i)) << 16));
          
          
          // copy strings
          
          // copy buffers
          
          // try to send!
          (_binding->tx_msg_fragment)++;
          mb->message = msg;
          err = multihop_send_message(&(mb->chan), MKCONT(xmplthc_mycall__multihop_send_handler, _binding), msg, msg_size);
          if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
              (_binding->tx_msg_fragment)--;
              err = multihop_chan_register_send(&(mb->chan), _binding->waitset, MKCONT(xmplthc_mycall__multihop_send_handler, _binding));
              assert(err_is_ok(err));
          }
          if (err_is_fail(err)) {
              break;
          } else {
              return;
          }
      case 1:
          // all fragments are sent
          free(mb->message);
          if (multihop_chan_is_window_full(&(mb->chan))) {
              mb->trigger_chan = true;
              return;
          } else {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      
      // Report error to user
      (_binding->error_handler)(_binding, err);
      _binding->tx_msgnum = 0;
      flounder_support_trigger_chan(&(_binding->register_chanstate));
      flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
  }
  
  static  void xmplthc_myresponse__multihop_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_multihop_binding *mb = arg;
      
      errval_t err = SYS_ERR_OK;
      uint64_t *msg;
      uint64_t msg_size;
      uint8_t *msg2;
      uint64_t o_frag_size;
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          // Calculate size of message & allocate it
          msg_size = 8;
          msg_size = ((msg_size + strlen(((_binding->tx_union).myresponse).s)) + 9);
          assert(msg_size != 0);
          msg = malloc(msg_size);
          
          // copy words from fixed size fragments
          // [[MsgCode]]
          msg[0] = xmplthc_myresponse__msgnum;
          msg2 = (((uint8_t *)(msg)) + 8);
          
          // copy strings
          o_frag_size = ((uint64_t )(strlen(((_binding->tx_union).myresponse).s)));
          memcpy(msg2, &o_frag_size, 8);
          memcpy(msg2 + 8, ((_binding->tx_union).myresponse).s, o_frag_size);
          msg2 = ((msg2 + o_frag_size) + 8);
          
          // copy buffers
          
          // try to send!
          (_binding->tx_msg_fragment)++;
          mb->message = msg;
          err = multihop_send_message(&(mb->chan), MKCONT(xmplthc_myresponse__multihop_send_handler, _binding), msg, msg_size);
          if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
              (_binding->tx_msg_fragment)--;
              err = multihop_chan_register_send(&(mb->chan), _binding->waitset, MKCONT(xmplthc_myresponse__multihop_send_handler, _binding));
              assert(err_is_ok(err));
          }
          if (err_is_fail(err)) {
              break;
          } else {
              return;
          }
      case 1:
          // all fragments are sent
          free(mb->message);
          if (multihop_chan_is_window_full(&(mb->chan))) {
              mb->trigger_chan = true;
              return;
          } else {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      
      // Report error to user
      (_binding->error_handler)(_binding, err);
      _binding->tx_msgnum = 0;
      flounder_support_trigger_chan(&(_binding->register_chanstate));
      flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
  }
  
  static  void xmplthc_myrpc_call__multihop_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_multihop_binding *mb = arg;
      
      errval_t err = SYS_ERR_OK;
      uint64_t *msg;
      uint64_t msg_size;
      
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          // Calculate size of message & allocate it
          msg_size = 8;
          assert(msg_size != 0);
          msg = malloc(msg_size);
          
          // copy words from fixed size fragments
          // [[MsgCode,ArgFieldFragment int32 [NamedField "i"] 0]]
          msg[0] = (xmplthc_myrpc_call__msgnum | (((uint64_t )(((_binding->tx_union).myrpc_call).i)) << 16));
          
          
          // copy strings
          
          // copy buffers
          
          // try to send!
          (_binding->tx_msg_fragment)++;
          mb->message = msg;
          err = multihop_send_message(&(mb->chan), MKCONT(xmplthc_myrpc_call__multihop_send_handler, _binding), msg, msg_size);
          if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
              (_binding->tx_msg_fragment)--;
              err = multihop_chan_register_send(&(mb->chan), _binding->waitset, MKCONT(xmplthc_myrpc_call__multihop_send_handler, _binding));
              assert(err_is_ok(err));
          }
          if (err_is_fail(err)) {
              break;
          } else {
              return;
          }
      case 1:
          // all fragments are sent
          free(mb->message);
          if (multihop_chan_is_window_full(&(mb->chan))) {
              mb->trigger_chan = true;
              return;
          } else {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      
      // Report error to user
      (_binding->error_handler)(_binding, err);
      _binding->tx_msgnum = 0;
      flounder_support_trigger_chan(&(_binding->register_chanstate));
      flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
  }
  
  static  void xmplthc_myrpc_response__multihop_send_handler(void *arg)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_multihop_binding *mb = arg;
      
      errval_t err = SYS_ERR_OK;
      uint64_t *msg;
      uint64_t msg_size;
      uint8_t *msg2;
      uint64_t o_frag_size;
      
      // Switch on current outgoing message fragment
      switch (_binding->tx_msg_fragment) {
      case 0:
          // Calculate size of message & allocate it
          msg_size = 8;
          msg_size = ((msg_size + strlen(((_binding->tx_union).myrpc_response).s)) + 9);
          assert(msg_size != 0);
          msg = malloc(msg_size);
          
          // copy words from fixed size fragments
          // [[MsgCode]]
          msg[0] = xmplthc_myrpc_response__msgnum;
          msg2 = (((uint8_t *)(msg)) + 8);
          
          // copy strings
          o_frag_size = ((uint64_t )(strlen(((_binding->tx_union).myrpc_response).s)));
          memcpy(msg2, &o_frag_size, 8);
          memcpy(msg2 + 8, ((_binding->tx_union).myrpc_response).s, o_frag_size);
          msg2 = ((msg2 + o_frag_size) + 8);
          
          // copy buffers
          
          // try to send!
          (_binding->tx_msg_fragment)++;
          mb->message = msg;
          err = multihop_send_message(&(mb->chan), MKCONT(xmplthc_myrpc_response__multihop_send_handler, _binding), msg, msg_size);
          if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
              (_binding->tx_msg_fragment)--;
              err = multihop_chan_register_send(&(mb->chan), _binding->waitset, MKCONT(xmplthc_myrpc_response__multihop_send_handler, _binding));
              assert(err_is_ok(err));
          }
          if (err_is_fail(err)) {
              break;
          } else {
              return;
          }
      case 1:
          // all fragments are sent
          free(mb->message);
          if (multihop_chan_is_window_full(&(mb->chan))) {
              mb->trigger_chan = true;
              return;
          } else {
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
              return;
          }
      default:
          assert(!("invalid fragment"));
          err = FLOUNDER_ERR_INVALID_STATE;
      }
      
      
      // Report error to user
      (_binding->error_handler)(_binding, err);
      _binding->tx_msgnum = 0;
      flounder_support_trigger_chan(&(_binding->register_chanstate));
      flounder_support_deregister_chan(&(_binding->tx_cont_chanstate));
  }
  
  
  /*
   * Cap receive handlers
   */
   void xmplthc_multihop_caps_rx_handler(void *arg, errval_t success, struct capref cap, uint32_t capid)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_multihop_binding *mb = arg;
      
      
      assert(capid == ((mb->capst).rx_capnum));
      
      // Check if there's an associated error
      // FIXME: how should we report this to the user? at present we just deliver a NULL capref
      if (err_is_fail(success)) {
          DEBUG_ERR(success, "could not send cap over multihop channel");
      }
      
      // Switch on current incoming message
      switch (_binding->rx_msgnum) {
      default:
          assert(!("invalid message number"));
          (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
      }
  }
  
  
  /*
   * Message sender functions
   */
  static  errval_t xmplthc_mymsg__multihop_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and the arguments
      _binding->tx_msgnum = xmplthc_mymsg__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).mymsg).i = i;
      FL_DEBUG("multihop TX xmplthc.mymsg\n");
      
      // try to send!
      xmplthc_mymsg__multihop_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_mycall__multihop_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and the arguments
      _binding->tx_msgnum = xmplthc_mycall__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).mycall).i = i;
      FL_DEBUG("multihop TX xmplthc.mycall\n");
      
      // try to send!
      xmplthc_mycall__multihop_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myresponse__multihop_send(struct xmplthc_binding *_binding, struct event_closure _continuation, const char *s)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and the arguments
      _binding->tx_msgnum = xmplthc_myresponse__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myresponse).s = ((char *)(s));
      FL_DEBUG("multihop TX xmplthc.myresponse\n");
      
      // try to send!
      xmplthc_myresponse__multihop_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myrpc_call__multihop_send(struct xmplthc_binding *_binding, struct event_closure _continuation, int32_t i)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and the arguments
      _binding->tx_msgnum = xmplthc_myrpc_call__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myrpc_call).i = i;
      FL_DEBUG("multihop TX xmplthc.myrpc_call\n");
      
      // try to send!
      xmplthc_myrpc_call__multihop_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  static  errval_t xmplthc_myrpc_response__multihop_send(struct xmplthc_binding *_binding, struct event_closure _continuation, const char *s)
  {
      // check that we can accept an outgoing message
      if ((_binding->tx_msgnum) != 0) {
          return(FLOUNDER_ERR_TX_BUSY);
      }
      
      // register send continuation
      if ((_continuation.handler) != NULL) {
          errval_t _err;
          _err = flounder_support_register(_binding->waitset, &(_binding->tx_cont_chanstate), _continuation, false);
          // may fail if previous continuation hasn't fired yet
          if (err_is_fail(_err)) {
              if (err_no(_err) == LIB_ERR_CHAN_ALREADY_REGISTERED) {
                  return(FLOUNDER_ERR_TX_BUSY);
              } else {
                  assert(!("shouldn't happen"));
                  return(_err);
              }
          }
      }
      
      // store message number and the arguments
      _binding->tx_msgnum = xmplthc_myrpc_response__msgnum;
      _binding->tx_msg_fragment = 0;
      ((_binding->tx_union).myrpc_response).s = ((char *)(s));
      FL_DEBUG("multihop TX xmplthc.myrpc_response\n");
      
      // try to send!
      xmplthc_myrpc_response__multihop_send_handler(_binding);
      
      return(SYS_ERR_OK);
  }
  
  
  /*
   * Send vtable
   */
  static  struct xmplthc_tx_vtbl xmplthc_multihop_tx_vtbl = {
      .mymsg = xmplthc_mymsg__multihop_send,
      .mycall = xmplthc_mycall__multihop_send,
      .myresponse = xmplthc_myresponse__multihop_send,
      .myrpc_call = xmplthc_myrpc_call__multihop_send,
      .myrpc_response = xmplthc_myrpc_response__multihop_send,
  };
  /*
   * Receive handler
   */
   void xmplthc_multihop_rx_handler(void *arg, uint8_t *message, size_t message_len)
  {
      // Get the binding state from our argument pointer
      struct xmplthc_binding *_binding = arg;
      struct xmplthc_multihop_binding *mb = arg;
      
      uint64_t o_frag_size;
      uint8_t *msg;
      
      // if this a dummy message?
      if (message_len == 0) {
          if (mb->trigger_chan) {
              mb->trigger_chan = false;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
          }
          return;
      }
      // is this the start of a new message?
      if ((_binding->rx_msgnum) == 0) {
          // unmarshall message number from first word, set fragment to 0
          _binding->rx_msgnum = ((message[0]) & 0xffff);
          _binding->rx_msg_fragment = 0;
          (mb->capst).rx_capnum = 0;
      } else {
          assert(!"should not happen");
      }
      
      // switch on message number
      switch (_binding->rx_msgnum) {
      case xmplthc_mymsg__msgnum:
          // store fixed size fragments
          ((_binding->rx_union).mymsg).i = (((((uint64_t *)(message))[0]) >> 16) & 0xffffffff);
          msg = (message + 8);
          
          // receive strings
          
          // receive buffers
          
          free(message);
          if (mb->trigger_chan) {
              mb->trigger_chan = false;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
          }
          FL_DEBUG("multihop RX xmplthc.mymsg\n");
          assert(((_binding->rx_vtbl).mymsg) != NULL);
          ((_binding->rx_vtbl).mymsg)(_binding, ((_binding->rx_union).mymsg).i);
          _binding->rx_msgnum = 0;
          break;
      case xmplthc_mycall__msgnum:
          // store fixed size fragments
          ((_binding->rx_union).mycall).i = (((((uint64_t *)(message))[0]) >> 16) & 0xffffffff);
          msg = (message + 8);
          
          // receive strings
          
          // receive buffers
          
          free(message);
          if (mb->trigger_chan) {
              mb->trigger_chan = false;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
          }
          FL_DEBUG("multihop RX xmplthc.mycall\n");
          assert(((_binding->rx_vtbl).mycall) != NULL);
          ((_binding->rx_vtbl).mycall)(_binding, ((_binding->rx_union).mycall).i);
          _binding->rx_msgnum = 0;
          break;
      case xmplthc_myresponse__msgnum:
          // store fixed size fragments
          msg = (message + 8);
          
          // receive strings
          o_frag_size = 0;
          memcpy(&o_frag_size, msg, 8);
          ((_binding->rx_union).myresponse).s = malloc(o_frag_size + 1);
          memcpy(((_binding->rx_union).myresponse).s, msg + 8, o_frag_size);
          (((_binding->rx_union).myresponse).s)[o_frag_size] = 0;
          msg = ((msg + o_frag_size) + 8);
          
          // receive buffers
          
          free(message);
          if (mb->trigger_chan) {
              mb->trigger_chan = false;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
          }
          FL_DEBUG("multihop RX xmplthc.myresponse\n");
          assert(((_binding->rx_vtbl).myresponse) != NULL);
          ((_binding->rx_vtbl).myresponse)(_binding, ((_binding->rx_union).myresponse).s);
          _binding->rx_msgnum = 0;
          break;
      case xmplthc_myrpc_call__msgnum:
          // store fixed size fragments
          ((_binding->rx_union).myrpc_call).i = (((((uint64_t *)(message))[0]) >> 16) & 0xffffffff);
          msg = (message + 8);
          
          // receive strings
          
          // receive buffers
          
          free(message);
          if (mb->trigger_chan) {
              mb->trigger_chan = false;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
          }
          FL_DEBUG("multihop RX xmplthc.myrpc_call\n");
          assert(((_binding->rx_vtbl).myrpc_call) != NULL);
          ((_binding->rx_vtbl).myrpc_call)(_binding, ((_binding->rx_union).myrpc_call).i);
          _binding->rx_msgnum = 0;
          break;
      case xmplthc_myrpc_response__msgnum:
          // store fixed size fragments
          msg = (message + 8);
          
          // receive strings
          o_frag_size = 0;
          memcpy(&o_frag_size, msg, 8);
          ((_binding->rx_union).myrpc_response).s = malloc(o_frag_size + 1);
          memcpy(((_binding->rx_union).myrpc_response).s, msg + 8, o_frag_size);
          (((_binding->rx_union).myrpc_response).s)[o_frag_size] = 0;
          msg = ((msg + o_frag_size) + 8);
          
          // receive buffers
          
          free(message);
          if (mb->trigger_chan) {
              mb->trigger_chan = false;
              _binding->tx_msgnum = 0;
              flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
              flounder_support_trigger_chan(&(_binding->register_chanstate));
          }
          FL_DEBUG("multihop RX xmplthc.myrpc_response\n");
          assert(((_binding->rx_vtbl).myrpc_response) != NULL);
          ((_binding->rx_vtbl).myrpc_response)(_binding, ((_binding->rx_union).myrpc_response).s);
          _binding->rx_msgnum = 0;
          break;
      default:
          (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_MSGNUM);
          return;
      }
  }
  
  
  /*
   * Control functions
   */
  static  bool xmplthc_multihop_can_send(struct xmplthc_binding *b)
  {
      struct xmplthc_multihop_binding *mb = (struct xmplthc_multihop_binding *)(b);
      return(((b->tx_msgnum) == 0) && (!multihop_chan_is_window_full(&(mb->chan))));
  }
  
  static  errval_t xmplthc_multihop_register_send(struct xmplthc_binding *b, struct waitset *ws, struct event_closure _continuation)
  {
      return(flounder_support_register(ws, &(b->register_chanstate), _continuation, xmplthc_multihop_can_send(b)));
  }
  
  static  void xmplthc_multihop_default_error_handler(struct xmplthc_binding *b, errval_t err)
  {
      DEBUG_ERR(err, "asynchronous error in Flounder-generated xmplthc multihop binding (default handler)");
      abort();
  }
  
  static  errval_t xmplthc_multihop_change_waitset(struct xmplthc_binding *_binding, struct waitset *ws)
  {
      struct xmplthc_multihop_binding *mb = (void *)(_binding);
      
      // change waitset on binding
      _binding->waitset = ws;
      
      // change waitset on multi-hop channel
      return(multihop_chan_change_waitset(&(mb->chan), ws));
  }
  
  static  errval_t xmplthc_multihop_control(struct xmplthc_binding *_binding, idc_control_t control)
  {
      // No control flags supported
      return(SYS_ERR_OK);
  }
  
  /*
   * Functions to initialise/destroy the binding state
   */
   void xmplthc_multihop_init(struct xmplthc_multihop_binding *mb, struct waitset *waitset)
  {
      (mb->b).st = NULL;
      (mb->b).waitset = waitset;
      event_mutex_init(&((mb->b).mutex), waitset);
      (mb->b).can_send = xmplthc_multihop_can_send;
      (mb->b).register_send = xmplthc_multihop_register_send;
      (mb->b).error_handler = xmplthc_multihop_default_error_handler;
      (mb->b).tx_vtbl = xmplthc_multihop_tx_vtbl;
      memset(&((mb->b).rx_vtbl), 0, sizeof((mb->b).rx_vtbl));
      flounder_support_waitset_chanstate_init(&((mb->b).register_chanstate));
      flounder_support_waitset_chanstate_init(&((mb->b).tx_cont_chanstate));
      (mb->b).tx_msgnum = 0;
      (mb->b).rx_msgnum = 0;
      (mb->b).tx_msg_fragment = 0;
      (mb->b).rx_msg_fragment = 0;
      (mb->b).tx_str_pos = 0;
      (mb->b).rx_str_pos = 0;
      (mb->b).tx_str_len = 0;
      (mb->b).rx_str_len = 0;
      (mb->b).bind_cont = NULL;
      (mb->b).change_waitset = xmplthc_multihop_change_waitset;
      (mb->b).control = xmplthc_multihop_control;
      mb->trigger_chan = false;
  }
  
   void xmplthc_multihop_destroy(struct xmplthc_multihop_binding *mb)
  {
      flounder_support_waitset_chanstate_destroy(&((mb->b).register_chanstate));
      flounder_support_waitset_chanstate_destroy(&((mb->b).tx_cont_chanstate));
      assert(! "NYI!");
  }
  
  
  /*
   * Bind function
   */
  static  void xmplthc_multihop_bind_continuation(void *st, errval_t err, struct multihop_chan *chan)
  {
      struct xmplthc_multihop_binding *mb = st;
      
      if (err_is_ok(err)) {
          // set receive handlers
          multihop_chan_set_receive_handler(&(mb->chan), (struct multihop_receive_handler){  .handler = xmplthc_multihop_rx_handler,  .arg = st });
          multihop_chan_set_caps_receive_handlers(&(mb->chan), (struct monitor_cap_handlers){  .st = st,  .cap_receive_handler = xmplthc_multihop_caps_rx_handler });
      } else {
          xmplthc_multihop_destroy(mb);
      }
      
      ((mb->b).bind_cont)((mb->b).st, err, &(mb->b));
  }
  
   errval_t xmplthc_multihop_bind(struct xmplthc_multihop_binding *mb, iref_t iref, xmplthc_bind_continuation_fn *_continuation, void *st, struct waitset *waitset, idc_bind_flags_t flags)
  {
      errval_t err;
      xmplthc_multihop_init(mb, waitset);
      (mb->b).st = st;
      (mb->b).bind_cont = _continuation;
      err = multihop_chan_bind(&(mb->chan), (struct multihop_bind_continuation){  .handler = xmplthc_multihop_bind_continuation,  .st = mb }, iref, waitset);
      if (err_is_fail(err)) {
          xmplthc_multihop_destroy(mb);
      }
      return(err);
  }
  
  
  /*
   * Connect callback for export
   */
   errval_t xmplthc_multihop_connect_handler(void *st, multihop_vci_t vci)
  {
      struct xmplthc_export *e = st;
      errval_t err;
      
      // allocate storage for binding
      struct xmplthc_multihop_binding *mb = malloc(sizeof(struct xmplthc_multihop_binding ));
      if (mb == NULL) {
          return(LIB_ERR_MALLOC_FAIL);
      }
      
      // initialize binding
      struct xmplthc_binding *_binding = &(mb->b);
      xmplthc_multihop_init(mb, e->waitset);
      (mb->chan).vci = vci;
      
      // run user's connect handler
      err = ((e->connect_cb)(e->st, _binding));
      if (err_is_fail(err)) {
          return(err);
      }
      
      // set receive handlers
      multihop_chan_set_receive_handler(&(mb->chan), (struct multihop_receive_handler){  .handler = xmplthc_multihop_rx_handler,  .arg = mb });
      multihop_chan_set_caps_receive_handlers(&(mb->chan), (struct monitor_cap_handlers){  .st = mb,  .cap_receive_handler = xmplthc_multihop_caps_rx_handler });
      
      // send back bind reply
      multihop_chan_send_bind_reply(&(mb->chan), SYS_ERR_OK, (mb->chan).vci, (mb->b).waitset);
      
      return(err);
  }
  
  #endif // CONFIG_FLOUNDER_BACKEND_MULTIHOP
  