1/** 2 * \file 3 * \brief Bidirectional LMP channel 4 */ 5 6/* 7 * Copyright (c) 2009, 2010, 2011, ETH Zurich. 8 * All rights reserved. 9 * 10 * This file is distributed under the terms in the attached LICENSE file. 11 * If you do not find this file, copies can be found by writing to: 12 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 13 */ 14 15#ifndef BARRELFISH_LMP_CHAN_H 16#define BARRELFISH_LMP_CHAN_H 17 18#include <sys/cdefs.h> 19 20#include <barrelfish/waitset.h> 21#include <barrelfish/lmp_endpoints.h> 22#include <barrelfish/idc.h> 23#include <assert.h> 24 25__BEGIN_DECLS 26 27struct lmp_chan; 28struct event_queue_node; 29 30struct lmp_bind_continuation { 31 /** 32 * \brief Handler which runs when a binding succeeds or fails 33 * \param st State pointer set in closure 34 * \param err Success/failure of binding 35 * \param lc On success, contains pointer to channel 36 */ 37 void (*handler)(void *st, errval_t err, struct lmp_chan *lc); 38 void *st; 39}; 40 41/// A bidirectional LMP channel 42struct lmp_chan { 43 struct waitset_chanstate send_waitset; ///< State belonging to waitset (for send) 44 struct lmp_chan *next, *prev; ///< Next/prev in list of channels with send events 45 struct capref local_cap, remote_cap; ///< Capabilities to local/remote endpoints 46 struct lmp_endpoint *endpoint; ///< Incoming LMP endpoint (in dispatcher) 47 48 /// connection state 49 enum {LMP_DISCONNECTED, ///< Disconnected 50 LMP_BIND_WAIT, ///< Waiting for bind reply 51 LMP_MONITOR_ACCEPT, ///< Special case for monitor binding: waiting for cap 52 LMP_CONNECTED, ///< Connection established 53 } connstate; 54 55 /* Arguments for an ongoing bind attempt */ 56 struct monitor_binding *monitor_binding; 57 struct lmp_bind_continuation bind_continuation; ///< Continuation for bind 58 iref_t iref; ///< IREF 59 size_t buflen_words; ///< requested LMP buffer length, in words 60}; 61 62void lmp_chan_init(struct lmp_chan *lc); 63void lmp_chan_destroy(struct lmp_chan *lc); 64errval_t lmp_chan_bind(struct lmp_chan *lc, struct lmp_bind_continuation cont, 65 struct event_queue_node *qnode, iref_t iref, 66 size_t buflen_words); 67errval_t lmp_chan_accept(struct lmp_chan *lc, size_t buflen_words, 68 struct capref endpoint); 69errval_t lmp_chan_register_send(struct lmp_chan *lc, struct waitset *ws, 70 struct event_closure closure); 71errval_t lmp_chan_deregister_send(struct lmp_chan *lc); 72void lmp_chan_migrate_send(struct lmp_chan *lc, struct waitset *ws); 73errval_t lmp_chan_alloc_recv_slot(struct lmp_chan *lc); 74void lmp_channels_retry_send_disabled(dispatcher_handle_t handle); 75void lmp_init(void); 76 77/** 78 * \brief Register an event handler to be notified when messages can be received 79 * 80 * In the future, call the closure on the given waitset when it is likely that 81 * a message can be received on the channel. A channel may only be registered 82 * with a single receive event handler on a single waitset at any one time. 83 * 84 * \param lc LMP channel 85 * \param ws Waitset 86 * \param closure Event handler 87 */ 88static inline errval_t lmp_chan_register_recv(struct lmp_chan *lc, 89 struct waitset *ws, 90 struct event_closure closure) 91{ 92 return lmp_endpoint_register(lc->endpoint, ws, closure); 93} 94 95/** 96 * \brief Cancel an event registration made with lmp_chan_register_recv() 97 * 98 * \param lc LMP channel 99 */ 100static inline errval_t lmp_chan_deregister_recv(struct lmp_chan *lc) 101{ 102 return lmp_endpoint_deregister(lc->endpoint); 103} 104 105/** 106 * \brief Migrate an event registration made with 107 * lmp_chan_register_recv() to a new waitset 108 * 109 * \param lc LMP channel 110 * \param ws New waitset 111 */ 112static inline void lmp_chan_migrate_recv(struct lmp_chan *lc, 113 struct waitset *ws) 114{ 115 lmp_endpoint_migrate(lc->endpoint, ws); 116} 117 118/** 119 * \brief Receive a message from an LMP channel, if possible 120 * 121 * Non-blocking. May fail if no message is available. 122 * 123 * \param lc LMP channel 124 * \param msg LMP message buffer, to be filled-in 125 * \param cap If non-NULL, filled-in with location of received capability, if any 126 */ 127static inline errval_t lmp_chan_recv(struct lmp_chan *lc, 128 struct lmp_recv_msg *msg, 129 struct capref *cap) 130{ 131 assert(msg != NULL); 132 assert(msg->buf.buflen == LMP_MSG_LENGTH); 133 return lmp_endpoint_recv(lc->endpoint, &msg->buf, cap); 134} 135 136/** 137 * \brief Check if a channel has data to receive 138 */ 139 140static inline bool lmp_chan_can_recv(struct lmp_chan *lc) 141{ 142 assert(lc); 143 assert(lc->endpoint); 144 return lmp_endpoint_can_recv(lc->endpoint); 145} 146 147/** 148 * \brief Set the receive capability slot for an LMP channel 149 * 150 * \param lc LMP channel 151 * \param slot Receive slot 152 */ 153static inline void lmp_chan_set_recv_slot(struct lmp_chan *lc, 154 struct capref slot) 155{ 156 lmp_endpoint_set_recv_slot(lc->endpoint, slot); 157} 158 159/** 160 * \brief Is the given error value a transient LMP error 161 * 162 * Returns true iff the given error code indicates a transient 163 * LMP send error condition that may succeed on a subsequent retry. 164 */ 165static inline bool lmp_err_is_transient(errval_t err) 166{ 167 enum err_code ec = err_no(err); 168 return ec == SYS_ERR_LMP_BUF_OVERFLOW 169 || ec == SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_LOOKUP 170 || ec == SYS_ERR_LMP_CAPTRANSFER_DST_CNODE_INVALID 171 || ec == SYS_ERR_LMP_CAPTRANSFER_DST_SLOT_OCCUPIED 172 || ec == SYS_ERR_LMP_TARGET_DISABLED; 173} 174 175/** 176 * \brief Apply generic IDC control operation to LMP send flags 177 */ 178static inline lmp_send_flags_t idc_control_to_lmp_flags(idc_control_t control, 179 lmp_send_flags_t flags) 180{ 181 switch (control) { 182 case IDC_CONTROL_SET_SYNC: 183 return (lmp_send_flags_t) ((unsigned)flags | (unsigned)LMP_FLAG_SYNC); 184 185 case IDC_CONTROL_CLEAR_SYNC: 186 return (lmp_send_flags_t) ((unsigned)flags & ~(unsigned)LMP_FLAG_SYNC); 187 188 default: // no-op for other control ops 189 return flags; 190 } 191} 192 193/** 194 * \brief Get a receiving chanstate of LMP channel 195 */ 196static inline struct waitset_chanstate * lmp_chan_get_receiving_channel(struct lmp_chan *chan) 197{ 198 assert(chan->endpoint); 199 return &chan->endpoint->waitset_state; 200} 201 202#include <barrelfish/lmp_chan_arch.h> 203 204__END_DECLS 205 206#endif // BARRELFISH_LMP_CHAN_H 207