]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/timer_call.c
xnu-344.tar.gz
[apple/xnu.git] / osfmk / kern / timer_call.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 1993-1995, 1999-2000 Apple Computer, Inc.
3 * All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * The contents of this file constitute Original Code as defined in and
8 * are subject to the Apple Public Source License Version 1.1 (the
9 * "License"). You may not use this file except in compliance with the
10 * License. Please obtain a copy of the License at
11 * http://www.apple.com/publicsource and read it before using this file.
12 *
13 * This Original Code and all software distributed under the License are
14 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
18 * License for the specific language governing rights and limitations
19 * under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 * Timer interrupt callout module.
25 *
26 * HISTORY
27 *
28 * 20 December 2000 (debo)
29 * Created.
30 */
31
32#include <mach/mach_types.h>
33
34#include <kern/clock.h>
9bccf70c 35#include <kern/processor.h>
1c79356b
A
36
37#include <kern/timer_call.h>
38#include <kern/call_entry.h>
39
40decl_simple_lock_data(static,timer_call_lock)
41
42static
43queue_head_t
44 delayed_call_queues[NCPUS];
45
46static struct {
1c79356b
A
47 int delayed_num,
48 delayed_hiwat;
49} timer_calls;
50
51static boolean_t
52 timer_call_initialized = FALSE;
53
54static void
55timer_call_interrupt(
0b4e3aa0 56 uint64_t timestamp);
1c79356b
A
57
58#define qe(x) ((queue_entry_t)(x))
59#define TC(x) ((timer_call_t)(x))
60
61void
62timer_call_initialize(void)
63{
64 spl_t s;
65 int i;
66
67 if (timer_call_initialized)
68 panic("timer_call_initialize");
69
70 simple_lock_init(&timer_call_lock, ETAP_MISC_TIMER);
71
72 s = splclock();
73 simple_lock(&timer_call_lock);
74
75 for (i = 0; i < NCPUS; i++)
76 queue_init(&delayed_call_queues[i]);
77
78 clock_set_timer_func((clock_timer_func_t)timer_call_interrupt);
79
80 timer_call_initialized = TRUE;
81
82 simple_unlock(&timer_call_lock);
83 splx(s);
84}
85
86void
87timer_call_setup(
88 timer_call_t call,
89 timer_call_func_t func,
90 timer_call_param_t param0)
91{
92 call_entry_setup(call, func, param0);
93}
94
95static __inline__
96void
97_delayed_call_enqueue(
98 queue_t queue,
99 timer_call_t call)
100{
101 timer_call_t current;
102
103 current = TC(queue_first(queue));
104
105 while (TRUE) {
0b4e3aa0
A
106 if ( queue_end(queue, qe(current)) ||
107 call->deadline < current->deadline ) {
1c79356b
A
108 current = TC(queue_prev(qe(current)));
109 break;
110 }
111
112 current = TC(queue_next(qe(current)));
113 }
114
115 insque(qe(call), qe(current));
116 if (++timer_calls.delayed_num > timer_calls.delayed_hiwat)
117 timer_calls.delayed_hiwat = timer_calls.delayed_num;
118
119 call->state = DELAYED;
120}
121
122static __inline__
123void
124_delayed_call_dequeue(
125 timer_call_t call)
126{
127 (void)remque(qe(call));
128 timer_calls.delayed_num--;
129
130 call->state = IDLE;
131}
132
1c79356b
A
133static __inline__
134void
135_set_delayed_call_timer(
136 timer_call_t call)
137{
138 clock_set_timer_deadline(call->deadline);
139}
140
141boolean_t
142timer_call_enter(
143 timer_call_t call,
0b4e3aa0 144 uint64_t deadline)
1c79356b
A
145{
146 boolean_t result = TRUE;
147 queue_t delayed;
148 spl_t s;
149
150 s = splclock();
151 simple_lock(&timer_call_lock);
152
9bccf70c 153 if (call->state == DELAYED)
1c79356b 154 _delayed_call_dequeue(call);
9bccf70c 155 else
1c79356b
A
156 result = FALSE;
157
158 call->param1 = 0;
159 call->deadline = deadline;
160
161 delayed = &delayed_call_queues[cpu_number()];
162
163 _delayed_call_enqueue(delayed, call);
164
165 if (queue_first(delayed) == qe(call))
166 _set_delayed_call_timer(call);
167
168 simple_unlock(&timer_call_lock);
169 splx(s);
170
171 return (result);
172}
173
174boolean_t
175timer_call_enter1(
176 timer_call_t call,
177 timer_call_param_t param1,
0b4e3aa0 178 uint64_t deadline)
1c79356b
A
179{
180 boolean_t result = TRUE;
181 queue_t delayed;
182 spl_t s;
183
184 s = splclock();
185 simple_lock(&timer_call_lock);
186
9bccf70c 187 if (call->state == DELAYED)
1c79356b 188 _delayed_call_dequeue(call);
9bccf70c 189 else
1c79356b
A
190 result = FALSE;
191
192 call->param1 = param1;
193 call->deadline = deadline;
194
195 delayed = &delayed_call_queues[cpu_number()];
196
197 _delayed_call_enqueue(delayed, call);
198
199 if (queue_first(delayed) == qe(call))
200 _set_delayed_call_timer(call);
201
202 simple_unlock(&timer_call_lock);
203 splx(s);
204
205 return (result);
206}
207
208boolean_t
209timer_call_cancel(
210 timer_call_t call)
211{
212 boolean_t result = TRUE;
213 spl_t s;
214
215 s = splclock();
216 simple_lock(&timer_call_lock);
217
9bccf70c 218 if (call->state == DELAYED)
1c79356b
A
219 _delayed_call_dequeue(call);
220 else
221 result = FALSE;
222
223 simple_unlock(&timer_call_lock);
224 splx(s);
225
226 return (result);
227}
228
229boolean_t
230timer_call_is_delayed(
231 timer_call_t call,
0b4e3aa0 232 uint64_t *deadline)
1c79356b
A
233{
234 boolean_t result = FALSE;
235 spl_t s;
236
237 s = splclock();
238 simple_lock(&timer_call_lock);
239
240 if (call->state == DELAYED) {
241 if (deadline != NULL)
242 *deadline = call->deadline;
243 result = TRUE;
244 }
245
246 simple_unlock(&timer_call_lock);
247 splx(s);
248
249 return (result);
250}
251
9bccf70c
A
252/*
253 * Called at splclock.
254 */
255
256void
257timer_call_shutdown(
258 processor_t processor)
259{
260 timer_call_t call;
261 queue_t delayed, delayed1;
262
263 assert(processor != current_processor());
264
265 delayed = &delayed_call_queues[processor->slot_num];
266 delayed1 = &delayed_call_queues[cpu_number()];
267
268 simple_lock(&timer_call_lock);
269
270 call = TC(queue_first(delayed));
271
272 while (!queue_end(delayed, qe(call))) {
273 _delayed_call_dequeue(call);
274
275 _delayed_call_enqueue(delayed1, call);
276
277 call = TC(queue_first(delayed));
278 }
279
280 call = TC(queue_first(delayed1));
281
282 if (!queue_end(delayed1, qe(call)))
283 _set_delayed_call_timer(call);
284
285 simple_unlock(&timer_call_lock);
286}
287
1c79356b
A
288static
289void
290timer_call_interrupt(
0b4e3aa0 291 uint64_t timestamp)
1c79356b
A
292{
293 timer_call_t call;
294 queue_t delayed = &delayed_call_queues[cpu_number()];
295
296 simple_lock(&timer_call_lock);
297
298 call = TC(queue_first(delayed));
299
300 while (!queue_end(delayed, qe(call))) {
0b4e3aa0 301 if (call->deadline <= timestamp) {
1c79356b
A
302 timer_call_func_t func;
303 timer_call_param_t param0, param1;
304
305 _delayed_call_dequeue(call);
306
307 func = call->func;
308 param0 = call->param0;
309 param1 = call->param1;
310
311 simple_unlock(&timer_call_lock);
312
313 (*func)(param0, param1);
314
315 simple_lock(&timer_call_lock);
316 }
317 else
318 break;
319
320 call = TC(queue_first(delayed));
321 }
322
323 if (!queue_end(delayed, qe(call)))
324 _set_delayed_call_timer(call);
325
326 simple_unlock(&timer_call_lock);
327}