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