/*
 * Copyright (c) 2010, ETH Zurich.
 * All rights reserved.
 * 
 * INTERFACE NAME: mem
 * INTEFACE FILE: ../if/mem.if
 * INTERFACE DESCRIPTION: Memory allocation RPC 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/mem_defs.h>

/*
 * Export function
 */
 errval_t mem_export(void *st, idc_export_callback_fn *export_cb, mem_connect_fn *connect_cb, struct waitset *ws, idc_export_flags_t flags)
{
    struct mem_export *e = malloc(sizeof(struct mem_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 = mem_lmp_connect_handler;
    #endif // CONFIG_FLOUNDER_BACKEND_LMP
    #ifdef CONFIG_FLOUNDER_BACKEND_UMP
    (e->common).ump_connect_callback = mem_ump_connect_handler;
    #endif // CONFIG_FLOUNDER_BACKEND_UMP
    #ifdef CONFIG_FLOUNDER_BACKEND_UMP_IPI
    (e->common).ump_connect_callback = mem_ump_ipi_connect_handler;
    #endif // CONFIG_FLOUNDER_BACKEND_UMP_IPI
    #ifdef CONFIG_FLOUNDER_BACKEND_MULTIHOP
    (e->common).multihop_connect_callback = mem_multihop_connect_handler;
    #endif // CONFIG_FLOUNDER_BACKEND_MULTIHOP
    
    return(idc_export_service(&(e->common)));
}


/*
 * Generic bind function
 */
static  void mem_bind_continuation_direct(void *st, errval_t err, struct mem_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 mem_lmp_binding ));
        assert((b->binding) != NULL);
        err = mem_lmp_bind(b->binding, b->iref, mem_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 mem_ump_ipi_binding ));
        assert((b->binding) != NULL);
        err = mem_ump_ipi_bind(b->binding, b->iref, mem_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 mem_ump_binding ));
        assert((b->binding) != NULL);
        err = mem_ump_bind(b->binding, b->iref, mem_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 mem_multihop_binding ));
        assert((b->binding) != NULL);
        err = mem_multihop_bind(b->binding, b->iref, mem_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:
    ((mem_bind_continuation_fn *)(b->callback))(b->st, err, _binding);
    free(b);
}

static  void mem_bind_contination_multihop(void *st, errval_t err, struct mem_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 mem_lmp_binding ));
        assert((b->binding) != NULL);
        err = mem_lmp_bind(b->binding, b->iref, mem_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 mem_multihop_binding ));
        assert((b->binding) != NULL);
        err = mem_multihop_bind(b->binding, b->iref, mem_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 mem_ump_ipi_binding ));
        assert((b->binding) != NULL);
        err = mem_ump_ipi_bind(b->binding, b->iref, mem_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 mem_ump_binding ));
        assert((b->binding) != NULL);
        err = mem_ump_bind(b->binding, b->iref, mem_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:
    ((mem_bind_continuation_fn *)(b->callback))(b->st, err, _binding);
    free(b);
}

 errval_t mem_bind(iref_t iref, mem_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) {
        mem_bind_contination_multihop(b, SYS_ERR_OK, NULL);
    } else {
        mem_bind_continuation_direct(b, SYS_ERR_OK, NULL);
    }
    
    return(SYS_ERR_OK);
}

/*
 * Copyright (c) 2010, ETH Zurich.
 * All rights reserved.
 * 
 * INTERFACE NAME: mem
 * INTEFACE FILE: ../if/mem.if
 * INTERFACE DESCRIPTION: Memory allocation RPC 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/mem_defs.h>

/*
 * Send handler functions
 */
static  void mem_allocate_call__lmp_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_lmp_binding *b = arg;
    errval_t err;
    
    // Switch on current outgoing message fragment
    switch (_binding->tx_msg_fragment) {
    case 0:
        err = lmp_chan_send3(&(b->chan), b->flags, NULL_CAP, mem_allocate_call__msgnum | (((uintptr_t )(((_binding->tx_union).allocate_call).bits)) << 16), ((_binding->tx_union).allocate_call).minbase, ((_binding->tx_union).allocate_call).maxlimit);
        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 = mem_allocate_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 mem_allocate_response__lmp_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_lmp_binding *b = arg;
    errval_t err;
    
    // Switch on current outgoing message fragment
    switch (_binding->tx_msg_fragment) {
    case 0:
        err = lmp_chan_send2(&(b->chan), b->flags, ((_binding->tx_union).allocate_response).mem_cap, mem_allocate_response__msgnum, ((_binding->tx_union).allocate_response).ret);
        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 = mem_allocate_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));
    }
}

static  void mem_steal_call__lmp_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_lmp_binding *b = arg;
    errval_t err;
    
    // Switch on current outgoing message fragment
    switch (_binding->tx_msg_fragment) {
    case 0:
        err = lmp_chan_send3(&(b->chan), b->flags, NULL_CAP, mem_steal_call__msgnum | (((uintptr_t )(((_binding->tx_union).steal_call).bits)) << 16), ((_binding->tx_union).steal_call).minbase, ((_binding->tx_union).steal_call).maxlimit);
        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 = mem_steal_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 mem_steal_response__lmp_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_lmp_binding *b = arg;
    errval_t err;
    
    // Switch on current outgoing message fragment
    switch (_binding->tx_msg_fragment) {
    case 0:
        err = lmp_chan_send2(&(b->chan), b->flags, ((_binding->tx_union).steal_response).mem_cap, mem_steal_response__msgnum, ((_binding->tx_union).steal_response).ret);
        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 = mem_steal_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));
    }
}

static  void mem_available_call__lmp_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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, mem_available_call__msgnum);
        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 = mem_available_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 mem_available_response__lmp_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_lmp_binding *b = arg;
    errval_t err;
    
    // Switch on current outgoing message fragment
    switch (_binding->tx_msg_fragment) {
    case 0:
        err = lmp_chan_send3(&(b->chan), b->flags, NULL_CAP, mem_available_response__msgnum, ((_binding->tx_union).available_response).mem_avail, ((_binding->tx_union).available_response).mem_total);
        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 = mem_available_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));
    }
}

