This source file includes following definitions.
- timeout_startup
- timeout_set
- timeout_add
- timeout_del
- timeout_hardclock_update
- softclock
- db_show_callout_bucket
- db_show_callout
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 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/lock.h>
31 #include <sys/timeout.h>
32 #include <sys/mutex.h>
33 #include <sys/queue.h>
34
35 #ifdef DDB
36 #include <machine/db_machdep.h>
37 #include <ddb/db_interface.h>
38 #include <ddb/db_access.h>
39 #include <ddb/db_sym.h>
40 #include <ddb/db_output.h>
41 #endif
42
43
44
45
46
47
48
49
50 #define BUCKETS 1024
51 #define WHEELSIZE 256
52 #define WHEELMASK 255
53 #define WHEELBITS 8
54
55 struct circq timeout_wheel[BUCKETS];
56 struct circq timeout_todo;
57
58 #define MASKWHEEL(wheel, time) (((time) >> ((wheel)*WHEELBITS)) & WHEELMASK)
59
60 #define BUCKET(rel, abs) \
61 (timeout_wheel[ \
62 ((rel) <= (1 << (2*WHEELBITS))) \
63 ? ((rel) <= (1 << WHEELBITS)) \
64 ? MASKWHEEL(0, (abs)) \
65 : MASKWHEEL(1, (abs)) + WHEELSIZE \
66 : ((rel) <= (1 << (3*WHEELBITS))) \
67 ? MASKWHEEL(2, (abs)) + 2*WHEELSIZE \
68 : MASKWHEEL(3, (abs)) + 3*WHEELSIZE])
69
70 #define MOVEBUCKET(wheel, time) \
71 CIRCQ_APPEND(&timeout_todo, \
72 &timeout_wheel[MASKWHEEL((wheel), (time)) + (wheel)*WHEELSIZE])
73
74
75
76
77
78
79
80 struct mutex timeout_mutex = MUTEX_INITIALIZER(IPL_HIGH);
81
82
83
84
85
86 #define CIRCQ_INIT(elem) do { \
87 (elem)->next = (elem); \
88 (elem)->prev = (elem); \
89 } while (0)
90
91 #define CIRCQ_INSERT(elem, list) do { \
92 (elem)->prev = (list)->prev; \
93 (elem)->next = (list); \
94 (list)->prev->next = (elem); \
95 (list)->prev = (elem); \
96 } while (0)
97
98 #define CIRCQ_APPEND(fst, snd) do { \
99 if (!CIRCQ_EMPTY(snd)) { \
100 (fst)->prev->next = (snd)->next;\
101 (snd)->next->prev = (fst)->prev;\
102 (snd)->prev->next = (fst); \
103 (fst)->prev = (snd)->prev; \
104 CIRCQ_INIT(snd); \
105 } \
106 } while (0)
107
108 #define CIRCQ_REMOVE(elem) do { \
109 (elem)->next->prev = (elem)->prev; \
110 (elem)->prev->next = (elem)->next; \
111 _Q_INVALIDATE((elem)->prev); \
112 _Q_INVALIDATE((elem)->next); \
113 } while (0)
114
115 #define CIRCQ_FIRST(elem) ((elem)->next)
116
117 #define CIRCQ_EMPTY(elem) (CIRCQ_FIRST(elem) == (elem))
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 extern int ticks;
133
134 void
135 timeout_startup(void)
136 {
137 int b;
138
139 CIRCQ_INIT(&timeout_todo);
140 for (b = 0; b < BUCKETS; b++)
141 CIRCQ_INIT(&timeout_wheel[b]);
142 }
143
144 void
145 timeout_set(struct timeout *new, void (*fn)(void *), void *arg)
146 {
147 new->to_func = fn;
148 new->to_arg = arg;
149 new->to_flags = TIMEOUT_INITIALIZED;
150 }
151
152
153 void
154 timeout_add(struct timeout *new, int to_ticks)
155 {
156 int old_time;
157
158 #ifdef DIAGNOSTIC
159 if (!(new->to_flags & TIMEOUT_INITIALIZED))
160 panic("timeout_add: not initialized");
161 if (to_ticks < 0)
162 panic("timeout_add: to_ticks (%d) < 0", to_ticks);
163 #endif
164
165 mtx_enter(&timeout_mutex);
166
167 old_time = new->to_time;
168 new->to_time = to_ticks + ticks;
169 new->to_flags &= ~TIMEOUT_TRIGGERED;
170
171
172
173
174
175
176 if (new->to_flags & TIMEOUT_ONQUEUE) {
177 if (new->to_time - ticks < old_time - ticks) {
178 CIRCQ_REMOVE(&new->to_list);
179 CIRCQ_INSERT(&new->to_list, &timeout_todo);
180 }
181 } else {
182 new->to_flags |= TIMEOUT_ONQUEUE;
183 CIRCQ_INSERT(&new->to_list, &timeout_todo);
184 }
185 mtx_leave(&timeout_mutex);
186 }
187
188 void
189 timeout_del(struct timeout *to)
190 {
191 mtx_enter(&timeout_mutex);
192 if (to->to_flags & TIMEOUT_ONQUEUE) {
193 CIRCQ_REMOVE(&to->to_list);
194 to->to_flags &= ~TIMEOUT_ONQUEUE;
195 }
196 to->to_flags &= ~TIMEOUT_TRIGGERED;
197 mtx_leave(&timeout_mutex);
198 }
199
200
201
202
203
204 int
205 timeout_hardclock_update(void)
206 {
207 int ret;
208
209 mtx_enter(&timeout_mutex);
210
211 ticks++;
212
213 MOVEBUCKET(0, ticks);
214 if (MASKWHEEL(0, ticks) == 0) {
215 MOVEBUCKET(1, ticks);
216 if (MASKWHEEL(1, ticks) == 0) {
217 MOVEBUCKET(2, ticks);
218 if (MASKWHEEL(2, ticks) == 0)
219 MOVEBUCKET(3, ticks);
220 }
221 }
222 ret = !CIRCQ_EMPTY(&timeout_todo);
223 mtx_leave(&timeout_mutex);
224
225 return (ret);
226 }
227
228 void
229 softclock(void)
230 {
231 struct timeout *to;
232 void (*fn)(void *);
233 void *arg;
234
235 mtx_enter(&timeout_mutex);
236 while (!CIRCQ_EMPTY(&timeout_todo)) {
237
238 to = (struct timeout *)CIRCQ_FIRST(&timeout_todo);
239 CIRCQ_REMOVE(&to->to_list);
240
241
242 if (to->to_time - ticks > 0) {
243 CIRCQ_INSERT(&to->to_list,
244 &BUCKET((to->to_time - ticks), to->to_time));
245 } else {
246 #ifdef DEBUG
247 if (to->to_time - ticks < 0)
248 printf("timeout delayed %d\n", to->to_time -
249 ticks);
250 #endif
251 to->to_flags &= ~TIMEOUT_ONQUEUE;
252 to->to_flags |= TIMEOUT_TRIGGERED;
253
254 fn = to->to_func;
255 arg = to->to_arg;
256
257 mtx_leave(&timeout_mutex);
258 fn(arg);
259 mtx_enter(&timeout_mutex);
260 }
261 }
262 mtx_leave(&timeout_mutex);
263 }
264
265 #ifdef DDB
266 void db_show_callout_bucket(struct circq *);
267
268 void
269 db_show_callout_bucket(struct circq *bucket)
270 {
271 struct timeout *to;
272 struct circq *p;
273 db_expr_t offset;
274 char *name;
275
276 for (p = CIRCQ_FIRST(bucket); p != bucket; p = CIRCQ_FIRST(p)) {
277 to = (struct timeout *)p;
278 db_find_sym_and_offset((db_addr_t)to->to_func, &name, &offset);
279 name = name ? name : "?";
280 db_printf("%9d %2d/%-4d %8x %s\n", to->to_time - ticks,
281 (bucket - timeout_wheel) / WHEELSIZE,
282 bucket - timeout_wheel, to->to_arg, name);
283 }
284 }
285
286 void
287 db_show_callout(db_expr_t addr, int haddr, db_expr_t count, char *modif)
288 {
289 int b;
290
291 db_printf("ticks now: %d\n", ticks);
292 db_printf(" ticks wheel arg func\n");
293
294 mtx_enter(&timeout_mutex);
295 db_show_callout_bucket(&timeout_todo);
296 for (b = 0; b < BUCKETS; b++)
297 db_show_callout_bucket(&timeout_wheel[b]);
298 mtx_leave(&timeout_mutex);
299 }
300 #endif