All user events take a void *data
[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                            void *data)
26 {
27         assert(ev_type == EV_ALARM);
28         if (ev_msg) {
29                 // There is a slight race here if you don't disable the alarm before
30                 // deregistering its handler.  Make sure you do this properly.
31                 handle_event_t handler = dispatch.handlers[ev_msg->ev_arg2];
32                 if (handler)
33                         handler(ev_msg, ev_type, data);
34         }
35 }
36
37 /* Initalize the alarm_dispatcher. This should only be called once. */
38 static void init_alarm_dispatch()
39 {
40         spin_pdr_init(&dispatch.lock);
41         dispatch.handlers = NULL;
42         dispatch.length = 0;
43         ev_handlers[EV_ALARM] = dispatch_alarm;
44 }
45
46 /* Grow the handler array if necessary.  The array lock must be held when
47  * calling this function. */
48 static void __maybe_grow_handler_array(int index)
49 {
50         if (dispatch.length <= index) {
51                 int new_size = GROWTH_INC * (1 + index/GROWTH_INC);
52                 dispatch.handlers = realloc(dispatch.handlers,
53                                             new_size * sizeof(handle_event_t));
54                 for (int i=dispatch.length; i<new_size; i++)
55                         dispatch.handlers[i] = NULL;
56                 dispatch.length = new_size;
57         }
58 }
59
60 /* Register an alarm handler for alarmid. Make sure the alarm is inactive
61  * before calling this function. */
62 void alarm_dispatch_register(int alarmid, handle_event_t handler)
63 {
64         run_once(init_alarm_dispatch());
65
66         spin_pdr_lock(&dispatch.lock);
67         __maybe_grow_handler_array(alarmid);
68         dispatch.handlers[alarmid] = handler;
69         spin_pdr_unlock(&dispatch.lock);
70 }
71
72 /* Deregister an alarm handler for alarmid. Make sure the alarm is inactive
73  * before calling this function. */
74 void alarm_dispatch_deregister(int alarmid)
75 {
76         spin_pdr_lock(&dispatch.lock);
77         if (alarmid < dispatch.length)
78                 dispatch.handlers[alarmid] = NULL;
79         spin_pdr_unlock(&dispatch.lock);
80 }
81