1/**
2 * \file
3 * \brief Handler function for asynchronous triggers sent by server.
4 */
5
6/*
7 * Copyright (c) 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, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
13 */
14
15#include <stdio.h>
16
17#include <barrelfish/barrelfish.h>
18#include <barrelfish/threads.h>
19
20#include <if/octopus_defs.h>
21#include <if/octopus_thc.h>
22
23#include <octopus/init.h>
24#include <octopus/getset.h>
25#include <octopus/trigger.h>
26
27#include "handler.h"
28#include "common.h"
29
30void trigger_handler(struct octopus_binding* b, octopus_trigger_id_t id,
31        uint64_t t, octopus_mode_t mode, const char* record, uint64_t st)
32{
33    assert(t != 0);
34
35    // XXX: The casting to uintptr_t is for 32-bit archs
36    trigger_handler_fn trigger_fn = (trigger_handler_fn) (uintptr_t)t;
37    void* state = (void*) (uintptr_t)st;
38
39    if (trigger_fn != NULL) {
40        trigger_fn(mode, record, state);
41    }
42    else {
43        fprintf(stderr, "Incoming trigger(%"PRIu64") for %s with unset handler function.",
44                id, record);
45    }
46}
47
48octopus_trigger_t oct_mktrigger(errval_t in_case, octopus_binding_type_t send_to,
49        octopus_mode_t mode, trigger_handler_fn fn, void* state)
50{
51    return (octopus_trigger_t) {
52                .in_case = in_case,
53                .m = mode,
54                .send_to = send_to,
55                // TODO: bad uint64_t here!
56                .trigger = (uint64_t)(uintptr_t) fn,
57                .st = (uint64_t)(uintptr_t) state
58            };
59}
60
61/**
62 * \brief Removes a trigger in the octopus server.
63 *
64 * In any case a valid watch id is specified this
65 * causes a trigger event to be sent with the
66 * OCT_REMOVED flag set. After this event it's safe
67 * to clean up any memory associated with the event handler.
68 *
69 * \param trigger_id ID of trigger we want to remove
70 *
71 * \retval SYS_ERR_OK
72 * \retval OCT_INVALID_ID
73 */
74errval_t oct_remove_trigger(octopus_trigger_id_t trigger_id)
75{
76    errval_t err = SYS_ERR_OK;
77    struct octopus_thc_client_binding_t* cl = oct_get_thc_client();
78    assert(cl != NULL);
79
80    errval_t error_code;
81    err = cl->call_seq.remove_trigger(cl, trigger_id, &error_code);
82    if (err_is_ok(err)) {
83        err = error_code;
84    }
85
86    return err;
87}
88
89/**
90 * Watches for a query of records and calls the trigger function for
91 * all records found and subsequent records registered.
92 *
93 * \param[in]  query         Records to watch for.
94 * \param[in]  event_handler Handler function to call.
95 * \param[in]  state         Additional state for handler function
96 * \param[out] tid           Trigger id.
97 * \retval SYS_ERR_OK        Trigger registered, handler fn called for all
98 *                           current records.
99 */
100errval_t oct_trigger_existing_and_watch(const char* query,
101        trigger_handler_fn event_handler, void* state,
102        octopus_trigger_id_t* tid)
103{
104    char** names = NULL;
105    char* record = NULL; // freed by cpu_change_event
106    size_t len = 0;
107    octopus_trigger_t t = oct_mktrigger(0, octopus_BINDING_EVENT,
108            TRIGGER_ALWAYS, event_handler, state);
109
110    // Get current cores registered in system
111    struct octopus_thc_client_binding_t* rpc = oct_get_thc_client();
112
113    struct octopus_get_names_response__rx_args reply;
114    errval_t err = rpc->call_seq.get_names(rpc, query,
115            t, reply.output, &reply.tid, &reply.error_code);
116    if (err_is_fail(err)) {
117        goto out;
118    }
119    err = reply.error_code;
120
121    switch(err_no(err)) {
122    case SYS_ERR_OK:
123        err = oct_parse_names(reply.output, &names, &len);
124        if (err_is_fail(err)) {
125            goto out;
126        }
127
128        for (size_t i=0; i < len; i++) {
129            err = oct_get(&record, names[i]);
130
131            switch (err_no(err)) {
132            case SYS_ERR_OK:
133                event_handler(OCT_ON_SET, record, state);
134                break;
135
136            case OCT_ERR_NO_RECORD:
137                break;
138
139            default:
140                DEBUG_ERR(err, "Unable to retrieve core record for %s", names[i]);
141                break;
142            }
143        }
144        break;
145    case OCT_ERR_NO_RECORD:
146        err = SYS_ERR_OK; // Overwrite (trigger is set)
147        break;
148
149    default:
150        // Do nothing (wait for trigger)
151        break;
152    }
153
154    // Return trigger id to caller, if requested
155    if (tid) {
156        *tid = reply.tid;
157    }
158
159out:
160    oct_free_names(names, len);
161
162    return err;
163}
164