summaryrefslogtreecommitdiff
path: root/firmware/kernel/timeout.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/kernel/timeout.c')
-rw-r--r--firmware/kernel/timeout.c97
1 files changed, 97 insertions, 0 deletions
diff --git a/firmware/kernel/timeout.c b/firmware/kernel/timeout.c
new file mode 100644
index 0000000000..8039e56ffb
--- /dev/null
+++ b/firmware/kernel/timeout.c
@@ -0,0 +1,97 @@
1
2/****************************************************************************
3 * Tick-based interval timers/one-shots - be mindful this is not really
4 * intended for continuous timers but for events that need to run for a short
5 * time and be cancelled without further software intervention.
6 ****************************************************************************/
7
8#include "config.h"
9#include "system.h" /* TIME_AFTER */
10#include "kernel.h"
11#include "timeout.h"
12#include "general.h"
13
14/* list of active timeout events */
15static struct timeout *tmo_list[MAX_NUM_TIMEOUTS+1];
16
17/* timeout tick task - calls event handlers when they expire
18 * Event handlers may alter expiration, callback and data during operation.
19 */
20static void timeout_tick(void)
21{
22 unsigned long tick = current_tick;
23 struct timeout **p = tmo_list;
24 struct timeout *curr;
25
26 for(curr = *p; curr != NULL; curr = *(++p))
27 {
28 int ticks;
29
30 if(TIME_BEFORE(tick, curr->expires))
31 continue;
32
33 /* this event has expired - call callback */
34 ticks = curr->callback(curr);
35 if(ticks > 0)
36 {
37 curr->expires = tick + ticks; /* reload */
38 }
39 else
40 {
41 timeout_cancel(curr); /* cancel */
42 }
43 }
44}
45
46/* Cancels a timeout callback - can be called from the ISR */
47void timeout_cancel(struct timeout *tmo)
48{
49 int oldlevel = disable_irq_save();
50 int rc = remove_array_ptr((void **)tmo_list, tmo);
51
52 if(rc >= 0 && *tmo_list == NULL)
53 {
54 tick_remove_task(timeout_tick); /* Last one - remove task */
55 }
56
57 restore_irq(oldlevel);
58}
59
60/* Adds a timeout callback - calling with an active timeout resets the
61 interval - can be called from the ISR */
62void timeout_register(struct timeout *tmo, timeout_cb_type callback,
63 int ticks, intptr_t data)
64{
65 int oldlevel;
66 void **arr, **p;
67
68 if(tmo == NULL)
69 return;
70
71 oldlevel = disable_irq_save();
72
73 /* See if this one is already registered */
74 arr = (void **)tmo_list;
75 p = find_array_ptr(arr, tmo);
76
77 if(p - arr < MAX_NUM_TIMEOUTS)
78 {
79 /* Vacancy */
80 if(*p == NULL)
81 {
82 /* Not present */
83 if(*tmo_list == NULL)
84 {
85 tick_add_task(timeout_tick); /* First one - add task */
86 }
87
88 *p = tmo;
89 }
90
91 tmo->callback = callback;
92 tmo->data = data;
93 tmo->expires = current_tick + ticks;
94 }
95
96 restore_irq(oldlevel);
97}