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
|
#include "util/timer.h"
#include "proc/spinlock.h"
#include "util/time.h"
static timer_t *timer_running = NULL;
static uint64_t timer_next_expiry = -1;
static list_t timers_primary = LIST_INITIALIZER(timers_primary);
static list_t timers_secondary = LIST_INITIALIZER(timers_secondary);
static int timers_firing = 0;
void timer_init(timer_t *timer)
{
timer->expires = -1;
list_link_init(&timer->link);
}
void timer_add(timer_t *timer) { timer_mod(timer, timer->expires); }
int __timer_del(timer_t *timer)
{
int ret = 0;
if (list_link_is_linked(&timer->link))
{
list_remove(&timer->link);
ret = 1;
}
return ret;
}
int timer_del(timer_t *timer)
{
int ret = __timer_del(timer);
return ret;
}
void __timer_add(timer_t *timer)
{
KASSERT(!list_link_is_linked(&timer->link));
list_t *list = timers_firing ? &timers_secondary : &timers_primary;
list_insert_head(list, &timer->link);
}
int timer_mod(timer_t *timer, int expires)
{
timer->expires = expires;
int ret = __timer_del(timer);
__timer_add(timer);
timer_next_expiry = MIN(timer_next_expiry, timer->expires);
return ret;
}
int timer_pending(timer_t *timer)
{
int ret = list_link_is_linked(&timer->link);
return ret;
}
int timer_del_sync(timer_t *timer)
{
/* Not great performance wise... */
while (timer_running == timer)
{
sched_yield();
}
int ret = __timer_del(timer);
return ret;
}
/* Note: using a linked-list rather than some priority is terribly inefficient
* Also this implementation is just bad. Sorry.
*/
int ready = 0;
void __timers_fire()
{
if (curthr && !preemption_enabled())
{
return;
}
timers_firing = 1;
//dbg(DBG_PRINT, "next expiry: %d\n", timer_next_expiry);
if (jiffies < timer_next_expiry)
{
timers_firing = 0;
return;
}
uint64_t min_expiry = 0;
list_iterate(&timers_primary, timer, timer_t, link)
{
if (jiffies >= timer->expires)
{
list_remove(&timer->link);
timer_running = timer;
timer->function(timer->data);
timer_running = NULL;
}
else
{
min_expiry = MIN(min_expiry, timer->expires);
}
}
/* migrate from the backup list to the primary list */
list_iterate(&timers_secondary, timer, timer_t, link)
{
min_expiry = MIN(min_expiry, timer->expires);
list_remove(&timer->link);
list_insert_head(&timers_primary, &timer->link);
}
timer_next_expiry = min_expiry;
timers_firing = 0;
}
|