]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/timer_call.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / osfmk / kern / timer_call.c
1 /*
2 * Copyright (c) 1993-1995, 1999-2004 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>
35 #include <kern/processor.h>
36
37 #include <kern/timer_call.h>
38 #include <kern/call_entry.h>
39
40 #include <sys/kdebug.h>
41
42 decl_simple_lock_data(static,timer_call_lock)
43
44 static struct {
45 int delayed_num,
46 delayed_hiwat;
47 } timer_call_vars;
48
49 static void
50 timer_call_interrupt(
51 uint64_t timestamp);
52
53 #define qe(x) ((queue_entry_t)(x))
54 #define TC(x) ((timer_call_t)(x))
55
56 void
57 timer_call_initialize(void)
58 {
59 spl_t s;
60
61 simple_lock_init(&timer_call_lock, 0);
62
63 s = splclock();
64 simple_lock(&timer_call_lock);
65
66 clock_set_timer_func((clock_timer_func_t)timer_call_interrupt);
67
68 simple_unlock(&timer_call_lock);
69 splx(s);
70 }
71
72 void
73 timer_call_setup(
74 timer_call_t call,
75 timer_call_func_t func,
76 timer_call_param_t param0)
77 {
78 call_entry_setup(call, func, param0);
79 }
80
81 static __inline__
82 void
83 _delayed_call_enqueue(
84 queue_t queue,
85 timer_call_t call)
86 {
87 timer_call_t current;
88
89 current = TC(queue_first(queue));
90
91 while (TRUE) {
92 if ( queue_end(queue, qe(current)) ||
93 call->deadline < current->deadline ) {
94 current = TC(queue_prev(qe(current)));
95 break;
96 }
97
98 current = TC(queue_next(qe(current)));
99 }
100
101 insque(qe(call), qe(current));
102 if (++timer_call_vars.delayed_num > timer_call_vars.delayed_hiwat)
103 timer_call_vars.delayed_hiwat = timer_call_vars.delayed_num;
104
105 call->state = DELAYED;
106 }
107
108 static __inline__
109 void
110 _delayed_call_dequeue(
111 timer_call_t call)
112 {
113 (void)remque(qe(call));
114 timer_call_vars.delayed_num--;
115
116 call->state = IDLE;
117 }
118
119 static __inline__
120 void
121 _set_delayed_call_timer(
122 timer_call_t call)
123 {
124 etimer_set_deadline(call->deadline);
125 }
126
127 boolean_t
128 timer_call_enter(
129 timer_call_t call,
130 uint64_t deadline)
131 {
132 boolean_t result = TRUE;
133 queue_t queue;
134 spl_t s;
135
136 s = splclock();
137 simple_lock(&timer_call_lock);
138
139 if (call->state == DELAYED)
140 _delayed_call_dequeue(call);
141 else
142 result = FALSE;
143
144 call->param1 = 0;
145 call->deadline = deadline;
146
147 queue = &PROCESSOR_DATA(current_processor(), timer_call_queue);
148
149 _delayed_call_enqueue(queue, call);
150
151 if (queue_first(queue) == qe(call))
152 _set_delayed_call_timer(call);
153
154 simple_unlock(&timer_call_lock);
155 splx(s);
156
157 return (result);
158 }
159
160 boolean_t
161 timer_call_enter1(
162 timer_call_t call,
163 timer_call_param_t param1,
164 uint64_t deadline)
165 {
166 boolean_t result = TRUE;
167 queue_t queue;
168 spl_t s;
169
170 s = splclock();
171 simple_lock(&timer_call_lock);
172
173 if (call->state == DELAYED)
174 _delayed_call_dequeue(call);
175 else
176 result = FALSE;
177
178 call->param1 = param1;
179 call->deadline = deadline;
180
181 queue = &PROCESSOR_DATA(current_processor(), timer_call_queue);
182
183 _delayed_call_enqueue(queue, call);
184
185 if (queue_first(queue) == qe(call))
186 _set_delayed_call_timer(call);
187
188 simple_unlock(&timer_call_lock);
189 splx(s);
190
191 return (result);
192 }
193
194 boolean_t
195 timer_call_cancel(
196 timer_call_t call)
197 {
198 boolean_t result = TRUE;
199 spl_t s;
200
201 s = splclock();
202 simple_lock(&timer_call_lock);
203
204 if (call->state == DELAYED)
205 _delayed_call_dequeue(call);
206 else
207 result = FALSE;
208
209 simple_unlock(&timer_call_lock);
210 splx(s);
211
212 return (result);
213 }
214
215 boolean_t
216 timer_call_is_delayed(
217 timer_call_t call,
218 uint64_t *deadline)
219 {
220 boolean_t result = FALSE;
221 spl_t s;
222
223 s = splclock();
224 simple_lock(&timer_call_lock);
225
226 if (call->state == DELAYED) {
227 if (deadline != NULL)
228 *deadline = call->deadline;
229 result = TRUE;
230 }
231
232 simple_unlock(&timer_call_lock);
233 splx(s);
234
235 return (result);
236 }
237
238 /*
239 * Called at splclock.
240 */
241
242 void
243 timer_call_shutdown(
244 processor_t processor)
245 {
246 timer_call_t call;
247 queue_t queue, myqueue;
248
249 assert(processor != current_processor());
250
251 queue = &PROCESSOR_DATA(processor, timer_call_queue);
252 myqueue = &PROCESSOR_DATA(current_processor(), timer_call_queue);
253
254 simple_lock(&timer_call_lock);
255
256 call = TC(queue_first(queue));
257
258 while (!queue_end(queue, qe(call))) {
259 _delayed_call_dequeue(call);
260
261 _delayed_call_enqueue(myqueue, call);
262
263 call = TC(queue_first(queue));
264 }
265
266 call = TC(queue_first(myqueue));
267
268 if (!queue_end(myqueue, qe(call)))
269 _set_delayed_call_timer(call);
270
271 simple_unlock(&timer_call_lock);
272 }
273
274 static
275 void
276 timer_call_interrupt(
277 uint64_t timestamp)
278 {
279 timer_call_t call;
280 queue_t queue;
281
282 simple_lock(&timer_call_lock);
283
284 queue = &PROCESSOR_DATA(current_processor(), timer_call_queue);
285
286 call = TC(queue_first(queue));
287
288 while (!queue_end(queue, qe(call))) {
289
290 if (call->deadline <= timestamp) {
291 timer_call_func_t func;
292 timer_call_param_t param0, param1;
293
294 _delayed_call_dequeue(call);
295
296 func = call->func;
297 param0 = call->param0;
298 param1 = call->param1;
299
300 simple_unlock(&timer_call_lock);
301
302 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 2) | DBG_FUNC_START, (int)func, param0, param1, 0, 0);
303
304 (*func)(param0, param1);
305
306 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, 2) | DBG_FUNC_END, (int)func, param0, param1, 0, 0);
307
308 simple_lock(&timer_call_lock);
309 }
310 else
311 break;
312
313 call = TC(queue_first(queue));
314 }
315
316 if (!queue_end(queue, qe(call)))
317 _set_delayed_call_timer(call);
318
319 simple_unlock(&timer_call_lock);
320
321 }