static  void mem_free_monitor_call__lmp_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_lmp_binding *b = arg;
    errval_t err;
    
    // Switch on current outgoing message fragment
    switch (_binding->tx_msg_fragment) {
    case 0:
        err = lmp_chan_send2(&(b->chan), b->flags, ((_binding->tx_union).free_monitor_call).mem_cap, mem_free_monitor_call__msgnum | (((uintptr_t )(((_binding->tx_union).free_monitor_call).bits)) << 16), ((_binding->tx_union).free_monitor_call).base);
        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 = mem_free_monitor_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 mem_free_monitor_response__lmp_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_lmp_binding *b = arg;
    errval_t err;
    
    // Switch on current outgoing message fragment
    switch (_binding->tx_msg_fragment) {
    case 0:
        err = lmp_chan_send2(&(b->chan), b->flags, NULL_CAP, mem_free_monitor_response__msgnum, ((_binding->tx_union).free_monitor_response).err);
        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 = mem_free_monitor_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 mem_allocate_call__lmp_send(struct mem_binding *_binding, struct event_closure _continuation, uint8_t bits, mem_genpaddr_t minbase, mem_genpaddr_t maxlimit)
{
    // 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 = mem_allocate_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).allocate_call).bits = bits;
    ((_binding->tx_union).allocate_call).minbase = minbase;
    ((_binding->tx_union).allocate_call).maxlimit = maxlimit;
    FL_DEBUG("lmp TX mem.allocate_call\n");
    
    // try to send!
    mem_allocate_call__lmp_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_allocate_response__lmp_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t ret, struct capref mem_cap)
{
    // 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 = mem_allocate_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).allocate_response).ret = ret;
    ((_binding->tx_union).allocate_response).mem_cap = mem_cap;
    FL_DEBUG("lmp TX mem.allocate_response\n");
    
    // try to send!
    mem_allocate_response__lmp_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_steal_call__lmp_send(struct mem_binding *_binding, struct event_closure _continuation, uint8_t bits, mem_genpaddr_t minbase, mem_genpaddr_t maxlimit)
{
    // 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 = mem_steal_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).steal_call).bits = bits;
    ((_binding->tx_union).steal_call).minbase = minbase;
    ((_binding->tx_union).steal_call).maxlimit = maxlimit;
    FL_DEBUG("lmp TX mem.steal_call\n");
    
    // try to send!
    mem_steal_call__lmp_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_steal_response__lmp_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t ret, struct capref mem_cap)
{
    // 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 = mem_steal_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).steal_response).ret = ret;
    ((_binding->tx_union).steal_response).mem_cap = mem_cap;
    FL_DEBUG("lmp TX mem.steal_response\n");
    
    // try to send!
    mem_steal_response__lmp_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_available_call__lmp_send(struct mem_binding *_binding, struct event_closure _continuation)
{
    // 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 = mem_available_call__msgnum;
    _binding->tx_msg_fragment = 0;
    FL_DEBUG("lmp TX mem.available_call\n");
    
    // try to send!
    mem_available_call__lmp_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_available_response__lmp_send(struct mem_binding *_binding, struct event_closure _continuation, mem_genpaddr_t mem_avail, mem_genpaddr_t mem_total)
{
    // 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 = mem_available_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).available_response).mem_avail = mem_avail;
    ((_binding->tx_union).available_response).mem_total = mem_total;
    FL_DEBUG("lmp TX mem.available_response\n");
    
    // try to send!
    mem_available_response__lmp_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_free_monitor_call__lmp_send(struct mem_binding *_binding, struct event_closure _continuation, struct capref mem_cap, mem_genpaddr_t base, uint8_t bits)
{
    // 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 = mem_free_monitor_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).free_monitor_call).mem_cap = mem_cap;
    ((_binding->tx_union).free_monitor_call).base = base;
    ((_binding->tx_union).free_monitor_call).bits = bits;
    FL_DEBUG("lmp TX mem.free_monitor_call\n");
    
    // try to send!
    mem_free_monitor_call__lmp_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_free_monitor_response__lmp_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t err)
{
    // 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 = mem_free_monitor_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).free_monitor_response).err = err;
    FL_DEBUG("lmp TX mem.free_monitor_response\n");
    
    // try to send!
    mem_free_monitor_response__lmp_send_handler(_binding);
    
    return(SYS_ERR_OK);
}


/*
 * Send vtable
 */
static  struct mem_tx_vtbl mem_lmp_tx_vtbl = {
    .allocate_call = mem_allocate_call__lmp_send,
    .allocate_response = mem_allocate_response__lmp_send,
    .steal_call = mem_steal_call__lmp_send,
    .steal_response = mem_steal_response__lmp_send,
    .available_call = mem_available_call__lmp_send,
    .available_response = mem_available_response__lmp_send,
    .free_monitor_call = mem_free_monitor_call__lmp_send,
    .free_monitor_response = mem_free_monitor_response__lmp_send,
};
/*
 * Receive handler
 */
 void mem_lmp_rx_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 = mem_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 mem_allocate_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).allocate_call).bits = ((((msg.words)[0]) >> 16) & 0xff);
                ((_binding->rx_union).allocate_call).minbase = ((msg.words)[1]);
                ((_binding->rx_union).allocate_call).maxlimit = ((msg.words)[2]);
                
                FL_DEBUG("lmp RX mem.allocate_call\n");
                assert(((_binding->rx_vtbl).allocate_call) != NULL);
                ((_binding->rx_vtbl).allocate_call)(_binding, ((_binding->rx_union).allocate_call).bits, ((_binding->rx_union).allocate_call).minbase, ((_binding->rx_union).allocate_call).maxlimit);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_allocate_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_union).allocate_response).ret = ((msg.words)[1]);
                ((_binding->rx_union).allocate_response).mem_cap = cap;
                
                FL_DEBUG("lmp RX mem.allocate_response\n");
                assert(((_binding->rx_vtbl).allocate_response) != NULL);
                ((_binding->rx_vtbl).allocate_response)(_binding, ((_binding->rx_union).allocate_response).ret, ((_binding->rx_union).allocate_response).mem_cap);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_steal_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).steal_call).bits = ((((msg.words)[0]) >> 16) & 0xff);
                ((_binding->rx_union).steal_call).minbase = ((msg.words)[1]);
                ((_binding->rx_union).steal_call).maxlimit = ((msg.words)[2]);
                
                FL_DEBUG("lmp RX mem.steal_call\n");
                assert(((_binding->rx_vtbl).steal_call) != NULL);
                ((_binding->rx_vtbl).steal_call)(_binding, ((_binding->rx_union).steal_call).bits, ((_binding->rx_union).steal_call).minbase, ((_binding->rx_union).steal_call).maxlimit);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_steal_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_union).steal_response).ret = ((msg.words)[1]);
                ((_binding->rx_union).steal_response).mem_cap = cap;
                
                FL_DEBUG("lmp RX mem.steal_response\n");
                assert(((_binding->rx_vtbl).steal_response) != NULL);
                ((_binding->rx_vtbl).steal_response)(_binding, ((_binding->rx_union).steal_response).ret, ((_binding->rx_union).steal_response).mem_cap);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_available_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;
                }
                
                
                FL_DEBUG("lmp RX mem.available_call\n");
                assert(((_binding->rx_vtbl).available_call) != NULL);
                ((_binding->rx_vtbl).available_call)(_binding);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_available_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_union).available_response).mem_avail = ((msg.words)[1]);
                ((_binding->rx_union).available_response).mem_total = ((msg.words)[2]);
                
                FL_DEBUG("lmp RX mem.available_response\n");
                assert(((_binding->rx_vtbl).available_response) != NULL);
                ((_binding->rx_vtbl).available_response)(_binding, ((_binding->rx_union).available_response).mem_avail, ((_binding->rx_union).available_response).mem_total);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_free_monitor_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).free_monitor_call).bits = ((((msg.words)[0]) >> 16) & 0xff);
                ((_binding->rx_union).free_monitor_call).base = ((msg.words)[1]);
                ((_binding->rx_union).free_monitor_call).mem_cap = cap;
                
                FL_DEBUG("lmp RX mem.free_monitor_call\n");
                assert(((_binding->rx_vtbl).free_monitor_call) != NULL);
                ((_binding->rx_vtbl).free_monitor_call)(_binding, ((_binding->rx_union).free_monitor_call).mem_cap, ((_binding->rx_union).free_monitor_call).base, ((_binding->rx_union).free_monitor_call).bits);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_free_monitor_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_union).free_monitor_response).err = ((msg.words)[1]);
                
                FL_DEBUG("lmp RX mem.free_monitor_response\n");
                assert(((_binding->rx_vtbl).free_monitor_response) != NULL);
                ((_binding->rx_vtbl).free_monitor_response)(_binding, ((_binding->rx_union).free_monitor_response).err);
                _binding->rx_msgnum = 0;
                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 mem_lmp_can_send(struct mem_binding *b)
{
    return((b->tx_msgnum) == 0);
}

static  errval_t mem_lmp_register_send(struct mem_binding *b, struct waitset *ws, struct event_closure _continuation)
{
    return(flounder_support_register(ws, &(b->register_chanstate), _continuation, mem_lmp_can_send(b)));
}

static  void mem_lmp_default_error_handler(struct mem_binding *b, errval_t err)
{
    DEBUG_ERR(err, "asynchronous error in Flounder-generated mem lmp binding (default handler)");
    abort();
}

