1/*
2 * Copyright (c) 2011, ETH Zurich.
3 * All rights reserved.
4 *
5 * This file is distributed under the terms in the attached LICENSE file.
6 * If you do not find this file, copies can be found by writing to:
7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group.
8 */
9
10#ifndef _THC_STUBS_H_
11#define _THC_STUBS_H_
12
13#ifdef BARRELFISH
14#include <flounder/flounder.h>
15#include <barrelfish/idc_export.h>
16#include <barrelfish/static_assert.h>
17#include <thc/thc.h>
18#endif // BARRELFISH
19
20#ifdef _MSC_VER
21
22typedef int32_t idc_control_t;
23
24struct event_mutex
25{
26    int dummy;
27};
28
29#define STATIC_ASSERT(x, msg) C_ASSERT(x)
30
31#endif
32
33//......................................................................
34//
35// This must match the layout of the binding structures generated by
36// Flounder.  The flounder-generated code asserts that the offsets
37// and sizes of the common fields match those in a specific binding
38// structure.
39
40struct common_binding;
41
42typedef  void common_continuation_fn(struct common_binding *_binding);
43typedef  bool common_can_send_fn(struct common_binding *_binding);
44typedef  errval_t common_register_send_fn(struct common_binding *_binding, struct waitset *ws, struct event_closure _continuation);
45typedef  errval_t common_change_waitset_fn(struct common_binding *_binding, struct waitset *ws);
46typedef  errval_t common_control_fn(struct common_binding *_binding, idc_control_t control);
47typedef  void common_error_handler_fn(struct common_binding *_binding, errval_t err);
48
49struct common_binding {
50  void *st;
51  struct waitset *waitset;
52  struct event_mutex mutex;
53  common_can_send_fn *can_send;
54  common_register_send_fn *register_send;
55  common_change_waitset_fn *change_waitset;
56  common_control_fn *control;
57  common_error_handler_fn *error_handler;
58};
59
60// The THC stubs use the following function-like macro to check that they
61// layout of a concrete binding structure matches the common_binding
62// structure.
63
64#define CHECK_FIELD(_t,_f)						\
65  STATIC_ASSERT(offsetof(struct common_binding, _f)==offsetof(_t,_f) &&	\
66		sizeof(((struct common_binding*)NULL)->_f)==sizeof(((_t*)NULL)->_f), "OFFSET mismatch"); \
67
68//......................................................................
69//
70// Common functions and data types used in the THC stubs.
71
72#define NO_DEMUX (uint64_t)-1
73
74// Each running receive operation maintains a thc_receier_info struct
75// for synchronization with bottom-half functions invoked via the
76// underlying binding's rx_vtbl
77
78struct thc_receiver_info {
79  // AWE for the bottom-half to resume.  NULL implies that the
80  // top-half has already been resumed (and so future
81  // bottom-half invocations should not attempt to supply a
82  // second message to it)
83  awe_t *waiter;
84
85  // Pointer to union-of-pointers-to-args to show where to
86  // put the incoming data.
87  void *args;
88
89  // Pointer to where to place incoming message type
90  volatile int *msg;
91
92  // Demux information (for out-of-order RPC receivers).
93  volatile uint64_t demux;
94
95  struct thc_receiver_info *next;
96};
97
98
99// Common fields for each THC binding
100
101struct thc_per_binding_state_t {
102  // Concurrency control over the fields in the THC binding structure
103  thc_lock_t thc_binding_lock;
104
105  // Saved state of the thread waiting for an upcall on being able
106  // to send
107  awe_t *waiting_sender;
108
109  // Saved state of the thread waiting for an upcall on a send being complete
110  // (in thc_complete_send).  NB: at most one of waiting_sender and
111  // waiting_complete_sender should be used at a time, since both are
112  // protected by the thc_next_sender semaphore.  The fields are kept
113  // separate for clarity.
114  awe_t *waiting_complete_sender;
115  int thc_send_complete;
116
117  // Semaphore use to choose which sender calls register_send
118  thc_sem_t thc_next_sender;
119
120  // Flag set when a register_send call has been made, but the critical
121  // section in the subsequent event handler has not yet run (a thread
122  // can enter thc_await_send and find this flag set because an
123  // earlier thc_await_send_x was canceled)
124  int send_possible_event_requested;
125};
126
127// Common fields for each message on each THC binding; a head of a
128// linked list of thc_receiver_info structures for the running
129// receive operations, and a pointer to a condition variable (indicating
130// whether a bottom-half function is waiting).
131//
132// num_discard counts the number of messages to discard in the bottom-half
133// before delivering any.  This is used when sequential RPC responses
134// arrive for receivers that have been canceled.
135
136struct thc_per_recv_t {
137  struct thc_receiver_info * volatile r;
138  thc_condvar_t cv_bh;
139  volatile int num_bh;
140  int num_discard;
141  thc_lock_t fifo_rpc_lock;
142  thc_queue_t fifo_rpc_q;
143  uint64_t fifo_rpc_next_recv;
144};
145
146// Initialization functions
147
148extern void thc_init_per_binding_state(struct thc_per_binding_state_t *thc);
149extern void thc_init_per_recv_state(struct thc_per_recv_t *recv);
150
151// Bottom-half receive operations
152
153static inline struct thc_receiver_info *thc_start_bh(struct thc_per_binding_state_t *thc,
154                                       void *f,
155                                       struct thc_per_recv_t *recv) {
156  thc_lock_acquire(&thc->thc_binding_lock);
157
158  // Wait for a receiver
159  while (recv->num_discard == 0 &&
160         (recv->r == NULL || recv->r->waiter == NULL)) {
161    recv->num_bh++;
162    thc_condvar_wait(&recv->cv_bh, &thc->thc_binding_lock);
163    recv->num_bh--;
164  }
165
166  if (recv->num_discard > 0) {
167    // Message is a response to an RPC that has been canceled
168    recv->num_discard--;
169    thc_lock_release(&thc->thc_binding_lock);
170    return NULL;
171  } else {
172    assert(recv->r->next == NULL && recv->r->demux == NO_DEMUX &&
173           "Expected single non-demux receiver");
174    return recv->r;
175  }
176}
177
178extern struct thc_receiver_info *thc_start_demuxable_bh(struct thc_per_binding_state_t *thc,
179                                                        void *common_binding,
180                                                        struct thc_per_recv_t *recv,
181                                                        uint64_t demux);
182
183static inline void thc_end_bh(struct thc_per_binding_state_t *thc,
184                void *f,
185                struct thc_per_recv_t *recv,
186                struct thc_receiver_info *rxi) {
187  assert(recv->r != NULL && "thc_start_bh: no-one waiting");
188  assert(rxi->waiter != NULL);
189  awe_t *awe = rxi->waiter;
190  rxi->waiter = NULL;
191  THCYieldTo(awe);
192  // thc->thc_binding_lock passed to the receiver
193}
194
195// Top-half single-message receive
196extern errval_t thc_receive(struct thc_per_binding_state_t *thc,
197                            struct thc_per_recv_t *recv,
198                            struct thc_receiver_info *rxi);
199extern errval_t thc_receive_x(struct thc_per_binding_state_t *thc,
200                              struct thc_per_recv_t *recv,
201                              struct thc_receiver_info *rxi);
202// Cause the next "n" messages to be discarded on receipt
203extern void thc_discard(struct thc_per_binding_state_t *thc,
204                        struct thc_per_recv_t *recv,
205                        uint64_t n);
206
207// Top-half demux-message receive.
208//
209// Valid call sequences are start->receive
210//                          start->receive_x
211//                      and start->cancel
212extern void thc_start_receive_demux(struct thc_per_binding_state_t *thc,
213                                    struct thc_per_recv_t *recv,
214                                    struct thc_receiver_info *rxi);
215extern errval_t thc_receive_demux(struct thc_per_binding_state_t *thc,
216                                  struct thc_per_recv_t *recv,
217                                  struct thc_receiver_info *rxi);
218extern errval_t thc_receive_demux_x(struct thc_per_binding_state_t *thc,
219                                    struct thc_per_recv_t *recv,
220                                    struct thc_receiver_info *rxi);
221extern errval_t thc_cancel_receive_demux(struct thc_per_binding_state_t *thc,
222                                         struct thc_per_recv_t *recv,
223                                         struct thc_receiver_info *rxi);
224
225// Top-half receive-any
226extern void thc_start_receive_any(struct thc_per_binding_state_t *thc);
227extern void thc_start_receiving(struct thc_per_binding_state_t *thc,
228                                struct thc_per_recv_t *recv,
229                                struct thc_receiver_info *rxi);
230extern void thc_wait_receive_any(struct thc_per_binding_state_t *thc,
231                                 struct thc_receiver_info *rxi);
232extern errval_t thc_wait_receive_any_x(struct thc_per_binding_state_t *thc,
233                                       struct thc_receiver_info *rxi);
234extern void thc_stop_receiving(struct thc_per_binding_state_t *thc,
235                               struct thc_per_recv_t *recv,
236                               struct thc_receiver_info *rxi);
237extern void thc_end_receive_any(struct thc_per_binding_state_t *thc);
238
239// Top-half send
240extern void thc_await_send(struct thc_per_binding_state_t *thc,
241                           void *common_binding);
242extern errval_t thc_await_send_x(struct thc_per_binding_state_t *thc,
243                                 void *common_binding);
244extern void thc_complete_send(struct thc_per_binding_state_t *thc,
245                              void *common_binding);
246
247// Callback to execute when a send is complete (to synchronoize with
248// thc_complete_send)
249extern void thc_complete_send_cb(void *f);
250
251
252#endif
253