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