static  errval_t mem_lmp_change_waitset(struct mem_binding *_binding, struct waitset *ws)
{
    struct mem_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 mem_lmp_control(struct mem_binding *_binding, idc_control_t control)
{
    struct mem_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 mem_lmp_init(struct mem_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 = mem_lmp_can_send;
    (b->b).register_send = mem_lmp_register_send;
    (b->b).error_handler = mem_lmp_default_error_handler;
    (b->b).tx_vtbl = mem_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 = mem_lmp_change_waitset;
    (b->b).control = mem_lmp_control;
    b->flags = LMP_SEND_FLAGS_DEFAULT;
}

 void mem_lmp_destroy(struct mem_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 mem_lmp_bind_continuation(void *st, errval_t err, struct lmp_chan *chan)
{
    struct mem_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 = mem_lmp_rx_handler,  .arg = b });
        if (err_is_fail(err)) {
            err = err_push(err, LIB_ERR_CHAN_REGISTER_RECV);
            goto fail;
        }
    } else {
        fail:
        mem_lmp_destroy(b);
    }
    
    ((b->b).bind_cont)((b->b).st, err, &(b->b));
}

 errval_t mem_lmp_bind(struct mem_lmp_binding *b, iref_t iref, mem_bind_continuation_fn *_continuation, void *st, struct waitset *waitset, idc_bind_flags_t flags, size_t lmp_buflen)
{
    errval_t err;
    mem_lmp_init(b, waitset);
    (b->b).st = st;
    (b->b).bind_cont = _continuation;
    err = lmp_chan_bind(&(b->chan), (struct lmp_bind_continuation){  .handler = mem_lmp_bind_continuation,  .st = b }, &((b->b).event_qnode), iref, lmp_buflen);
    if (err_is_fail(err)) {
        mem_lmp_destroy(b);
    }
    return(err);
}


