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