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