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