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