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