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