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