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