]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/timer_call.c
xnu-201.42.3.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
36 #include <kern/timer_call.h>
37 #include <kern/call_entry.h>
38
39 decl_simple_lock_data(static,timer_call_lock)
40
41 static
42 queue_head_t
43 delayed_call_queues[NCPUS];
44
45 static struct {
46 int pending_num,
47 pending_hiwat;
48 int delayed_num,
49 delayed_hiwat;
50 } timer_calls;
51
52 static boolean_t
53 timer_call_initialized = FALSE;
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 int i;
67
68 if (timer_call_initialized)
69 panic("timer_call_initialize");
70
71 simple_lock_init(&timer_call_lock, ETAP_MISC_TIMER);
72
73 s = splclock();
74 simple_lock(&timer_call_lock);
75
76 for (i = 0; i < NCPUS; i++)
77 queue_init(&delayed_call_queues[i]);
78
79 clock_set_timer_func((clock_timer_func_t)timer_call_interrupt);
80
81 timer_call_initialized = TRUE;
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_calls.delayed_num > timer_calls.delayed_hiwat)
118 timer_calls.delayed_hiwat = timer_calls.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_calls.delayed_num--;
130
131 call->state = IDLE;
132 }
133
134 static __inline__
135 void
136 _pending_call_enqueue(
137 queue_t queue,
138 timer_call_t call)
139 {
140 enqueue_tail(queue, qe(call));
141 if (++timer_calls.pending_num > timer_calls.pending_hiwat)
142 timer_calls.pending_hiwat = timer_calls.pending_num;
143
144 call->state = PENDING;
145 }
146
147 static __inline__
148 void
149 _pending_call_dequeue(
150 timer_call_t call)
151 {
152 (void)remque(qe(call));
153 timer_calls.pending_num--;
154
155 call->state = IDLE;
156 }
157
158 static __inline__
159 void
160 _set_delayed_call_timer(
161 timer_call_t call)
162 {
163 clock_set_timer_deadline(call->deadline);
164 }
165
166 boolean_t
167 timer_call_enter(
168 timer_call_t call,
169 uint64_t deadline)
170 {
171 boolean_t result = TRUE;
172 queue_t delayed;
173 spl_t s;
174
175 s = splclock();
176 simple_lock(&timer_call_lock);
177
178 if (call->state == PENDING)
179 _pending_call_dequeue(call);
180 else if (call->state == DELAYED)
181 _delayed_call_dequeue(call);
182 else if (call->state == IDLE)
183 result = FALSE;
184
185 call->param1 = 0;
186 call->deadline = deadline;
187
188 delayed = &delayed_call_queues[cpu_number()];
189
190 _delayed_call_enqueue(delayed, call);
191
192 if (queue_first(delayed) == qe(call))
193 _set_delayed_call_timer(call);
194
195 simple_unlock(&timer_call_lock);
196 splx(s);
197
198 return (result);
199 }
200
201 boolean_t
202 timer_call_enter1(
203 timer_call_t call,
204 timer_call_param_t param1,
205 uint64_t deadline)
206 {
207 boolean_t result = TRUE;
208 queue_t delayed;
209 spl_t s;
210
211 s = splclock();
212 simple_lock(&timer_call_lock);
213
214 if (call->state == PENDING)
215 _pending_call_dequeue(call);
216 else if (call->state == DELAYED)
217 _delayed_call_dequeue(call);
218 else if (call->state == IDLE)
219 result = FALSE;
220
221 call->param1 = param1;
222 call->deadline = deadline;
223
224 delayed = &delayed_call_queues[cpu_number()];
225
226 _delayed_call_enqueue(delayed, call);
227
228 if (queue_first(delayed) == qe(call))
229 _set_delayed_call_timer(call);
230
231 simple_unlock(&timer_call_lock);
232 splx(s);
233
234 return (result);
235 }
236
237 boolean_t
238 timer_call_cancel(
239 timer_call_t call)
240 {
241 boolean_t result = TRUE;
242 spl_t s;
243
244 s = splclock();
245 simple_lock(&timer_call_lock);
246
247 if (call->state == PENDING)
248 _pending_call_dequeue(call);
249 else if (call->state == DELAYED)
250 _delayed_call_dequeue(call);
251 else
252 result = FALSE;
253
254 simple_unlock(&timer_call_lock);
255 splx(s);
256
257 return (result);
258 }
259
260 boolean_t
261 timer_call_is_delayed(
262 timer_call_t call,
263 uint64_t *deadline)
264 {
265 boolean_t result = FALSE;
266 spl_t s;
267
268 s = splclock();
269 simple_lock(&timer_call_lock);
270
271 if (call->state == DELAYED) {
272 if (deadline != NULL)
273 *deadline = call->deadline;
274 result = TRUE;
275 }
276
277 simple_unlock(&timer_call_lock);
278 splx(s);
279
280 return (result);
281 }
282
283 static
284 void
285 timer_call_interrupt(
286 uint64_t timestamp)
287 {
288 timer_call_t call;
289 queue_t delayed = &delayed_call_queues[cpu_number()];
290
291 simple_lock(&timer_call_lock);
292
293 call = TC(queue_first(delayed));
294
295 while (!queue_end(delayed, qe(call))) {
296 if (call->deadline <= timestamp) {
297 timer_call_func_t func;
298 timer_call_param_t param0, param1;
299
300 _delayed_call_dequeue(call);
301
302 func = call->func;
303 param0 = call->param0;
304 param1 = call->param1;
305
306 simple_unlock(&timer_call_lock);
307
308 (*func)(param0, param1);
309
310 simple_lock(&timer_call_lock);
311 }
312 else
313 break;
314
315 call = TC(queue_first(delayed));
316 }
317
318 if (!queue_end(delayed, qe(call)))
319 _set_delayed_call_timer(call);
320
321 simple_unlock(&timer_call_lock);
322 }