/*
 * Connect callback for export
 */
 errval_t mem_lmp_connect_handler(void *st, size_t buflen_words, struct capref endpoint, struct lmp_chan **retchan)
{
    struct mem_export *e = st;
    errval_t err;
    
    // allocate storage for binding
    struct mem_lmp_binding *b = malloc(sizeof(struct mem_lmp_binding ));
    if (b == NULL) {
        return(LIB_ERR_MALLOC_FAIL);
    }
    
    struct mem_binding *_binding = &(b->b);
    mem_lmp_init(b, e->waitset);
    
    // run user's connect handler
    err = ((e->connect_cb)(e->st, _binding));
    if (err_is_fail(err)) {
        // connection refused
        mem_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 = mem_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: mem
 * INTEFACE FILE: ../if/mem.if
 * INTERFACE DESCRIPTION: Memory allocation RPC 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/mem_defs.h>

/*
 * Send handler function
 */
static  void mem_ump_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 mem_allocate_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, mem_allocate_call__msgnum);
            (msg->data)[0] = (((_binding->tx_union).allocate_call).bits);
            (msg->data)[1] = (((_binding->tx_union).allocate_call).minbase);
            (msg->data)[2] = (((_binding->tx_union).allocate_call).maxlimit);
            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 mem_allocate_response__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, mem_allocate_response__msgnum);
            (msg->data)[0] = (((_binding->tx_union).allocate_response).ret);
            flounder_stub_ump_barrier();
            (msg->header).control = ctrl;
            (_binding->tx_msg_fragment)++;
            if ((((b->ump_state).capst).tx_capnum) == 2) {
                _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) <= 1);
            break;
        default:
            assert(!("invalid fragment"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_steal_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, mem_steal_call__msgnum);
            (msg->data)[0] = (((_binding->tx_union).steal_call).bits);
            (msg->data)[1] = (((_binding->tx_union).steal_call).minbase);
            (msg->data)[2] = (((_binding->tx_union).steal_call).maxlimit);
            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 mem_steal_response__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, mem_steal_response__msgnum);
            (msg->data)[0] = (((_binding->tx_union).steal_response).ret);
            flounder_stub_ump_barrier();
            (msg->header).control = ctrl;
            (_binding->tx_msg_fragment)++;
            if ((((b->ump_state).capst).tx_capnum) == 2) {
                _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) <= 1);
            break;
        default:
            assert(!("invalid fragment"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_available_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, mem_available_call__msgnum);
            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 mem_available_response__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, mem_available_response__msgnum);
            (msg->data)[0] = (((_binding->tx_union).available_response).mem_avail);
            (msg->data)[1] = (((_binding->tx_union).available_response).mem_total);
            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 mem_free_monitor_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, mem_free_monitor_call__msgnum);
            (msg->data)[0] = (((_binding->tx_union).free_monitor_call).bits);
            (msg->data)[1] = (((_binding->tx_union).free_monitor_call).base);
            flounder_stub_ump_barrier();
            (msg->header).control = ctrl;
            (_binding->tx_msg_fragment)++;
            if ((((b->ump_state).capst).tx_capnum) == 2) {
                _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) <= 1);
            break;
        default:
            assert(!("invalid fragment"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_free_monitor_response__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, mem_free_monitor_response__msgnum);
            (msg->data)[0] = (((_binding->tx_union).free_monitor_response).err);
            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;
    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 mem_ump_cap_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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) {
    case mem_allocate_response__msgnum:
        // Switch on current outgoing cap
        switch (((b->ump_state).capst).tx_capnum) {
        case 0:
            err = flounder_stub_send_cap(&((b->ump_state).capst), ((b->ump_state).chan).monitor_binding, ((b->ump_state).chan).monitor_id, ((_binding->tx_union).allocate_response).mem_cap, true, mem_ump_cap_send_handler);
            if (err_is_fail(err)) {
                (_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;
            }
            break;
        case 1:
            flounder_support_monitor_mutex_unlock(((b->ump_state).chan).monitor_binding);
            if ((_binding->tx_msg_fragment) == 1) {
                _binding->tx_msgnum = 0;
                flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
                flounder_support_trigger_chan(&(_binding->register_chanstate));
            }
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_steal_response__msgnum:
        // Switch on current outgoing cap
        switch (((b->ump_state).capst).tx_capnum) {
        case 0:
            err = flounder_stub_send_cap(&((b->ump_state).capst), ((b->ump_state).chan).monitor_binding, ((b->ump_state).chan).monitor_id, ((_binding->tx_union).steal_response).mem_cap, true, mem_ump_cap_send_handler);
            if (err_is_fail(err)) {
                (_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;
            }
            break;
        case 1:
            flounder_support_monitor_mutex_unlock(((b->ump_state).chan).monitor_binding);
            if ((_binding->tx_msg_fragment) == 1) {
                _binding->tx_msgnum = 0;
                flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
                flounder_support_trigger_chan(&(_binding->register_chanstate));
            }
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_free_monitor_call__msgnum:
        // Switch on current outgoing cap
        switch (((b->ump_state).capst).tx_capnum) {
        case 0:
            err = flounder_stub_send_cap(&((b->ump_state).capst), ((b->ump_state).chan).monitor_binding, ((b->ump_state).chan).monitor_id, ((_binding->tx_union).free_monitor_call).mem_cap, true, mem_ump_cap_send_handler);
            if (err_is_fail(err)) {
                (_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;
            }
            break;
        case 1:
            flounder_support_monitor_mutex_unlock(((b->ump_state).chan).monitor_binding);
            if ((_binding->tx_msg_fragment) == 1) {
                _binding->tx_msgnum = 0;
                flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
                flounder_support_trigger_chan(&(_binding->register_chanstate));
            }
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    default:
        assert(!("invalid message number"));
        (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
    }
}


/*
 * Receive handler
 */
 void mem_ump_rx_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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) {
                mem_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 mem_allocate_call__msgnum:
            switch (_binding->rx_msg_fragment) {
            case 0:
                ((_binding->rx_union).allocate_call).bits = (((msg->data)[0]) & 0xff);
                ((_binding->rx_union).allocate_call).minbase = ((msg->data)[1]);
                ((_binding->rx_union).allocate_call).maxlimit = ((msg->data)[2]);
                
                FL_DEBUG("ump RX mem.allocate_call\n");
                assert(((_binding->rx_vtbl).allocate_call) != NULL);
                ((_binding->rx_vtbl).allocate_call)(_binding, ((_binding->rx_union).allocate_call).bits, ((_binding->rx_union).allocate_call).minbase, ((_binding->rx_union).allocate_call).maxlimit);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_allocate_response__msgnum:
            switch (_binding->rx_msg_fragment) {
            case 0:
                ((b->ump_state).capst).tx_cap_ack = true;
                ((b->ump_state).capst).rx_capnum = 0;
                ((_binding->rx_union).allocate_response).ret = ((msg->data)[0]);
                
                (_binding->rx_msg_fragment)++;
                if ((((b->ump_state).capst).rx_capnum) == 1) {
                    FL_DEBUG("ump RX mem.allocate_response\n");
                    assert(((_binding->rx_vtbl).allocate_response) != NULL);
                    ((_binding->rx_vtbl).allocate_response)(_binding, ((_binding->rx_union).allocate_response).ret, ((_binding->rx_union).allocate_response).mem_cap);
                    _binding->rx_msgnum = 0;
                } else {
                    // don't process anything else until we're done
                    goto out_no_reregister;
                }
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_steal_call__msgnum:
            switch (_binding->rx_msg_fragment) {
            case 0:
                ((_binding->rx_union).steal_call).bits = (((msg->data)[0]) & 0xff);
                ((_binding->rx_union).steal_call).minbase = ((msg->data)[1]);
                ((_binding->rx_union).steal_call).maxlimit = ((msg->data)[2]);
                
                FL_DEBUG("ump RX mem.steal_call\n");
                assert(((_binding->rx_vtbl).steal_call) != NULL);
                ((_binding->rx_vtbl).steal_call)(_binding, ((_binding->rx_union).steal_call).bits, ((_binding->rx_union).steal_call).minbase, ((_binding->rx_union).steal_call).maxlimit);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_steal_response__msgnum:
            switch (_binding->rx_msg_fragment) {
            case 0:
                ((b->ump_state).capst).tx_cap_ack = true;
                ((b->ump_state).capst).rx_capnum = 0;
                ((_binding->rx_union).steal_response).ret = ((msg->data)[0]);
                
                (_binding->rx_msg_fragment)++;
                if ((((b->ump_state).capst).rx_capnum) == 1) {
                    FL_DEBUG("ump RX mem.steal_response\n");
                    assert(((_binding->rx_vtbl).steal_response) != NULL);
                    ((_binding->rx_vtbl).steal_response)(_binding, ((_binding->rx_union).steal_response).ret, ((_binding->rx_union).steal_response).mem_cap);
                    _binding->rx_msgnum = 0;
                } else {
                    // don't process anything else until we're done
                    goto out_no_reregister;
                }
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_available_call__msgnum:
            switch (_binding->rx_msg_fragment) {
            case 0:
                
                FL_DEBUG("ump RX mem.available_call\n");
                assert(((_binding->rx_vtbl).available_call) != NULL);
                ((_binding->rx_vtbl).available_call)(_binding);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_available_response__msgnum:
            switch (_binding->rx_msg_fragment) {
            case 0:
                ((_binding->rx_union).available_response).mem_avail = ((msg->data)[0]);
                ((_binding->rx_union).available_response).mem_total = ((msg->data)[1]);
                
                FL_DEBUG("ump RX mem.available_response\n");
                assert(((_binding->rx_vtbl).available_response) != NULL);
                ((_binding->rx_vtbl).available_response)(_binding, ((_binding->rx_union).available_response).mem_avail, ((_binding->rx_union).available_response).mem_total);
                _binding->rx_msgnum = 0;
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_free_monitor_call__msgnum:
            switch (_binding->rx_msg_fragment) {
            case 0:
                ((b->ump_state).capst).tx_cap_ack = true;
                ((b->ump_state).capst).rx_capnum = 0;
                ((_binding->rx_union).free_monitor_call).bits = (((msg->data)[0]) & 0xff);
                ((_binding->rx_union).free_monitor_call).base = ((msg->data)[1]);
                
                (_binding->rx_msg_fragment)++;
                if ((((b->ump_state).capst).rx_capnum) == 1) {
                    FL_DEBUG("ump RX mem.free_monitor_call\n");
                    assert(((_binding->rx_vtbl).free_monitor_call) != NULL);
                    ((_binding->rx_vtbl).free_monitor_call)(_binding, ((_binding->rx_union).free_monitor_call).mem_cap, ((_binding->rx_union).free_monitor_call).base, ((_binding->rx_union).free_monitor_call).bits);
                    _binding->rx_msgnum = 0;
                } else {
                    // don't process anything else until we're done
                    goto out_no_reregister;
                }
                break;
            default:
                (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
                goto out;
            }
            break;
        case mem_free_monitor_response__msgnum:
            switch (_binding->rx_msg_fragment) {
            case 0:
                ((_binding->rx_union).free_monitor_response).err = ((msg->data)[0]);
                
                FL_DEBUG("ump RX mem.free_monitor_response\n");
                assert(((_binding->rx_vtbl).free_monitor_response) != NULL);
                ((_binding->rx_vtbl).free_monitor_response)(_binding, ((_binding->rx_union).free_monitor_response).err);
                _binding->rx_msgnum = 0;
                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)) {
                mem_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 = mem_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)) {
        mem_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 mem_ump_cap_rx_handler(void *arg, errval_t success, struct capref cap, uint32_t capid)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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) {
    case mem_allocate_response__msgnum:
        // Switch on current incoming cap
        switch ((((b->ump_state).capst).rx_capnum)++) {
        case 0:
            ((_binding->rx_union).allocate_response).mem_cap = cap;
            if ((_binding->rx_msg_fragment) == 1) {
                FL_DEBUG("ump RX mem.allocate_response\n");
                assert(((_binding->rx_vtbl).allocate_response) != NULL);
                ((_binding->rx_vtbl).allocate_response)(_binding, ((_binding->rx_union).allocate_response).ret, ((_binding->rx_union).allocate_response).mem_cap);
                _binding->rx_msgnum = 0;
                // register for receive notification
                err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = mem_ump_rx_handler,  .arg = _binding });
                if (err_is_fail(err)) {
                    (_binding->error_handler)(_binding, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
                }
            }
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_steal_response__msgnum:
        // Switch on current incoming cap
        switch ((((b->ump_state).capst).rx_capnum)++) {
        case 0:
            ((_binding->rx_union).steal_response).mem_cap = cap;
            if ((_binding->rx_msg_fragment) == 1) {
                FL_DEBUG("ump RX mem.steal_response\n");
                assert(((_binding->rx_vtbl).steal_response) != NULL);
                ((_binding->rx_vtbl).steal_response)(_binding, ((_binding->rx_union).steal_response).ret, ((_binding->rx_union).steal_response).mem_cap);
                _binding->rx_msgnum = 0;
                // register for receive notification
                err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = mem_ump_rx_handler,  .arg = _binding });
                if (err_is_fail(err)) {
                    (_binding->error_handler)(_binding, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
                }
            }
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_free_monitor_call__msgnum:
        // Switch on current incoming cap
        switch ((((b->ump_state).capst).rx_capnum)++) {
        case 0:
            ((_binding->rx_union).free_monitor_call).mem_cap = cap;
            if ((_binding->rx_msg_fragment) == 1) {
                FL_DEBUG("ump RX mem.free_monitor_call\n");
                assert(((_binding->rx_vtbl).free_monitor_call) != NULL);
                ((_binding->rx_vtbl).free_monitor_call)(_binding, ((_binding->rx_union).free_monitor_call).mem_cap, ((_binding->rx_union).free_monitor_call).base, ((_binding->rx_union).free_monitor_call).bits);
                _binding->rx_msgnum = 0;
                // register for receive notification
                err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = mem_ump_rx_handler,  .arg = _binding });
                if (err_is_fail(err)) {
                    (_binding->error_handler)(_binding, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
                }
            }
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    default:
        assert(!("invalid message number"));
        (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
    }
}


/*
 * Monitor mutex acquire continuation
 */
static  void mem_ump_monitor_mutex_cont(void *arg)
{
    struct mem_ump_binding *b = arg;
    assert(!(((b->ump_state).capst).monitor_mutex_held));
    ((b->ump_state).capst).monitor_mutex_held = true;
    if (((b->ump_state).capst).rx_cap_ack) {
        mem_ump_cap_send_handler(b);
    }
}


/*
 * Message sender functions
 */
static  errval_t mem_allocate_call__ump_send(struct mem_binding *_binding, struct event_closure _continuation, uint8_t bits, mem_genpaddr_t minbase, mem_genpaddr_t maxlimit)
{
    // 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 = mem_allocate_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).allocate_call).bits = bits;
    ((_binding->tx_union).allocate_call).minbase = minbase;
    ((_binding->tx_union).allocate_call).maxlimit = maxlimit;
    FL_DEBUG("ump TX mem.allocate_call\n");
    
    // try to send!
    mem_ump_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_allocate_response__ump_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t ret, struct capref mem_cap)
{
    // 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 = mem_allocate_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).allocate_response).ret = ret;
    ((_binding->tx_union).allocate_response).mem_cap = mem_cap;
    FL_DEBUG("ump TX mem.allocate_response\n");
    
    // init cap send state
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).tx_capnum = 0;
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).rx_cap_ack = false;
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).monitor_mutex_held = false;
    
    // wait to acquire the monitor binding mutex
    flounder_support_monitor_mutex_enqueue(((((struct mem_ump_binding *)(_binding))->ump_state).chan).monitor_binding, &(_binding->event_qnode), (struct event_closure){  .handler = mem_ump_monitor_mutex_cont,  .arg = _binding });
    
    // try to send!
    mem_ump_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_steal_call__ump_send(struct mem_binding *_binding, struct event_closure _continuation, uint8_t bits, mem_genpaddr_t minbase, mem_genpaddr_t maxlimit)
{
    // 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 = mem_steal_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).steal_call).bits = bits;
    ((_binding->tx_union).steal_call).minbase = minbase;
    ((_binding->tx_union).steal_call).maxlimit = maxlimit;
    FL_DEBUG("ump TX mem.steal_call\n");
    
    // try to send!
    mem_ump_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_steal_response__ump_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t ret, struct capref mem_cap)
{
    // 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 = mem_steal_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).steal_response).ret = ret;
    ((_binding->tx_union).steal_response).mem_cap = mem_cap;
    FL_DEBUG("ump TX mem.steal_response\n");
    
    // init cap send state
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).tx_capnum = 0;
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).rx_cap_ack = false;
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).monitor_mutex_held = false;
    
    // wait to acquire the monitor binding mutex
    flounder_support_monitor_mutex_enqueue(((((struct mem_ump_binding *)(_binding))->ump_state).chan).monitor_binding, &(_binding->event_qnode), (struct event_closure){  .handler = mem_ump_monitor_mutex_cont,  .arg = _binding });
    
    // try to send!
    mem_ump_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_available_call__ump_send(struct mem_binding *_binding, struct event_closure _continuation)
{
    // 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 = mem_available_call__msgnum;
    _binding->tx_msg_fragment = 0;
    FL_DEBUG("ump TX mem.available_call\n");
    
    // try to send!
    mem_ump_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_available_response__ump_send(struct mem_binding *_binding, struct event_closure _continuation, mem_genpaddr_t mem_avail, mem_genpaddr_t mem_total)
{
    // 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 = mem_available_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).available_response).mem_avail = mem_avail;
    ((_binding->tx_union).available_response).mem_total = mem_total;
    FL_DEBUG("ump TX mem.available_response\n");
    
    // try to send!
    mem_ump_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_free_monitor_call__ump_send(struct mem_binding *_binding, struct event_closure _continuation, struct capref mem_cap, mem_genpaddr_t base, uint8_t bits)
{
    // 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 = mem_free_monitor_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).free_monitor_call).mem_cap = mem_cap;
    ((_binding->tx_union).free_monitor_call).base = base;
    ((_binding->tx_union).free_monitor_call).bits = bits;
    FL_DEBUG("ump TX mem.free_monitor_call\n");
    
    // init cap send state
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).tx_capnum = 0;
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).rx_cap_ack = false;
    ((((struct mem_ump_binding *)(_binding))->ump_state).capst).monitor_mutex_held = false;
    
    // wait to acquire the monitor binding mutex
    flounder_support_monitor_mutex_enqueue(((((struct mem_ump_binding *)(_binding))->ump_state).chan).monitor_binding, &(_binding->event_qnode), (struct event_closure){  .handler = mem_ump_monitor_mutex_cont,  .arg = _binding });
    
    // try to send!
    mem_ump_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_free_monitor_response__ump_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t err)
{
    // 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 = mem_free_monitor_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).free_monitor_response).err = err;
    FL_DEBUG("ump TX mem.free_monitor_response\n");
    
    // try to send!
    mem_ump_send_handler(_binding);
    
    return(SYS_ERR_OK);
}


/*
 * Send vtable
 */
static  struct mem_tx_vtbl mem_ump_tx_vtbl = {
    .allocate_call = mem_allocate_call__ump_send,
    .allocate_response = mem_allocate_response__ump_send,
    .steal_call = mem_steal_call__ump_send,
    .steal_response = mem_steal_response__ump_send,
    .available_call = mem_available_call__ump_send,
    .available_response = mem_available_response__ump_send,
    .free_monitor_call = mem_free_monitor_call__ump_send,
    .free_monitor_response = mem_free_monitor_response__ump_send,
};
/*
 * Control functions
 */
static  bool mem_ump_can_send(struct mem_binding *b)
{
    return((b->tx_msgnum) == 0);
}

static  errval_t mem_ump_register_send(struct mem_binding *b, struct waitset *ws, struct event_closure _continuation)
{
    return(flounder_support_register(ws, &(b->register_chanstate), _continuation, mem_ump_can_send(b)));
}

static  void mem_ump_default_error_handler(struct mem_binding *b, errval_t err)
{
    DEBUG_ERR(err, "asynchronous error in Flounder-generated mem ump binding (default handler)");
    abort();
}

static  errval_t mem_ump_change_waitset(struct mem_binding *_binding, struct waitset *ws)
{
    struct mem_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 = mem_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 mem_ump_control(struct mem_binding *_binding, idc_control_t control)
{
    // no control flags are supported
    return(SYS_ERR_OK);
}


/*
 * Function to destroy the binding state
 */
 void mem_ump_destroy(struct mem_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 mem_ump_bind_continuation(void *st, errval_t err, struct ump_chan *chan, struct capref notify_cap)
{
    struct mem_binding *_binding = st;
    struct mem_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 = mem_ump_cap_rx_handler;
        // register for receive notification
        err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = mem_ump_rx_handler,  .arg = _binding });
        if (err_is_fail(err)) {
            (_binding->error_handler)(_binding, err_push(err, LIB_ERR_CHAN_REGISTER_RECV));
        }
    } else {
        mem_ump_destroy(b);
    }
    
    (_binding->bind_cont)(_binding->st, err, _binding);
}

 errval_t mem_ump_init(struct mem_ump_binding *b, struct waitset *waitset, volatile void *inbuf, size_t inbufsize, volatile void *outbuf, size_t outbufsize)
{
    errval_t err;
    struct mem_binding *_binding = &(b->b);
    (b->b).st = NULL;
    (b->b).waitset = waitset;
    event_mutex_init(&((b->b).mutex), waitset);
    (b->b).can_send = mem_ump_can_send;
    (b->b).register_send = mem_ump_register_send;
    (b->b).error_handler = mem_ump_default_error_handler;
    (b->b).tx_vtbl = mem_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)) {
        mem_ump_destroy(b);
        return(err_push(err, LIB_ERR_UMP_CHAN_INIT));
    }
    
    (b->b).change_waitset = mem_ump_change_waitset;
    (b->b).control = mem_ump_control;
    // register for receive notification
    err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = mem_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 mem_ump_new_monitor_binding_continuation(void *st, errval_t err, struct monitor_binding *monitor_binding)
{
    struct mem_binding *_binding = st;
    struct mem_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 = mem_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);
        mem_ump_destroy(b);
    }
}

 errval_t mem_ump_bind(struct mem_ump_binding *b, iref_t iref, mem_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 = mem_ump_can_send;
    (b->b).register_send = mem_ump_register_send;
    (b->b).error_handler = mem_ump_default_error_handler;
    (b->b).tx_vtbl = mem_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 = mem_ump_change_waitset;
    (b->b).control = mem_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(mem_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 = mem_ump_bind_continuation,  .st = b }, &((b->b).event_qnode), iref, get_monitor_binding(), inchanlen, outchanlen, NULL_CAP);
    }
    
    if (err_is_fail(err)) {
        mem_ump_destroy(b);
    }
    return(err);
}


/*
 * Connect callback for export
 */
 errval_t mem_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 mem_export *e = st;
    errval_t err;
    
    // allocate storage for binding
    struct mem_ump_binding *b = malloc(sizeof(struct mem_ump_binding ));
    if (b == NULL) {
        return(LIB_ERR_MALLOC_FAIL);
    }
    
    struct mem_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 = mem_ump_can_send;
    (b->b).register_send = mem_ump_register_send;
    (b->b).error_handler = mem_ump_default_error_handler;
    (b->b).tx_vtbl = mem_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 = mem_ump_change_waitset;
    (b->b).control = mem_ump_control;
    
    // run user's connect handler
    err = ((e->connect_cb)(e->st, _binding));
    if (err_is_fail(err)) {
        // connection refused
        mem_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 = mem_ump_cap_rx_handler;
    
    // register for receive notification
    err = ump_chan_register_recv(&((b->ump_state).chan), _binding->waitset, (struct event_closure){  .handler = mem_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: mem
 * INTEFACE FILE: ../if/mem.if
 * INTERFACE DESCRIPTION: Memory allocation RPC 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/mem_defs.h>

/*
 * Capability sender function
 */
static  void mem_multihop_cap_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_multihop_binding *mb = arg;
    
    errval_t err = SYS_ERR_OK;
    
    // Switch on current outgoing message
    switch (_binding->tx_msgnum) {
    case mem_allocate_response__msgnum:
        // Switch on current outgoing cap
        switch ((mb->capst).tx_capnum) {
        case 0:
            err = multihop_send_capability(&(mb->chan), MKCONT(mem_multihop_cap_send_handler, _binding), &(mb->capst), ((_binding->tx_union).allocate_response).mem_cap);
            if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
                err = multihop_chan_register_send(&(mb->chan), _binding->waitset, MKCONT(mem_multihop_cap_send_handler, _binding));
                assert(err_is_ok(err));
            }
            if (err_is_fail(err)) {
                (_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;
            }
            break;
        case 1:
            if (multihop_chan_is_window_full(&(mb->chan))) {
                mb->trigger_chan = true;
                break;
            } else {
                _binding->tx_msgnum = 0;
                flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
                flounder_support_trigger_chan(&(_binding->register_chanstate));
                break;
            }
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_steal_response__msgnum:
        // Switch on current outgoing cap
        switch ((mb->capst).tx_capnum) {
        case 0:
            err = multihop_send_capability(&(mb->chan), MKCONT(mem_multihop_cap_send_handler, _binding), &(mb->capst), ((_binding->tx_union).steal_response).mem_cap);
            if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
                err = multihop_chan_register_send(&(mb->chan), _binding->waitset, MKCONT(mem_multihop_cap_send_handler, _binding));
                assert(err_is_ok(err));
            }
            if (err_is_fail(err)) {
                (_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;
            }
            break;
        case 1:
            if (multihop_chan_is_window_full(&(mb->chan))) {
                mb->trigger_chan = true;
                break;
            } else {
                _binding->tx_msgnum = 0;
                flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
                flounder_support_trigger_chan(&(_binding->register_chanstate));
                break;
            }
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_free_monitor_call__msgnum:
        // Switch on current outgoing cap
        switch ((mb->capst).tx_capnum) {
        case 0:
            err = multihop_send_capability(&(mb->chan), MKCONT(mem_multihop_cap_send_handler, _binding), &(mb->capst), ((_binding->tx_union).free_monitor_call).mem_cap);
            if (err_no(err) == FLOUNDER_ERR_TX_BUSY) {
                err = multihop_chan_register_send(&(mb->chan), _binding->waitset, MKCONT(mem_multihop_cap_send_handler, _binding));
                assert(err_is_ok(err));
            }
            if (err_is_fail(err)) {
                (_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;
            }
            break;
        case 1:
            if (multihop_chan_is_window_full(&(mb->chan))) {
                mb->trigger_chan = true;
                break;
            } else {
                _binding->tx_msgnum = 0;
                flounder_support_trigger_chan(&(_binding->tx_cont_chanstate));
                flounder_support_trigger_chan(&(_binding->register_chanstate));
                break;
            }
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    default:
        assert(!("invalid message number"));
        (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
    }
}

/*
 * Send handler functions
 */
static  void mem_allocate_call__multihop_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 = 24;
        assert(msg_size != 0);
        msg = malloc(msg_size);
        
        // copy words from fixed size fragments
        // [[MsgCode,ArgFieldFragment uint8 [NamedField "bits"] 0],[ArgFieldFragment uint64 [NamedField "minbase"] 0],[ArgFieldFragment uint64 [NamedField "maxlimit"] 0]]
        msg[0] = (mem_allocate_call__msgnum | (((uint64_t )(((_binding->tx_union).allocate_call).bits)) << 16));
        msg[1] = (((_binding->tx_union).allocate_call).minbase);
        msg[2] = (((_binding->tx_union).allocate_call).maxlimit);
        
        
        // copy strings
        
        // copy buffers
        
        // try to send!
        (_binding->tx_msg_fragment)++;
        mb->message = msg;
        err = multihop_send_message(&(mb->chan), MKCONT(mem_allocate_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(mem_allocate_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 mem_allocate_response__multihop_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 = 16;
        assert(msg_size != 0);
        msg = malloc(msg_size);
        
        // copy words from fixed size fragments
        // [[MsgCode],[ArgFieldFragment uint64 [NamedField "ret"] 0]]
        msg[0] = mem_allocate_response__msgnum;
        msg[1] = (((_binding->tx_union).allocate_response).ret);
        
        
        // copy strings
        
        // copy buffers
        
        // try to send!
        (_binding->tx_msg_fragment)++;
        mb->message = msg;
        err = multihop_send_message(&(mb->chan), MKCONT(mem_allocate_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(mem_allocate_response__multihop_send_handler, _binding));
            assert(err_is_ok(err));
        }
        if (err_is_fail(err)) {
            break;
        } else {
            return;
        }
    case 1:
        free(mb->message);
        // send caps
        mem_multihop_cap_send_handler(mb);
        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 mem_steal_call__multihop_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 = 24;
        assert(msg_size != 0);
        msg = malloc(msg_size);
        
        // copy words from fixed size fragments
        // [[MsgCode,ArgFieldFragment uint8 [NamedField "bits"] 0],[ArgFieldFragment uint64 [NamedField "minbase"] 0],[ArgFieldFragment uint64 [NamedField "maxlimit"] 0]]
        msg[0] = (mem_steal_call__msgnum | (((uint64_t )(((_binding->tx_union).steal_call).bits)) << 16));
        msg[1] = (((_binding->tx_union).steal_call).minbase);
        msg[2] = (((_binding->tx_union).steal_call).maxlimit);
        
        
        // copy strings
        
        // copy buffers
        
        // try to send!
        (_binding->tx_msg_fragment)++;
        mb->message = msg;
        err = multihop_send_message(&(mb->chan), MKCONT(mem_steal_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(mem_steal_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 mem_steal_response__multihop_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 = 16;
        assert(msg_size != 0);
        msg = malloc(msg_size);
        
        // copy words from fixed size fragments
        // [[MsgCode],[ArgFieldFragment uint64 [NamedField "ret"] 0]]
        msg[0] = mem_steal_response__msgnum;
        msg[1] = (((_binding->tx_union).steal_response).ret);
        
        
        // copy strings
        
        // copy buffers
        
        // try to send!
        (_binding->tx_msg_fragment)++;
        mb->message = msg;
        err = multihop_send_message(&(mb->chan), MKCONT(mem_steal_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(mem_steal_response__multihop_send_handler, _binding));
            assert(err_is_ok(err));
        }
        if (err_is_fail(err)) {
            break;
        } else {
            return;
        }
    case 1:
        free(mb->message);
        // send caps
        mem_multihop_cap_send_handler(mb);
        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 mem_available_call__multihop_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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]]
        msg[0] = mem_available_call__msgnum;
        
        
        // copy strings
        
        // copy buffers
        
        // try to send!
        (_binding->tx_msg_fragment)++;
        mb->message = msg;
        err = multihop_send_message(&(mb->chan), MKCONT(mem_available_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(mem_available_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 mem_available_response__multihop_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 = 24;
        assert(msg_size != 0);
        msg = malloc(msg_size);
        
        // copy words from fixed size fragments
        // [[MsgCode],[ArgFieldFragment uint64 [NamedField "mem_avail"] 0],[ArgFieldFragment uint64 [NamedField "mem_total"] 0]]
        msg[0] = mem_available_response__msgnum;
        msg[1] = (((_binding->tx_union).available_response).mem_avail);
        msg[2] = (((_binding->tx_union).available_response).mem_total);
        
        
        // copy strings
        
        // copy buffers
        
        // try to send!
        (_binding->tx_msg_fragment)++;
        mb->message = msg;
        err = multihop_send_message(&(mb->chan), MKCONT(mem_available_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(mem_available_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));
}

static  void mem_free_monitor_call__multihop_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 = 16;
        assert(msg_size != 0);
        msg = malloc(msg_size);
        
        // copy words from fixed size fragments
        // [[MsgCode,ArgFieldFragment uint8 [NamedField "bits"] 0],[ArgFieldFragment uint64 [NamedField "base"] 0]]
        msg[0] = (mem_free_monitor_call__msgnum | (((uint64_t )(((_binding->tx_union).free_monitor_call).bits)) << 16));
        msg[1] = (((_binding->tx_union).free_monitor_call).base);
        
        
        // copy strings
        
        // copy buffers
        
        // try to send!
        (_binding->tx_msg_fragment)++;
        mb->message = msg;
        err = multihop_send_message(&(mb->chan), MKCONT(mem_free_monitor_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(mem_free_monitor_call__multihop_send_handler, _binding));
            assert(err_is_ok(err));
        }
        if (err_is_fail(err)) {
            break;
        } else {
            return;
        }
    case 1:
        free(mb->message);
        // send caps
        mem_multihop_cap_send_handler(mb);
        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 mem_free_monitor_response__multihop_send_handler(void *arg)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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 = 16;
        assert(msg_size != 0);
        msg = malloc(msg_size);
        
        // copy words from fixed size fragments
        // [[MsgCode],[ArgFieldFragment uint64 [NamedField "err"] 0]]
        msg[0] = mem_free_monitor_response__msgnum;
        msg[1] = (((_binding->tx_union).free_monitor_response).err);
        
        
        // copy strings
        
        // copy buffers
        
        // try to send!
        (_binding->tx_msg_fragment)++;
        mb->message = msg;
        err = multihop_send_message(&(mb->chan), MKCONT(mem_free_monitor_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(mem_free_monitor_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 mem_multihop_caps_rx_handler(void *arg, errval_t success, struct capref cap, uint32_t capid)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_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) {
    case mem_allocate_response__msgnum:
        // Switch on current incoming cap
        switch (((mb->capst).rx_capnum)++) {
        case 0:
            ((_binding->rx_union).allocate_response).mem_cap = cap;
            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 mem.allocate_response\n");
            assert(((_binding->rx_vtbl).allocate_response) != NULL);
            ((_binding->rx_vtbl).allocate_response)(_binding, ((_binding->rx_union).allocate_response).ret, ((_binding->rx_union).allocate_response).mem_cap);
            _binding->rx_msgnum = 0;
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_steal_response__msgnum:
        // Switch on current incoming cap
        switch (((mb->capst).rx_capnum)++) {
        case 0:
            ((_binding->rx_union).steal_response).mem_cap = cap;
            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 mem.steal_response\n");
            assert(((_binding->rx_vtbl).steal_response) != NULL);
            ((_binding->rx_vtbl).steal_response)(_binding, ((_binding->rx_union).steal_response).ret, ((_binding->rx_union).steal_response).mem_cap);
            _binding->rx_msgnum = 0;
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    case mem_free_monitor_call__msgnum:
        // Switch on current incoming cap
        switch (((mb->capst).rx_capnum)++) {
        case 0:
            ((_binding->rx_union).free_monitor_call).mem_cap = cap;
            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 mem.free_monitor_call\n");
            assert(((_binding->rx_vtbl).free_monitor_call) != NULL);
            ((_binding->rx_vtbl).free_monitor_call)(_binding, ((_binding->rx_union).free_monitor_call).mem_cap, ((_binding->rx_union).free_monitor_call).base, ((_binding->rx_union).free_monitor_call).bits);
            _binding->rx_msgnum = 0;
            break;
        default:
            assert(!("invalid cap number"));
            (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
        }
        break;
    default:
        assert(!("invalid message number"));
        (_binding->error_handler)(_binding, FLOUNDER_ERR_INVALID_STATE);
    }
}


/*
 * Message sender functions
 */
static  errval_t mem_allocate_call__multihop_send(struct mem_binding *_binding, struct event_closure _continuation, uint8_t bits, mem_genpaddr_t minbase, mem_genpaddr_t maxlimit)
{
    // 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 = mem_allocate_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).allocate_call).bits = bits;
    ((_binding->tx_union).allocate_call).minbase = minbase;
    ((_binding->tx_union).allocate_call).maxlimit = maxlimit;
    FL_DEBUG("multihop TX mem.allocate_call\n");
    
    // try to send!
    mem_allocate_call__multihop_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_allocate_response__multihop_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t ret, struct capref mem_cap)
{
    // 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 = mem_allocate_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).allocate_response).ret = ret;
    ((_binding->tx_union).allocate_response).mem_cap = mem_cap;
    FL_DEBUG("multihop TX mem.allocate_response\n");
    
    // try to send!
    mem_allocate_response__multihop_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_steal_call__multihop_send(struct mem_binding *_binding, struct event_closure _continuation, uint8_t bits, mem_genpaddr_t minbase, mem_genpaddr_t maxlimit)
{
    // 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 = mem_steal_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).steal_call).bits = bits;
    ((_binding->tx_union).steal_call).minbase = minbase;
    ((_binding->tx_union).steal_call).maxlimit = maxlimit;
    FL_DEBUG("multihop TX mem.steal_call\n");
    
    // try to send!
    mem_steal_call__multihop_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_steal_response__multihop_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t ret, struct capref mem_cap)
{
    // 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 = mem_steal_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).steal_response).ret = ret;
    ((_binding->tx_union).steal_response).mem_cap = mem_cap;
    FL_DEBUG("multihop TX mem.steal_response\n");
    
    // try to send!
    mem_steal_response__multihop_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_available_call__multihop_send(struct mem_binding *_binding, struct event_closure _continuation)
{
    // 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 = mem_available_call__msgnum;
    _binding->tx_msg_fragment = 0;
    FL_DEBUG("multihop TX mem.available_call\n");
    
    // try to send!
    mem_available_call__multihop_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_available_response__multihop_send(struct mem_binding *_binding, struct event_closure _continuation, mem_genpaddr_t mem_avail, mem_genpaddr_t mem_total)
{
    // 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 = mem_available_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).available_response).mem_avail = mem_avail;
    ((_binding->tx_union).available_response).mem_total = mem_total;
    FL_DEBUG("multihop TX mem.available_response\n");
    
    // try to send!
    mem_available_response__multihop_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_free_monitor_call__multihop_send(struct mem_binding *_binding, struct event_closure _continuation, struct capref mem_cap, mem_genpaddr_t base, uint8_t bits)
{
    // 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 = mem_free_monitor_call__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).free_monitor_call).mem_cap = mem_cap;
    ((_binding->tx_union).free_monitor_call).base = base;
    ((_binding->tx_union).free_monitor_call).bits = bits;
    FL_DEBUG("multihop TX mem.free_monitor_call\n");
    
    // try to send!
    mem_free_monitor_call__multihop_send_handler(_binding);
    
    return(SYS_ERR_OK);
}

static  errval_t mem_free_monitor_response__multihop_send(struct mem_binding *_binding, struct event_closure _continuation, mem_errval_t err)
{
    // 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 = mem_free_monitor_response__msgnum;
    _binding->tx_msg_fragment = 0;
    ((_binding->tx_union).free_monitor_response).err = err;
    FL_DEBUG("multihop TX mem.free_monitor_response\n");
    
    // try to send!
    mem_free_monitor_response__multihop_send_handler(_binding);
    
    return(SYS_ERR_OK);
}


/*
 * Send vtable
 */
static  struct mem_tx_vtbl mem_multihop_tx_vtbl = {
    .allocate_call = mem_allocate_call__multihop_send,
    .allocate_response = mem_allocate_response__multihop_send,
    .steal_call = mem_steal_call__multihop_send,
    .steal_response = mem_steal_response__multihop_send,
    .available_call = mem_available_call__multihop_send,
    .available_response = mem_available_response__multihop_send,
    .free_monitor_call = mem_free_monitor_call__multihop_send,
    .free_monitor_response = mem_free_monitor_response__multihop_send,
};
/*
 * Receive handler
 */
 void mem_multihop_rx_handler(void *arg, uint8_t *message, size_t message_len)
{
    // Get the binding state from our argument pointer
    struct mem_binding *_binding = arg;
    struct mem_multihop_binding *mb = arg;
    
    
    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 mem_allocate_call__msgnum:
        // store fixed size fragments
        ((_binding->rx_union).allocate_call).bits = (((((uint64_t *)(message))[0]) >> 16) & 0xff);
        ((_binding->rx_union).allocate_call).minbase = (((uint64_t *)(message))[1]);
        ((_binding->rx_union).allocate_call).maxlimit = (((uint64_t *)(message))[2]);
        msg = (message + 24);
        
        // 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 mem.allocate_call\n");
        assert(((_binding->rx_vtbl).allocate_call) != NULL);
        ((_binding->rx_vtbl).allocate_call)(_binding, ((_binding->rx_union).allocate_call).bits, ((_binding->rx_union).allocate_call).minbase, ((_binding->rx_union).allocate_call).maxlimit);
        _binding->rx_msgnum = 0;
        break;
    case mem_allocate_response__msgnum:
        // store fixed size fragments
        ((_binding->rx_union).allocate_response).ret = (((uint64_t *)(message))[1]);
        msg = (message + 16);
        
        // 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));
        }
        (_binding->rx_msg_fragment)++;
        break;
    case mem_steal_call__msgnum:
        // store fixed size fragments
        ((_binding->rx_union).steal_call).bits = (((((uint64_t *)(message))[0]) >> 16) & 0xff);
        ((_binding->rx_union).steal_call).minbase = (((uint64_t *)(message))[1]);
        ((_binding->rx_union).steal_call).maxlimit = (((uint64_t *)(message))[2]);
        msg = (message + 24);
        
        // 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 mem.steal_call\n");
        assert(((_binding->rx_vtbl).steal_call) != NULL);
        ((_binding->rx_vtbl).steal_call)(_binding, ((_binding->rx_union).steal_call).bits, ((_binding->rx_union).steal_call).minbase, ((_binding->rx_union).steal_call).maxlimit);
        _binding->rx_msgnum = 0;
        break;
    case mem_steal_response__msgnum:
        // store fixed size fragments
        ((_binding->rx_union).steal_response).ret = (((uint64_t *)(message))[1]);
        msg = (message + 16);
        
        // 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));
        }
        (_binding->rx_msg_fragment)++;
        break;
    case mem_available_call__msgnum:
        // store fixed size fragments
        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 mem.available_call\n");
        assert(((_binding->rx_vtbl).available_call) != NULL);
        ((_binding->rx_vtbl).available_call)(_binding);
        _binding->rx_msgnum = 0;
        break;
    case mem_available_response__msgnum:
        // store fixed size fragments
        ((_binding->rx_union).available_response).mem_avail = (((uint64_t *)(message))[1]);
        ((_binding->rx_union).available_response).mem_total = (((uint64_t *)(message))[2]);
        msg = (message + 24);
        
        // 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 mem.available_response\n");
        assert(((_binding->rx_vtbl).available_response) != NULL);
        ((_binding->rx_vtbl).available_response)(_binding, ((_binding->rx_union).available_response).mem_avail, ((_binding->rx_union).available_response).mem_total);
        _binding->rx_msgnum = 0;
        break;
    case mem_free_monitor_call__msgnum:
        // store fixed size fragments
        ((_binding->rx_union).free_monitor_call).bits = (((((uint64_t *)(message))[0]) >> 16) & 0xff);
        ((_binding->rx_union).free_monitor_call).base = (((uint64_t *)(message))[1]);
        msg = (message + 16);
        
        // 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));
        }
        (_binding->rx_msg_fragment)++;
        break;
    case mem_free_monitor_response__msgnum:
        // store fixed size fragments
        ((_binding->rx_union).free_monitor_response).err = (((uint64_t *)(message))[1]);
        msg = (message + 16);
        
        // 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 mem.free_monitor_response\n");
        assert(((_binding->rx_vtbl).free_monitor_response) != NULL);
        ((_binding->rx_vtbl).free_monitor_response)(_binding, ((_binding->rx_union).free_monitor_response).err);
        _binding->rx_msgnum = 0;
        break;
    default:
        (_binding->error_handler)(_binding, FLOUNDER_ERR_RX_INVALID_MSGNUM);
        return;
    }
}


/*
 * Control functions
 */
static  bool mem_multihop_can_send(struct mem_binding *b)
{
    struct mem_multihop_binding *mb = (struct mem_multihop_binding *)(b);
    return(((b->tx_msgnum) == 0) && (!multihop_chan_is_window_full(&(mb->chan))));
}

static  errval_t mem_multihop_register_send(struct mem_binding *b, struct waitset *ws, struct event_closure _continuation)
{
    return(flounder_support_register(ws, &(b->register_chanstate), _continuation, mem_multihop_can_send(b)));
}

static  void mem_multihop_default_error_handler(struct mem_binding *b, errval_t err)
{
    DEBUG_ERR(err, "asynchronous error in Flounder-generated mem multihop binding (default handler)");
    abort();
}

static  errval_t mem_multihop_change_waitset(struct mem_binding *_binding, struct waitset *ws)
{
    struct mem_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 mem_multihop_control(struct mem_binding *_binding, idc_control_t control)
{
    // No control flags supported
    return(SYS_ERR_OK);
}

/*
 * Functions to initialise/destroy the binding state
 */
 void mem_multihop_init(struct mem_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 = mem_multihop_can_send;
    (mb->b).register_send = mem_multihop_register_send;
    (mb->b).error_handler = mem_multihop_default_error_handler;
    (mb->b).tx_vtbl = mem_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 = mem_multihop_change_waitset;
    (mb->b).control = mem_multihop_control;
    mb->trigger_chan = false;
}

 void mem_multihop_destroy(struct mem_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 mem_multihop_bind_continuation(void *st, errval_t err, struct multihop_chan *chan)
{
    struct mem_multihop_binding *mb = st;
    
    if (err_is_ok(err)) {
        // set receive handlers
        multihop_chan_set_receive_handler(&(mb->chan), (struct multihop_receive_handler){  .handler = mem_multihop_rx_handler,  .arg = st });
        multihop_chan_set_caps_receive_handlers(&(mb->chan), (struct monitor_cap_handlers){  .st = st,  .cap_receive_handler = mem_multihop_caps_rx_handler });
    } else {
        mem_multihop_destroy(mb);
    }
    
    ((mb->b).bind_cont)((mb->b).st, err, &(mb->b));
}

 errval_t mem_multihop_bind(struct mem_multihop_binding *mb, iref_t iref, mem_bind_continuation_fn *_continuation, void *st, struct waitset *waitset, idc_bind_flags_t flags)
{
    errval_t err;
    mem_multihop_init(mb, waitset);
    (mb->b).st = st;
    (mb->b).bind_cont = _continuation;
    err = multihop_chan_bind(&(mb->chan), (struct multihop_bind_continuation){  .handler = mem_multihop_bind_continuation,  .st = mb }, iref, waitset);
    if (err_is_fail(err)) {
        mem_multihop_destroy(mb);
    }
    return(err);
}


/*
 * Connect callback for export
 */
 errval_t mem_multihop_connect_handler(void *st, multihop_vci_t vci)
{
    struct mem_export *e = st;
    errval_t err;
    
    // allocate storage for binding
    struct mem_multihop_binding *mb = malloc(sizeof(struct mem_multihop_binding ));
    if (mb == NULL) {
        return(LIB_ERR_MALLOC_FAIL);
    }
    
    // initialize binding
    struct mem_binding *_binding = &(mb->b);
    mem_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 = mem_multihop_rx_handler,  .arg = mb });
    multihop_chan_set_caps_receive_handlers(&(mb->chan), (struct monitor_cap_handlers){  .st = mb,  .cap_receive_handler = mem_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
