1/** 2 * \file 3 * \brief Initialization functions for the octopus client library. 4 * 5 * We use two bindings: One for communication with the server using RPC calls, 6 * and one for asynchronous events coming from the server. 7 */ 8 9/* 10 * Copyright (c) 2011, ETH Zurich. 11 * All rights reserved. 12 * 13 * This file is distributed under the terms in the attached LICENSE file. 14 * If you do not find this file, copies can be found by writing to: 15 * ETH Zurich D-INFK, Universitaetstr. 6, CH-8092 Zurich. Attn: Systems Group. 16 */ 17 18#include <stdlib.h> 19 20#include <barrelfish/barrelfish.h> 21#include <barrelfish/threads.h> 22#include <barrelfish/nameservice_client.h> 23 24#include <if/monitor_defs.h> 25#include <octopus/init.h> 26#include <thc/thc.h> 27#include <if/octopus_defs.h> 28#include <if/octopus_thc.h> 29 30#include "handler.h" 31#include "common.h" 32 33static struct oct_state { 34 struct octopus_binding* binding; 35 struct octopus_thc_client_binding_t thc_client; 36 struct waitset ws; 37 errval_t err; 38 bool is_done; 39} rpc, event; 40 41static iref_t service_iref = 0; 42static uint64_t client_identifier = 0; 43static bool initialized = false; 44 45struct octopus_binding* oct_get_event_binding(void) 46{ 47 assert(event.binding != NULL); 48 return event.binding; 49} 50 51struct octopus_thc_client_binding_t* oct_get_thc_client(void) 52{ 53 //assert(rpc.rpc_client != NULL); 54 return &rpc.thc_client; 55} 56 57static void identify_response_handler(struct octopus_binding* b) 58{ 59 event.is_done = true; 60} 61 62static struct octopus_rx_vtbl rx_vtbl = { 63 .identify_response = identify_response_handler, 64 .subscription = subscription_handler, 65 .trigger = trigger_handler 66}; 67 68/* 69static int event_handler_thread(void* st) 70{ 71 errval_t err = SYS_ERR_OK; 72 struct octopus_binding* b = oct_get_event_binding(); 73 74 b->change_waitset(b, &event.ws); 75 76 uint64_t id = (uint64_t) st; 77 err = b->tx_vtbl.identify_call(b, NOP_CONT, id, octopus_BINDING_EVENT); 78 assert(err_is_ok(err)); 79 80 // TODO abort condition 81 while (1) { 82 err = event_dispatch(&event.ws); 83 if (err_is_fail(err)) { 84 USER_PANIC_ERR(err, 85 "error in event_dispatch for octopus event binding"); 86 } 87 } 88 89 return SYS_ERR_OK; 90}*/ 91 92static void event_bind_cb(void *st, errval_t err, struct octopus_binding *b) 93{ 94 if (err_is_fail(err)) { 95 DEBUG_ERR(err, "oct_event bind failed"); 96 goto out; 97 } 98 99 event.binding = b; 100 event.binding->rx_vtbl = rx_vtbl; 101 102out: 103 assert(!event.is_done); 104 event.is_done = true; 105 event.err = err; 106} 107 108static void get_name_iref_reply(struct monitor_binding *mb, iref_t iref, 109 uintptr_t state) 110{ 111 struct oct_state* ds = (struct oct_state*)state; 112 service_iref = iref; 113 ds->err = (iref != 0) ? SYS_ERR_OK : LIB_ERR_GET_NAME_IREF; 114 ds->is_done = true; 115} 116 117static errval_t init_binding(struct oct_state* state, 118 octopus_bind_continuation_fn bind_fn) 119{ 120 errval_t err = SYS_ERR_OK; 121 assert(service_iref != 0); 122 123 state->is_done = false; 124 err = octopus_bind(service_iref, bind_fn, NULL, get_default_waitset(), 125 IDC_BIND_FLAGS_DEFAULT); 126 if (err_is_fail(err)) { 127 return err_push(err, FLOUNDER_ERR_BIND); 128 } 129 130 // Wait for callback to complete 131 while (!state->is_done) { 132 messages_wait_and_handle_next(); 133 } 134 135 return state->err; 136} 137 138static errval_t get_service_iref(void) 139{ 140 errval_t err = SYS_ERR_OK; 141 if (service_iref > 0) { 142 // we already have the iref 143 return err; 144 } 145 146 struct monitor_binding *mb = get_monitor_binding(); 147 148 rpc.is_done = false; 149 150 mb->rx_vtbl.get_name_iref_reply = get_name_iref_reply; 151 err = mb->tx_vtbl.get_name_iref_request(mb, NOP_CONT, (uintptr_t)&rpc); 152 if (err_is_fail(err)) { 153 return err; 154 } 155 156 while (!rpc.is_done) { 157 messages_wait_and_handle_next(); 158 } 159 160 if (err_is_fail(rpc.err)) { 161 return rpc.err; 162 } 163 164 return err; 165 166} 167 168errval_t oct_thc_init(void) 169{ 170 errval_t err = SYS_ERR_OK; 171 172 err = get_service_iref(); 173 if (err_is_fail(err)) { 174 return err; 175 } 176 assert(service_iref != 0); 177 178 // XXX: Can't use different waitset here? 179 err = octopus_thc_connect(service_iref, 180 get_default_waitset(), IDC_BIND_FLAGS_DEFAULT, &(rpc.binding)); 181 if (err_is_fail(err)) { 182 return err; 183 } 184 185 assert(rpc.binding != NULL); 186 err = octopus_thc_init_client(&rpc.thc_client, rpc.binding, rpc.binding); 187 if (err_is_fail(err)) { 188 return err; 189 } 190 191 // TODO: Hack. Tell the server that these bindings belong together 192 octopus_thc_client_binding_t* cl = oct_get_thc_client(); 193 err = cl->call_seq.get_identifier(cl, &client_identifier); 194 if (err_is_fail(err)) { 195 return err; 196 } 197 198 // Register rpc binding using identifier 199 err = cl->call_seq.identify(cl, client_identifier, octopus_BINDING_RPC); 200 201 return err; 202} 203 204/** 205 * \brief Initializes the octopus client library. 206 * 207 * Note the octopus rpc binding is most likely already initialized 208 * by libbarrelfish (used for nameservice). This function 209 * will set up the event thread to handle asynchronous events. 210 */ 211//__attribute__((constructor)) 212errval_t oct_init(void) 213{ 214 if (initialized) { 215 return SYS_ERR_OK; 216 } 217 initialized = true; 218 219 errval_t err = oct_thc_init(); 220 if (err_is_fail(err)) { 221 return err; 222 } 223 224 err = init_binding(&event, event_bind_cb); 225 if (err_is_fail(err)) { 226 return err; 227 } 228 229 // Register event binding 230 event.is_done = false; 231 event.binding->tx_vtbl.identify_call(event.binding, NOP_CONT, 232 client_identifier, octopus_BINDING_EVENT); 233 while (!event.is_done) { 234 messages_wait_and_handle_next(); 235 } 236 237 return err; 238} 239