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
|
/* SPDX-License-Identifier: GPL-3.0-or-later */
/* Copyright 2021 - 2022, Kim Kuparinen < kimi.h.kuparinen@gmail.com > */
#ifndef APOS_TIMER_H
#define APOS_TIMER_H
/**
* @file timer.h
* Timer handling.
*
* \todo Document exceptions and return values better.
*/
#include <apos/types.h>
/**
* ticks_t typedef, use unsigned 64bit integer on all platforms.
*
* GCC will compile uint64_t even on 32bit platforms, just with some runtime
* overhead, should be fine. This will allow us to have a reasonable time range
* even with nanosecond clocks. (138 years with ~4.2 Hz clock)
*/
typedef uint64_t ticks_t;
/**
* tunit_t typedef, whichever time unit we're dealing with.
*/
typedef size_t tunit_t;
/**
* Timer structure.
*/
struct timer {
/** tid. Thread ID of whoever scheduled the timer. */
id_t tid;
/** cid. Control ID, used to differentiate timers. */
id_t cid;
/** ticks. Absolute number of ticks, essentially a timepoint for when
* the timer should trigger. */
ticks_t ticks;
};
/**
* Initialize timers.
*
* @param fdt Pointer to global FDT
*/
void init_timer(const void *fdt);
/**
* Set up timer interrupt ticks from now.
*
* @param tid Thread id for callback.
* @param ticks Ticks from \ref current_ticks().
* @return Id of created timer.
*/
id_t new_rel_timer(id_t tid, ticks_t ticks);
/**
* Set up timer interrupt at ticks.
*
* @param tid Thread id for callback.
* @param ticks Ticks from \ref current_ticks().
* @return Id of created timer.
*/
id_t new_abs_timer(id_t tid, ticks_t ticks);
/**
* Return a pointer to the newest timer, i.e. the one that is closest to
* triggering.
*
* @return Pointer to a timer or NULL if queue is empty.
*/
struct timer *newest_timer();
/**
* Find a timer associated with a specific control ID.
*
* @param cid Control ID to find.
* @return Pointer to associated timer if found, else NULL.
*/
struct timer *find_timer(id_t cid);
/**
* Remove a timer.
*
* @param timer Pointer to timer to remove.
* @return OK on success.
*/
stat_t remove_timer(struct timer *timer);
/**
* Convert nanoseconds to ticks.
*
* @param nsecs Number of nanoseconds to represent as ticks.
* @return Equivalent ticks to nsecs.
*/
ticks_t nsecs_to_ticks(tunit_t nsecs);
/**
* Convert microseconds to ticks.
*
* @param usecs Number of microseconds to represent as ticks.
* @return Equivalent ticks to usecs.
*/
static inline ticks_t usecs_to_ticks(tunit_t usecs)
{
return nsecs_to_ticks(usecs * 1000);
}
/**
* Convert milliseconds to ticks.
*
* @param msecs Number of milliseconds to represent as ticks.
* @return Equivalent ticks to msecs.
*/
static inline ticks_t msecs_to_ticks(tunit_t msecs)
{
return usecs_to_ticks(msecs * 1000);
}
/**
* Convert seconds to ticks.
*
* @param secs Number of seconds to represent as ticks.
* @return Equivalent ticks to secs.
*/
static inline ticks_t secs_to_ticks(tunit_t secs)
{
/** \todo likely not a problem on 64bit systems, not sure how to handle situation on
* 32bit */
return msecs_to_ticks(secs * 1000);
}
#endif /* APOS_TIMER_H */
|