-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtimer.c
More file actions
250 lines (197 loc) · 5.75 KB
/
timer.c
File metadata and controls
250 lines (197 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
#include "timer.h"
#include "supervisor.h"
#include "common.h"
#define HANDLE_NULL ((timer_t) 0x0000000000000000ull)
#define HANDLE_MAGIC_MASK ((timer_t) 0xFF00000000000000ull)
#define HANDLE_MAGIC_BITS ((timer_t) 0xAA00000000000000ull)
static inline bool handle_check_magic(const timer_t tm)
{
return (tm & HANDLE_MAGIC_MASK) != HANDLE_MAGIC_BITS;
}
static inline size_t handle_remove_magic(const timer_t tm)
{
return (size_t) (tm ^ HANDLE_MAGIC_BITS);
}
static inline timer_t handle_put_magic(const size_t idx)
{
return (timer_t) idx | HANDLE_MAGIC_BITS;
}
#define MAX_TIMERS ((size_t) 4096)
static struct timer {
bool in_use;
timer_cb_t cb;
timer_repeat_t repeat_max, repeat_count;
timer_interval_t interval;
timer_unit_t unit;
bool running, autodel;
} timers[MAX_TIMERS] = {0};
void timer_accept_timeout(const size_t timer_idx)
{
struct timer *const timer = &timers[timer_idx];
if (unlikely(!timer->running)) {
return;
}
timer->repeat_count++;
if (timer->repeat_max && timer->repeat_count >= timer->repeat_max) {
timer->running = false;
if (timer->autodel && likely(!supervisor_del_timer(timer_idx))) {
*timer = (const struct timer) {0};
} else if (!timer->autodel) {
supervisor_disable_timer(timer_idx);
}
}
}
timer_cb_t timer_get_cb(const size_t timer_idx)
{
return timers[timer_idx].cb;
}
void timer_delete_all(void)
{
for (size_t idx = 0; idx < MAX_TIMERS; ++idx) {
if (timers[idx].in_use) {
supervisor_del_timer(idx);
timers[idx] = (struct timer) {0};
}
}
}
static inline size_t find_free_timer(void)
{
static size_t last_allocated_idx = MAX_TIMERS;
for (size_t idx = last_allocated_idx; idx < MAX_TIMERS; ++idx) {
if (!timers[idx].in_use) {
last_allocated_idx = idx;
return idx;
}
}
for (size_t idx = 0; idx < last_allocated_idx; ++idx) {
if (!timers[idx].in_use) {
last_allocated_idx = idx;
return idx;
}
}
return MAX_TIMERS;
}
static inline size_t check_handle(const timer_t tm)
{
if (unlikely(tm == HANDLE_NULL)) {
log_warn("Timer handle is null");
return MAX_TIMERS;
}
if (unlikely(handle_check_magic(tm))) {
log_warn("Timer handle invalid: %016llX does not have initial 'AA' bits", tm);
return MAX_TIMERS;
}
const size_t idx = handle_remove_magic(tm);
if (unlikely(idx >= MAX_TIMERS)) {
log_warn("Timer handle out of bounds (%zu): %016llX", MAX_TIMERS, tm);
return MAX_TIMERS;
}
if (unlikely(!timers[idx].in_use)) {
log_warn("Timer handle deallocated: %016llX", tm);
return MAX_TIMERS;
}
return idx;
}
timer_t timer_new(void)
{
const size_t free_idx = find_free_timer();
if (unlikely(free_idx == MAX_TIMERS)) {
log_warn("Timer limit of %zu exceeded", MAX_TIMERS);
return HANDLE_NULL;
}
if (unlikely(supervisor_add_timer(free_idx, false, 1, TIMER_UNIT_SEC))) {
return HANDLE_NULL;
}
timers[free_idx] = (const struct timer) {
.in_use = true,
.cb = NULL,
.repeat_max = 0,
.repeat_count = 0,
.interval = 1,
.unit = TIMER_UNIT_SEC,
.running = false,
.autodel = false,
};
return handle_put_magic(free_idx);
}
timer_t timer_add(const timer_cb_t cb, const timer_repeat_t repeat, const bool run, const timer_interval_t interval, const timer_unit_t unit, const bool autodel)
{
const size_t free_idx = find_free_timer();
if (unlikely(free_idx == MAX_TIMERS)) {
log_warn("Timer limit of %zu exceeded", MAX_TIMERS);
return HANDLE_NULL;
}
if (unlikely(supervisor_add_timer(free_idx, run, interval, unit))) {
return HANDLE_NULL;
}
timers[free_idx] = (const struct timer) {
.in_use = true,
.cb = cb,
.repeat_max = repeat,
.repeat_count = 0,
.interval = interval,
.unit = unit,
.running = run,
.autodel = autodel,
};
return handle_put_magic(free_idx);
}
bool timer_set_cb(const timer_t tm, const timer_cb_t cb)
{
const size_t idx = check_handle(tm);
if (unlikely(idx == MAX_TIMERS)) {
return false;
}
timers[idx].cb = cb;
return true;
}
bool timer_set_repeat(const timer_t tm, const timer_repeat_t repeat)
{
const size_t idx = check_handle(tm);
if (unlikely(idx == MAX_TIMERS)) {
return false;
}
struct timer *const timer = &timers[idx];
timer->repeat_count = 0;
timer->repeat_max = repeat;
return true;
}
bool timer_set_interval(const timer_t tm, const timer_interval_t interval, const timer_unit_t unit)
{
const size_t idx = check_handle(tm);
if (unlikely(idx == MAX_TIMERS || supervisor_enable_timer(idx, interval, unit))) {
return false;
}
struct timer *const timer = &timers[idx];
timer->interval = interval;
timer->unit = unit;
timer->running = true;
return true;
}
bool timer_pause(const timer_t tm)
{
const size_t idx = check_handle(tm);
if (unlikely(idx == MAX_TIMERS || supervisor_disable_timer(idx))) {
return false;
}
timers[idx].running = false;
return true;
}
bool timer_resume(const timer_t tm)
{
const size_t idx = check_handle(tm);
if (unlikely(idx == MAX_TIMERS || supervisor_enable_timer(idx, timers[idx].interval, timers[idx].unit))) {
return false;
}
timers[idx].running = true;
return true;
}
bool timer_del(const timer_t tm)
{
const size_t idx = check_handle(tm);
if (unlikely(idx == MAX_TIMERS || supervisor_del_timer(idx))) {
return false;
}
timers[idx] = (const struct timer) {0};
return true;
}