]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/timer_call.c
xnu-123.5.tar.gz
[apple/xnu.git] / osfmk / kern / timer_call.c
CommitLineData
1c79356b
A
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
39decl_simple_lock_data(static,timer_call_lock)
40
41static
42queue_head_t
43 delayed_call_queues[NCPUS];
44
45static struct {
46 int pending_num,
47 pending_hiwat;
48 int delayed_num,
49 delayed_hiwat;
50} timer_calls;
51
52static boolean_t
53 timer_call_initialized = FALSE;
54
55static void
56timer_call_interrupt(
57 AbsoluteTime timestamp);
58
59#define qe(x) ((queue_entry_t)(x))
60#define TC(x) ((timer_call_t)(x))
61
62void
63timer_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
87void
88timer_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
96static __inline__
97void
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 CMP_ABSOLUTETIME(&call->deadline,
109 &current->deadline) < 0 ) {
110 current = TC(queue_prev(qe(current)));
111 break;
112 }
113
114 current = TC(queue_next(qe(current)));
115 }
116
117 insque(qe(call), qe(current));
118 if (++timer_calls.delayed_num > timer_calls.delayed_hiwat)
119 timer_calls.delayed_hiwat = timer_calls.delayed_num;
120
121 call->state = DELAYED;
122}
123
124static __inline__
125void
126_delayed_call_dequeue(
127 timer_call_t call)
128{
129 (void)remque(qe(call));
130 timer_calls.delayed_num--;
131
132 call->state = IDLE;
133}
134
135static __inline__
136void
137_pending_call_enqueue(
138 queue_t queue,
139 timer_call_t call)
140{
141 enqueue_tail(queue, qe(call));
142 if (++timer_calls.pending_num > timer_calls.pending_hiwat)
143 timer_calls.pending_hiwat = timer_calls.pending_num;
144
145 call->state = PENDING;
146}
147
148static __inline__
149void
150_pending_call_dequeue(
151 timer_call_t call)
152{
153 (void)remque(qe(call));
154 timer_calls.pending_num--;
155
156 call->state = IDLE;
157}
158
159static __inline__
160void
161_set_delayed_call_timer(
162 timer_call_t call)
163{
164 clock_set_timer_deadline(call->deadline);
165}
166
167boolean_t
168timer_call_enter(
169 timer_call_t call,
170 AbsoluteTime deadline)
171{
172 boolean_t result = TRUE;
173 queue_t delayed;
174 spl_t s;
175
176 s = splclock();
177 simple_lock(&timer_call_lock);
178
179 if (call->state == PENDING)
180 _pending_call_dequeue(call);
181 else if (call->state == DELAYED)
182 _delayed_call_dequeue(call);
183 else if (call->state == IDLE)
184 result = FALSE;
185
186 call->param1 = 0;
187 call->deadline = deadline;
188
189 delayed = &delayed_call_queues[cpu_number()];
190
191 _delayed_call_enqueue(delayed, call);
192
193 if (queue_first(delayed) == qe(call))
194 _set_delayed_call_timer(call);
195
196 simple_unlock(&timer_call_lock);
197 splx(s);
198
199 return (result);
200}
201
202boolean_t
203timer_call_enter1(
204 timer_call_t call,
205 timer_call_param_t param1,
206 AbsoluteTime deadline)
207{
208 boolean_t result = TRUE;
209 queue_t delayed;
210 spl_t s;
211
212 s = splclock();
213 simple_lock(&timer_call_lock);
214
215 if (call->state == PENDING)
216 _pending_call_dequeue(call);
217 else if (call->state == DELAYED)
218 _delayed_call_dequeue(call);
219 else if (call->state == IDLE)
220 result = FALSE;
221
222 call->param1 = param1;
223 call->deadline = deadline;
224
225 delayed = &delayed_call_queues[cpu_number()];
226
227 _delayed_call_enqueue(delayed, call);
228
229 if (queue_first(delayed) == qe(call))
230 _set_delayed_call_timer(call);
231
232 simple_unlock(&timer_call_lock);
233 splx(s);
234
235 return (result);
236}
237
238boolean_t
239timer_call_cancel(
240 timer_call_t call)
241{
242 boolean_t result = TRUE;
243 spl_t s;
244
245 s = splclock();
246 simple_lock(&timer_call_lock);
247
248 if (call->state == PENDING)
249 _pending_call_dequeue(call);
250 else if (call->state == DELAYED)
251 _delayed_call_dequeue(call);
252 else
253 result = FALSE;
254
255 simple_unlock(&timer_call_lock);
256 splx(s);
257
258 return (result);
259}
260
261boolean_t
262timer_call_is_delayed(
263 timer_call_t call,
264 AbsoluteTime *deadline)
265{
266 boolean_t result = FALSE;
267 spl_t s;
268
269 s = splclock();
270 simple_lock(&timer_call_lock);
271
272 if (call->state == DELAYED) {
273 if (deadline != NULL)
274 *deadline = call->deadline;
275 result = TRUE;
276 }
277
278 simple_unlock(&timer_call_lock);
279 splx(s);
280
281 return (result);
282}
283
284static
285void
286timer_call_interrupt(
287 AbsoluteTime timestamp)
288{
289 timer_call_t call;
290 queue_t delayed = &delayed_call_queues[cpu_number()];
291
292 simple_lock(&timer_call_lock);
293
294 call = TC(queue_first(delayed));
295
296 while (!queue_end(delayed, qe(call))) {
297 if (CMP_ABSOLUTETIME(&call->deadline, &timestamp) <= 0) {
298 timer_call_func_t func;
299 timer_call_param_t param0, param1;
300
301 _delayed_call_dequeue(call);
302
303 func = call->func;
304 param0 = call->param0;
305 param1 = call->param1;
306
307 simple_unlock(&timer_call_lock);
308
309 (*func)(param0, param1);
310
311 simple_lock(&timer_call_lock);
312 }
313 else
314 break;
315
316 call = TC(queue_first(delayed));
317 }
318
319 if (!queue_end(delayed, qe(call)))
320 _set_delayed_call_timer(call);
321
322 simple_unlock(&timer_call_lock);
323}