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
|
#include <apos/sp_tree.h>
#include <apos/string.h>
#include <apos/nodes.h>
#include <apos/utils.h>
#include <apos/timer.h>
#include <arch/timer.h>
#include <arch/cpu.h>
static ticks_t ticks_per_sec = 0;
static struct sp_root cpu_timers[MAX_CPUS] = {0};
static struct node_root node_root;
struct timer_node {
struct sp_node sp_n;
struct timer timer;
};
#define timer_container(ptr)\
container_of(ptr, struct timer_node, sp_n)
#define timer_node_container(ptr)\
container_of(ptr, struct timer_node, timer)
static struct sp_root *__cpu_timers()
{
return &cpu_timers[cpu_id()];
}
void init_timer()
{
ticks_per_sec = stat_timer();
init_nodes(&node_root, sizeof(struct timer_node));
}
static id_t __insert_timer(struct timer_node *ti)
{
struct sp_root *root = __cpu_timers();
struct sp_node *n = sp_root(root), *p = NULL;
enum sp_dir d;
while (n) {
struct timer_node *t = container_of(n, struct timer_node, sp_n);
if (ti->timer.cid == t->timer.cid)
ti->timer.cid--;
p = n;
if (ti->timer.cid < t->timer.cid) {
n = sp_left(n);
d = LEFT;
} else {
n = sp_right(n);
d = RIGHT;
}
}
if (sp_root(root))
sp_insert(&sp_root(root), p, &ti->sp_n, d);
else
sp_root(root) = &ti->sp_n;
return ti->timer.cid;
}
/* ticks is absolute */
static id_t __new_timer(id_t tid, ticks_t ticks)
{
struct timer_node *ti = (struct timer_node *)get_node(&node_root);
ti->timer.ticks = ticks;
ti->timer.cid = ticks;
ti->timer.tid = tid;
return __insert_timer(ti);
}
/* these are likely not perfectly accurate timers due to some random delay from
* function calls etc, but probably good enough. */
id_t new_rel_timer(id_t tid, ticks_t ticks)
{
return new_abs_timer(tid, ticks + current_ticks());
}
id_t new_abs_timer(id_t tid, ticks_t ticks)
{
id_t id = __new_timer(tid, ticks);
set_timer(ticks);
return id;
}
struct timer *newest_timer()
{
struct sp_node *t = sp_first(sp_root(__cpu_timers()));
return &timer_container(t)->timer;
}
struct timer *find_timer(id_t cid)
{
struct sp_node *n = sp_root(__cpu_timers());
while (n) {
struct timer_node *t = timer_container(n);
if (t->timer.cid == cid)
return &t->timer;
if (t->timer.cid < cid)
n = sp_left(n);
else
n = sp_right(n);
}
return 0;
}
void remove_timer(struct timer *t)
{
if (!t)
return;
struct sp_node *n = &timer_node_container(t)->sp_n;
sp_remove(&sp_root(__cpu_timers()), n);
}
/* TODO: does this overflow too early? */
ticks_t nsecs_to_ticks(tunit_t nsecs)
{
return (nsecs * ticks_per_sec) / 1000000000;
}
|