]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
c910b4d9 | 2 | * Copyright (c) 1993-2008 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
2d21ac55 A |
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. | |
8f6c56a5 | 14 | * |
2d21ac55 A |
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 | |
8f6c56a5 A |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
2d21ac55 A |
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. | |
8f6c56a5 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b A |
27 | */ |
28 | /* | |
29 | * Timer interrupt callout module. | |
1c79356b A |
30 | */ |
31 | ||
32 | #include <mach/mach_types.h> | |
33 | ||
34 | #include <kern/clock.h> | |
9bccf70c | 35 | #include <kern/processor.h> |
2d21ac55 | 36 | #include <kern/etimer.h> |
1c79356b | 37 | #include <kern/timer_call.h> |
c910b4d9 | 38 | #include <kern/timer_queue.h> |
1c79356b A |
39 | #include <kern/call_entry.h> |
40 | ||
0c530ab8 A |
41 | #include <sys/kdebug.h> |
42 | ||
2d21ac55 A |
43 | #if CONFIG_DTRACE && (DEVELOPMENT || DEBUG ) |
44 | #include <mach/sdt.h> | |
45 | #endif | |
1c79356b | 46 | |
2d21ac55 | 47 | decl_simple_lock_data(static,timer_call_lock) |
1c79356b | 48 | |
1c79356b A |
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 | { | |
91447636 | 55 | simple_lock_init(&timer_call_lock, 0); |
1c79356b A |
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 | ||
c910b4d9 A |
67 | __inline__ queue_t |
68 | call_entry_enqueue_deadline( | |
69 | call_entry_t entry, | |
70 | queue_t queue, | |
71 | uint64_t deadline) | |
1c79356b | 72 | { |
c910b4d9 | 73 | queue_t old_queue = entry->queue; |
1c79356b A |
74 | timer_call_t current; |
75 | ||
c910b4d9 A |
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))); | |
1c79356b | 81 | |
c910b4d9 A |
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))); | |
1c79356b A |
93 | } |
94 | ||
c910b4d9 | 95 | insque(qe(entry), qe(current)); |
1c79356b | 96 | } |
c910b4d9 A |
97 | else |
98 | if (deadline < entry->deadline) { | |
99 | current = TC(queue_prev(qe(entry))); | |
1c79356b | 100 | |
c910b4d9 | 101 | (void)remque(qe(entry)); |
1c79356b | 102 | |
c910b4d9 A |
103 | while (TRUE) { |
104 | if ( queue_end(queue, qe(current)) || | |
105 | current->deadline <= deadline ) { | |
106 | break; | |
107 | } | |
1c79356b | 108 | |
c910b4d9 A |
109 | current = TC(queue_prev(qe(current))); |
110 | } | |
1c79356b | 111 | |
c910b4d9 A |
112 | insque(qe(entry), qe(current)); |
113 | } | |
1c79356b | 114 | |
c910b4d9 A |
115 | entry->queue = queue; |
116 | entry->deadline = deadline; | |
117 | ||
118 | return (old_queue); | |
1c79356b A |
119 | } |
120 | ||
c910b4d9 A |
121 | __inline__ queue_t |
122 | call_entry_enqueue_tail( | |
123 | call_entry_t entry, | |
124 | queue_t queue) | |
1c79356b | 125 | { |
c910b4d9 | 126 | queue_t old_queue = entry->queue; |
1c79356b | 127 | |
c910b4d9 A |
128 | if (old_queue != NULL) |
129 | (void)remque(qe(entry)); | |
1c79356b | 130 | |
c910b4d9 | 131 | enqueue_tail(queue, qe(entry)); |
1c79356b | 132 | |
c910b4d9 | 133 | entry->queue = queue; |
1c79356b | 134 | |
c910b4d9 A |
135 | return (old_queue); |
136 | } | |
1c79356b | 137 | |
c910b4d9 A |
138 | __inline__ queue_t |
139 | call_entry_dequeue( | |
140 | call_entry_t entry) | |
141 | { | |
142 | queue_t old_queue = entry->queue; | |
1c79356b | 143 | |
c910b4d9 A |
144 | if (old_queue != NULL) |
145 | (void)remque(qe(entry)); | |
1c79356b | 146 | |
c910b4d9 | 147 | entry->queue = NULL; |
1c79356b | 148 | |
c910b4d9 | 149 | return (old_queue); |
1c79356b A |
150 | } |
151 | ||
152 | boolean_t | |
c910b4d9 A |
153 | timer_call_enter( |
154 | timer_call_t call, | |
155 | uint64_t deadline) | |
1c79356b | 156 | { |
c910b4d9 | 157 | queue_t queue, old_queue; |
1c79356b A |
158 | spl_t s; |
159 | ||
160 | s = splclock(); | |
161 | simple_lock(&timer_call_lock); | |
162 | ||
c910b4d9 | 163 | queue = timer_queue_assign(deadline); |
1c79356b | 164 | |
c910b4d9 | 165 | old_queue = call_entry_enqueue_deadline(call, queue, deadline); |
1c79356b | 166 | |
c910b4d9 | 167 | call->param1 = NULL; |
1c79356b A |
168 | |
169 | simple_unlock(&timer_call_lock); | |
170 | splx(s); | |
171 | ||
c910b4d9 | 172 | return (old_queue != NULL); |
1c79356b A |
173 | } |
174 | ||
175 | boolean_t | |
c910b4d9 A |
176 | timer_call_enter1( |
177 | timer_call_t call, | |
178 | timer_call_param_t param1, | |
179 | uint64_t deadline) | |
1c79356b | 180 | { |
c910b4d9 | 181 | queue_t queue, old_queue; |
1c79356b A |
182 | spl_t s; |
183 | ||
184 | s = splclock(); | |
185 | simple_lock(&timer_call_lock); | |
186 | ||
c910b4d9 | 187 | queue = timer_queue_assign(deadline); |
2d21ac55 | 188 | |
c910b4d9 | 189 | old_queue = call_entry_enqueue_deadline(call, queue, deadline); |
2d21ac55 | 190 | |
c910b4d9 | 191 | call->param1 = param1; |
1c79356b A |
192 | |
193 | simple_unlock(&timer_call_lock); | |
194 | splx(s); | |
195 | ||
c910b4d9 | 196 | return (old_queue != NULL); |
1c79356b A |
197 | } |
198 | ||
199 | boolean_t | |
c910b4d9 A |
200 | timer_call_cancel( |
201 | timer_call_t call) | |
1c79356b | 202 | { |
c910b4d9 | 203 | queue_t old_queue; |
1c79356b A |
204 | spl_t s; |
205 | ||
206 | s = splclock(); | |
207 | simple_lock(&timer_call_lock); | |
208 | ||
c910b4d9 A |
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); | |
1c79356b A |
216 | } |
217 | ||
218 | simple_unlock(&timer_call_lock); | |
219 | splx(s); | |
220 | ||
c910b4d9 | 221 | return (old_queue != NULL); |
1c79356b A |
222 | } |
223 | ||
9bccf70c | 224 | void |
c910b4d9 A |
225 | timer_queue_shutdown( |
226 | queue_t queue) | |
9bccf70c | 227 | { |
c910b4d9 A |
228 | timer_call_t call; |
229 | queue_t new_queue; | |
230 | spl_t s; | |
9bccf70c | 231 | |
c910b4d9 | 232 | s = splclock(); |
9bccf70c A |
233 | simple_lock(&timer_call_lock); |
234 | ||
55e303ae | 235 | call = TC(queue_first(queue)); |
9bccf70c | 236 | |
55e303ae | 237 | while (!queue_end(queue, qe(call))) { |
c910b4d9 | 238 | new_queue = timer_queue_assign(call->deadline); |
9bccf70c | 239 | |
c910b4d9 | 240 | call_entry_enqueue_deadline(call, new_queue, call->deadline); |
9bccf70c | 241 | |
55e303ae | 242 | call = TC(queue_first(queue)); |
9bccf70c A |
243 | } |
244 | ||
9bccf70c | 245 | simple_unlock(&timer_call_lock); |
c910b4d9 | 246 | splx(s); |
9bccf70c A |
247 | } |
248 | ||
c910b4d9 A |
249 | uint64_t |
250 | timer_queue_expire( | |
251 | queue_t queue, | |
252 | uint64_t deadline) | |
1c79356b | 253 | { |
c910b4d9 | 254 | timer_call_t call; |
1c79356b A |
255 | |
256 | simple_lock(&timer_call_lock); | |
257 | ||
55e303ae | 258 | call = TC(queue_first(queue)); |
1c79356b | 259 | |
55e303ae | 260 | while (!queue_end(queue, qe(call))) { |
c910b4d9 | 261 | if (call->deadline <= deadline) { |
1c79356b A |
262 | timer_call_func_t func; |
263 | timer_call_param_t param0, param1; | |
264 | ||
c910b4d9 | 265 | call_entry_dequeue(call); |
1c79356b A |
266 | |
267 | func = call->func; | |
268 | param0 = call->param0; | |
269 | param1 = call->param1; | |
270 | ||
271 | simple_unlock(&timer_call_lock); | |
272 | ||
2d21ac55 A |
273 | KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_EXCP_DECI, |
274 | 2) | |
275 | | DBG_FUNC_START, | |
276 | (unsigned int)func, | |
277 | (unsigned int)param0, | |
278 | (unsigned int)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 | |
0c530ab8 | 285 | |
1c79356b A |
286 | (*func)(param0, param1); |
287 | ||
2d21ac55 A |
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 | (unsigned int)func, | |
298 | (unsigned int)param0, | |
299 | (unsigned int)param1, 0, 0); | |
0c530ab8 | 300 | |
1c79356b | 301 | simple_lock(&timer_call_lock); |
c910b4d9 A |
302 | } |
303 | else | |
1c79356b A |
304 | break; |
305 | ||
55e303ae | 306 | call = TC(queue_first(queue)); |
1c79356b A |
307 | } |
308 | ||
55e303ae | 309 | if (!queue_end(queue, qe(call))) |
c910b4d9 A |
310 | deadline = call->deadline; |
311 | else | |
312 | deadline = UINT64_MAX; | |
1c79356b A |
313 | |
314 | simple_unlock(&timer_call_lock); | |
c910b4d9 A |
315 | |
316 | return (deadline); | |
1c79356b | 317 | } |