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