]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/timer_call.c
fe421d3e06f67a84a85a4b04d22eaaf64059c71a
[apple/xnu.git] / osfmk / kern / timer_call.c
1 /*
2 * Copyright (c) 1993-1995, 1999-2000 Apple Computer, Inc.
3 * All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 *
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
18 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
19 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
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.
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>
38 #include <kern/processor.h>
39
40 #include <kern/timer_call.h>
41 #include <kern/call_entry.h>
42
43 decl_simple_lock_data(static,timer_call_lock)
44
45 static
46 queue_head_t
47 delayed_call_queues[NCPUS];
48
49 static struct {
50 int delayed_num,
51 delayed_hiwat;
52 } timer_calls;
53
54 static boolean_t
55 timer_call_initialized = FALSE;
56
57 static void
58 timer_call_interrupt(
59 uint64_t timestamp);
60
61 #define qe(x) ((queue_entry_t)(x))
62 #define TC(x) ((timer_call_t)(x))
63
64 void
65 timer_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
89 void
90 timer_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
98 static __inline__
99 void
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) {
109 if ( queue_end(queue, qe(current)) ||
110 call->deadline < current->deadline ) {
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
125 static __inline__
126 void
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
136 static __inline__
137 void
138 _set_delayed_call_timer(
139 timer_call_t call)
140 {
141 clock_set_timer_deadline(call->deadline);
142 }
143
144 boolean_t
145 timer_call_enter(
146 timer_call_t call,
147 uint64_t deadline)
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
156 if (call->state == DELAYED)
157 _delayed_call_dequeue(call);
158 else
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
177 boolean_t
178 timer_call_enter1(
179 timer_call_t call,
180 timer_call_param_t param1,
181 uint64_t deadline)
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
190 if (call->state == DELAYED)
191 _delayed_call_dequeue(call);
192 else
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
211 boolean_t
212 timer_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
221 if (call->state == DELAYED)
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
232 boolean_t
233 timer_call_is_delayed(
234 timer_call_t call,
235 uint64_t *deadline)
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
255 /*
256 * Called at splclock.
257 */
258
259 void
260 timer_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
291 static
292 void
293 timer_call_interrupt(
294 uint64_t timestamp)
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))) {
304 if (call->deadline <= timestamp) {
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 }