]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/timer_call.c
xnu-1504.7.4.tar.gz
[apple/xnu.git] / osfmk / kern / timer_call.c
1 /*
2 * Copyright (c) 1993-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Timer interrupt callout module.
30 */
31
32 #include <mach/mach_types.h>
33
34 #include <kern/clock.h>
35 #include <kern/processor.h>
36 #include <kern/etimer.h>
37 #include <kern/timer_call.h>
38 #include <kern/timer_queue.h>
39 #include <kern/call_entry.h>
40
41 #include <sys/kdebug.h>
42
43 #if CONFIG_DTRACE && (DEVELOPMENT || DEBUG )
44 #include <mach/sdt.h>
45 #endif
46
47 decl_simple_lock_data(static,timer_call_lock)
48
49 #define qe(x) ((queue_entry_t)(x))
50 #define TC(x) ((timer_call_t)(x))
51
52 void
53 timer_call_initialize(void)
54 {
55 simple_lock_init(&timer_call_lock, 0);
56 }
57
58 void
59 timer_call_setup(
60 timer_call_t call,
61 timer_call_func_t func,
62 timer_call_param_t param0)
63 {
64 call_entry_setup(call, func, param0);
65 }
66
67 __inline__ queue_t
68 call_entry_enqueue_deadline(
69 call_entry_t entry,
70 queue_t queue,
71 uint64_t deadline)
72 {
73 queue_t old_queue = entry->queue;
74 timer_call_t current;
75
76 if (old_queue != queue || entry->deadline < deadline) {
77 if (old_queue != queue)
78 current = TC(queue_first(queue));
79 else
80 current = TC(queue_next(qe(entry)));
81
82 if (old_queue != NULL)
83 (void)remque(qe(entry));
84
85 while (TRUE) {
86 if ( queue_end(queue, qe(current)) ||
87 deadline < current->deadline ) {
88 current = TC(queue_prev(qe(current)));
89 break;
90 }
91
92 current = TC(queue_next(qe(current)));
93 }
94
95 insque(qe(entry), qe(current));
96 }
97 else
98 if (deadline < entry->deadline) {
99 current = TC(queue_prev(qe(entry)));
100
101 (void)remque(qe(entry));
102
103 while (TRUE) {
104 if ( queue_end(queue, qe(current)) ||
105 current->deadline <= deadline ) {
106 break;
107 }
108
109 current = TC(queue_prev(qe(current)));
110 }
111
112 insque(qe(entry), qe(current));
113 }
114
115 entry->queue = queue;
116 entry->deadline = deadline;
117
118 return (old_queue);
119 }
120
121 __inline__ queue_t
122 call_entry_enqueue_tail(
123 call_entry_t entry,
124 queue_t queue)
125 {
126 queue_t old_queue = entry->queue;
127
128 if (old_queue != NULL)
129 (void)remque(qe(entry));
130
131 enqueue_tail(queue, qe(entry));
132
133 entry->queue = queue;
134
135 return (old_queue);
136 }
137
138 __inline__ queue_t
139 call_entry_dequeue(
140 call_entry_t entry)
141 {
142 queue_t old_queue = entry->queue;
143
144 if (old_queue != NULL)
145 (void)remque(qe(entry));
146
147 entry->queue = NULL;
148
149 return (old_queue);
150 }
151
152 boolean_t
153 timer_call_enter(
154 timer_call_t call,
155 uint64_t deadline)
156 {
157 queue_t queue, old_queue;
158 spl_t s;
159
160 s = splclock();
161 simple_lock(&timer_call_lock);
162
163 queue = timer_queue_assign(deadline);
164
165 old_queue = call_entry_enqueue_deadline(call, queue, deadline);
166
167 call->param1 = NULL;
168
169 simple_unlock(&timer_call_lock);
170 splx(s);
171
172 return (old_queue != NULL);
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 queue_t queue, old_queue;
182 spl_t s;
183
184 s = splclock();
185 simple_lock(&timer_call_lock);
186
187 queue = timer_queue_assign(deadline);
188
189 old_queue = call_entry_enqueue_deadline(call, queue, deadline);
190
191 call->param1 = param1;
192
193 simple_unlock(&timer_call_lock);
194 splx(s);
195
196 return (old_queue != NULL);
197 }
198
199 boolean_t
200 timer_call_cancel(
201 timer_call_t call)
202 {
203 queue_t old_queue;
204 spl_t s;
205
206 s = splclock();
207 simple_lock(&timer_call_lock);
208
209 old_queue = call_entry_dequeue(call);
210
211 if (old_queue != NULL) {
212 if (!queue_empty(old_queue))
213 timer_queue_cancel(old_queue, call->deadline, TC(queue_first(old_queue))->deadline);
214 else
215 timer_queue_cancel(old_queue, call->deadline, UINT64_MAX);
216 }
217
218 simple_unlock(&timer_call_lock);
219 splx(s);
220
221 return (old_queue != NULL);
222 }
223
224 void
225 timer_queue_shutdown(
226 queue_t queue)
227 {
228 timer_call_t call;
229 queue_t new_queue;
230 spl_t s;
231
232 s = splclock();
233 simple_lock(&timer_call_lock);
234
235 call = TC(queue_first(queue));
236
237 while (!queue_end(queue, qe(call))) {
238 new_queue = timer_queue_assign(call->deadline);
239
240 call_entry_enqueue_deadline(call, new_queue, call->deadline);
241
242 call = TC(queue_first(queue));
243 }
244
245 simple_unlock(&timer_call_lock);
246 splx(s);
247 }
248
249 uint64_t
250 timer_queue_expire(
251 queue_t queue,
252 uint64_t deadline)
253 {
254 timer_call_t call;
255
256 simple_lock(&timer_call_lock);
257
258 call = TC(queue_first(queue));
259
260 while (!queue_end(queue, qe(call))) {
261 if (call->deadline <= deadline) {
262 timer_call_func_t func;
263 timer_call_param_t param0, param1;
264
265 call_entry_dequeue(call);
266
267 func = call->func;
268 param0 = call->param0;
269 param1 = call->param1;
270
271 simple_unlock(&timer_call_lock);
272
273 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI,
274 2)
275 | DBG_FUNC_START,
276 func,
277 param0,
278 param1, 0, 0);
279
280 #if CONFIG_DTRACE && (DEVELOPMENT || DEBUG )
281 DTRACE_TMR3(callout__start, timer_call_func_t, func,
282 timer_call_param_t, param0,
283 timer_call_param_t, param1);
284 #endif
285
286 (*func)(param0, param1);
287
288 #if CONFIG_DTRACE && (DEVELOPMENT || DEBUG )
289 DTRACE_TMR3(callout__end, timer_call_func_t, func,
290 timer_call_param_t, param0,
291 timer_call_param_t, param1);
292 #endif
293
294 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI,
295 2)
296 | DBG_FUNC_END,
297 func,
298 param0,
299 param1, 0, 0);
300
301 simple_lock(&timer_call_lock);
302 }
303 else
304 break;
305
306 call = TC(queue_first(queue));
307 }
308
309 if (!queue_end(queue, qe(call)))
310 deadline = call->deadline;
311 else
312 deadline = UINT64_MAX;
313
314 simple_unlock(&timer_call_lock);
315
316 return (deadline);
317 }