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