Add a dispatcher for the alarm event
[akaros.git] / user / benchutil / alarm_dispatch.c
1 /* Copyright (c) 2013 The Regents of the University of California
2  * Kevin Klues <klueska@cs.berkeley.edu>
3  * See LICENSE for details. */
4
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <ros/common.h>
8 #include <arch/atomic.h>
9 #include <spinlock.h>
10 #include <alarm_dispatch.h>
11
12 #define GROWTH_INC 10
13
14 /* The dispatch data structure.  Holds an array of handlers indexed by an
15  * alarmid.  The size of the array is initally 0 and grows in increments of
16  * GROWTH_INC on demand when a larger alarmid is registering its handler. */
17 struct {
18         struct spin_pdr_lock lock;
19         handle_event_t *handlers;
20         int length;
21 } dispatch;
22
23 /* Dispatch the alarm event to its proper handler */
24 static void dispatch_alarm(struct event_msg *ev_msg, unsigned int ev_type)
25 {
26         assert(ev_type == EV_ALARM);
27         if (ev_msg) {
28                 // There is a slight race here if you don't disable the alarm before
29                 // deregistering its handler.  Make sure you do this properly.
30                 dispatch.handlers[ev_msg->ev_arg2](ev_msg, ev_type);
31         }
32 }
33
34 /* Initalize the alarm_dispatcher. This should only be called once. */
35 static void init_alarm_dispatch()
36 {
37         spin_pdr_init(&dispatch.lock);
38         dispatch.handlers = NULL;
39         dispatch.length = 0;
40         ev_handlers[EV_ALARM] = dispatch_alarm;
41 }
42
43 /* Grow the handler array if necessary.  The array lock must be held when
44  * calling this function. */
45 static void __maybe_grow_handler_array(int index)
46 {
47         if (dispatch.length <= index) {
48                 int new_size = dispatch.length + GROWTH_INC*(index/GROWTH_INC);
49                 dispatch.handlers = realloc(dispatch.handlers, new_size);
50                 for (int i=dispatch.length; i<new_size; i++)
51                         dispatch.handlers[i] = NULL;
52                 dispatch.length = new_size;
53         }
54 }
55
56 /* Register an alarm handler for alarmid. Make sure the alarm is inactive
57  * before calling this function. */
58 void alarm_dispatch_register(int alarmid, handle_event_t handler)
59 {
60         run_once(init_alarm_dispatch());
61
62         spin_pdr_lock(&dispatch.lock);
63         __maybe_grow_handler_array(alarmid);
64         dispatch.handlers[alarmid] = handler;
65         spin_pdr_unlock(&dispatch.lock);
66 }
67
68 /* Deregister an alarm handler for alarmid. Make sure the alarm is inactive
69  * before calling this function. */
70 void alarm_dispatch_deregister(int alarmid)
71 {
72         spin_pdr_lock(&dispatch.lock);
73         if (alarmid < dispatch.length)
74                 dispatch.handlers[alarmid] = NULL;
75         spin_pdr_unlock(&dispatch.lock);
76 }
77