1/**
2 * \file
3 * \brief Deferred events (ie. timers)
4 */
5
6/*
7 * Copyright (c) 2009, 2011, 2012, 2013, 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 <barrelfish/barrelfish.h>
16#include <barrelfish/deferred.h>
17#include <barrelfish/waitset_chan.h>
18#include <stdio.h>
19#include <barrelfish/systime.h>
20
21// FIXME: why do I need quite so many dispatcher headers?
22#include <barrelfish/dispatch.h>
23#include <barrelfish/dispatcher_arch.h>
24#include <barrelfish/curdispatcher_arch.h>
25#include <barrelfish_kpi/dispatcher_shared.h>
26
27#include "waitset_chan_priv.h"
28
29static void update_wakeup_disabled(dispatcher_handle_t dh)
30{
31    struct dispatcher_generic *dg = get_dispatcher_generic(dh);
32    struct dispatcher_shared_generic *ds = get_dispatcher_shared_generic(dh);
33
34    if (dg->deferred_events == NULL) {
35        ds->wakeup = 0;
36    } else {
37        ds->wakeup = dg->deferred_events->time;
38    }
39}
40
41/**
42 * \brief Returns the system time when the current dispatcher was last dispatched
43 */
44systime_t get_system_time(void)
45{
46    return systime_now();
47}
48
49void deferred_event_init(struct deferred_event *event)
50{
51    assert(event != NULL);
52    waitset_chanstate_init(&event->waitset_state, CHANTYPE_DEFERRED);
53    event->next = event->prev = NULL;
54    event->time = 0;
55}
56
57/**
58 * \brief Register a deferred event
59 *
60 * \param ws Waitset
61 * \param delay Delay in microseconds
62 * \param closure Event closure to execute
63 * \param event Storage for event metadata
64 */
65errval_t deferred_event_register(struct deferred_event *event,
66                                 struct waitset *ws, delayus_t delay,
67                                 struct event_closure closure)
68{
69    errval_t err;
70
71    dispatcher_handle_t dh = disp_disable();
72    err = waitset_chan_register_disabled(ws, &event->waitset_state, closure);
73    if (err_is_ok(err)) {
74        struct dispatcher_generic *dg = get_dispatcher_generic(dh);
75
76        // determine absolute time for event
77        event->time = systime_now() + ns_to_systime((uint64_t)delay * 1000);
78        // enqueue in sorted list of pending timers
79        for (struct deferred_event *e = dg->deferred_events, *p = NULL; ;
80             p = e, e = e->next) {
81            if (e == NULL || e->time > event->time) {
82                if (p == NULL) { // insert at head
83                    assert(e == dg->deferred_events);
84                    event->prev = NULL;
85                    event->next = e;
86                    if (e != NULL) {
87                        e->prev = event;
88                    }
89                    dg->deferred_events = event;
90                } else {
91                    event->next = e;
92                    event->prev = p;
93                    p->next = event;
94                    if (e != NULL) {
95                        e->prev = event;
96                    }
97                }
98                break;
99            }
100        }
101    }
102
103    update_wakeup_disabled(dh);
104
105    disp_enable(dh);
106
107    return err;
108}
109
110static void usleep_callback(void *val)
111{
112    bool *wakeup = val;
113    *wakeup = true;
114}
115
116errval_t barrelfish_usleep(delayus_t delay)
117{
118    struct deferred_event dev;
119    struct waitset ws;
120    errval_t err;
121    bool wakeup = false;
122
123    deferred_event_init(&dev);
124    waitset_init(&ws);
125    err = deferred_event_register(&dev, &ws, delay,
126                                  MKCLOSURE(usleep_callback, &wakeup));
127    if(err_is_fail(err)) {
128        return err;
129    }
130
131    while(!wakeup) {
132        err = event_dispatch(&ws);
133        if(err_is_fail(err)) {
134            return err;
135        }
136    }
137
138    return waitset_destroy(&ws);
139}
140
141/**
142 * \brief Cancel a deferred event that has not yet fired
143 */
144errval_t deferred_event_cancel(struct deferred_event *event)
145{
146    enum ws_chanstate chanstate = event->waitset_state.state;
147    dispatcher_handle_t handle = disp_disable();
148    errval_t err = waitset_chan_deregister_disabled(&event->waitset_state, handle);
149    if (err_is_ok(err) && chanstate != CHAN_PENDING) {
150        // remove from dispatcher queue
151        struct dispatcher_generic *disp = get_dispatcher_generic(handle);
152        if (event->prev == NULL) {
153            disp->deferred_events = event->next;
154        } else {
155            event->prev->next = event->next;
156        }
157        if (event->next != NULL) {
158            event->next->prev = event->prev;
159        }
160        update_wakeup_disabled(handle);
161    }
162
163    disp_enable(handle);
164    return err;
165}
166
167static void periodic_event_handler(void *arg)
168{
169    struct periodic_event *e = arg;
170    assert(e != NULL);
171
172    // re-register (first, in case the handler wishes to cancel it)
173    errval_t err = deferred_event_register(&e->de, e->waitset, e->period,
174                           MKCLOSURE(periodic_event_handler, e));
175    assert(err_is_ok(err));
176
177    // run handler
178    e->cl.handler(e->cl.arg);
179}
180
181/**
182 * \brief Create a periodic event
183 *
184 * A periodic event will repeatedly run a closure at a fixed rate until cancelled.
185 *
186 * \param event Storage for event state
187 * \param ws Waitset
188 * \param period Period, in microseconds
189 * \param closure Closure to run
190 */
191errval_t periodic_event_create(struct periodic_event *event, struct waitset *ws,
192                               delayus_t period, struct event_closure closure)
193{
194    assert(event != NULL);
195    deferred_event_init(&event->de);
196    event->cl = closure;
197    event->waitset = ws;
198    event->period = period;
199    return deferred_event_register(&event->de, ws, period,
200                                   MKCLOSURE(periodic_event_handler, event));
201}
202
203/// Cancel a periodic event
204errval_t periodic_event_cancel(struct periodic_event *event)
205{
206    return deferred_event_cancel(&event->de);
207}
208
209
210/// Trigger any pending deferred events, while disabled
211void trigger_deferred_events_disabled(dispatcher_handle_t dh, systime_t now)
212{
213    struct dispatcher_generic *dg = get_dispatcher_generic(dh);
214    struct deferred_event *e;
215    errval_t err;
216
217    for (e = dg->deferred_events; e != NULL && e->time <= now; e = e->next) {
218        err = waitset_chan_trigger_disabled(&e->waitset_state, dh);
219        assert_disabled(err_is_ok(err));
220    }
221    dg->deferred_events = e;
222    if (e != NULL) {
223        e->prev = NULL;
224    }
225    update_wakeup_disabled(dh);
226}
227