]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
6d2010ae | 2 | * Copyright (c) 1998-2000, 2009-2010 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 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. | |
0a7de745 | 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. | |
0a7de745 | 17 | * |
2d21ac55 A |
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. | |
0a7de745 | 25 | * |
2d21ac55 | 26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
1c79356b | 27 | */ |
1c79356b A |
28 | |
29 | #include <sys/cdefs.h> | |
30 | ||
31 | __BEGIN_DECLS | |
32 | #include <kern/thread_call.h> | |
33 | __END_DECLS | |
34 | ||
35 | #include <IOKit/assert.h> | |
36 | #include <IOKit/system.h> | |
37 | ||
38 | #include <IOKit/IOLib.h> | |
39 | #include <IOKit/IOTimerEventSource.h> | |
40 | #include <IOKit/IOWorkLoop.h> | |
41 | ||
42 | #include <IOKit/IOTimeStamp.h> | |
060df5ea | 43 | #include <IOKit/IOKitDebug.h> |
4b17d6b6 A |
44 | #if CONFIG_DTRACE |
45 | #include <mach/sdt.h> | |
46 | #endif | |
47 | ||
d9a64523 A |
48 | #include <libkern/Block.h> |
49 | ||
50 | ||
1c79356b A |
51 | #define super IOEventSource |
52 | OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource) | |
5ba3f43e A |
53 | OSMetaClassDefineReservedUsed(IOTimerEventSource, 0); |
54 | OSMetaClassDefineReservedUsed(IOTimerEventSource, 1); | |
55 | OSMetaClassDefineReservedUsed(IOTimerEventSource, 2); | |
1c79356b A |
56 | OSMetaClassDefineReservedUnused(IOTimerEventSource, 3); |
57 | OSMetaClassDefineReservedUnused(IOTimerEventSource, 4); | |
58 | OSMetaClassDefineReservedUnused(IOTimerEventSource, 5); | |
59 | OSMetaClassDefineReservedUnused(IOTimerEventSource, 6); | |
60 | OSMetaClassDefineReservedUnused(IOTimerEventSource, 7); | |
61 | ||
6d2010ae A |
62 | #if IOKITSTATS |
63 | ||
64 | #define IOStatisticsInitializeCounter() \ | |
65 | do { \ | |
66 | IOStatistics::setCounterType(IOEventSource::reserved->counter, kIOStatisticsTimerEventSourceCounter); \ | |
67 | } while (0) | |
68 | ||
69 | #define IOStatisticsOpenGate() \ | |
70 | do { \ | |
71 | IOStatistics::countOpenGate(me->IOEventSource::reserved->counter); \ | |
72 | } while (0) | |
73 | ||
74 | #define IOStatisticsCloseGate() \ | |
75 | do { \ | |
76 | IOStatistics::countCloseGate(me->IOEventSource::reserved->counter); \ | |
77 | } while (0) | |
78 | ||
79 | #define IOStatisticsTimeout() \ | |
80 | do { \ | |
81 | IOStatistics::countTimerTimeout(me->IOEventSource::reserved->counter); \ | |
82 | } while (0) | |
83 | ||
84 | #else | |
85 | ||
86 | #define IOStatisticsInitializeCounter() | |
87 | #define IOStatisticsOpenGate() | |
88 | #define IOStatisticsCloseGate() | |
89 | #define IOStatisticsTimeout() | |
90 | ||
91 | #endif /* IOKITSTATS */ | |
92 | ||
0a7de745 | 93 | // |
91447636 | 94 | // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used, |
0a7de745 | 95 | // not a subclassed implementation. |
91447636 A |
96 | // |
97 | ||
1c79356b A |
98 | // Timeout handler function. This function is called by the kernel when |
99 | // the timeout interval expires. | |
100 | // | |
5ba3f43e | 101 | |
d9a64523 | 102 | __inline__ void |
cb323159 A |
103 | IOTimerEventSource::invokeAction(IOTimerEventSource::Action _action, IOTimerEventSource * ts, |
104 | OSObject * _owner, IOWorkLoop * _workLoop) | |
5ba3f43e | 105 | { |
0a7de745 | 106 | bool trace = (gIOKitTrace & kIOTraceTimers) ? true : false; |
5ba3f43e | 107 | |
0a7de745 A |
108 | if (trace) { |
109 | IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION), | |
cb323159 | 110 | VM_KERNEL_ADDRHIDE(_action), VM_KERNEL_ADDRHIDE(_owner)); |
0a7de745 | 111 | } |
5ba3f43e | 112 | |
0a7de745 A |
113 | if (kActionBlock & flags) { |
114 | ((IOTimerEventSource::ActionBlock) actionBlock)(ts); | |
115 | } else { | |
cb323159 | 116 | (*_action)(_owner, ts); |
0a7de745 | 117 | } |
5ba3f43e A |
118 | |
119 | #if CONFIG_DTRACE | |
cb323159 | 120 | DTRACE_TMR3(iotescallout__expire, Action, _action, OSObject, _owner, void, _workLoop); |
5ba3f43e A |
121 | #endif |
122 | ||
0a7de745 A |
123 | if (trace) { |
124 | IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION), | |
cb323159 | 125 | VM_KERNEL_UNSLIDE(_action), VM_KERNEL_ADDRHIDE(_owner)); |
0a7de745 | 126 | } |
5ba3f43e A |
127 | } |
128 | ||
0a7de745 A |
129 | void |
130 | IOTimerEventSource::timeout(void *self) | |
1c79356b | 131 | { |
0a7de745 A |
132 | IOTimerEventSource *me = (IOTimerEventSource *) self; |
133 | ||
134 | IOStatisticsTimeout(); | |
135 | ||
136 | if (me->enabled && me->action) { | |
137 | IOWorkLoop * | |
138 | wl = me->workLoop; | |
139 | if (wl) { | |
140 | Action doit; | |
141 | wl->closeGate(); | |
142 | IOStatisticsCloseGate(); | |
143 | doit = (Action) me->action; | |
144 | if (doit && me->enabled && AbsoluteTime_to_scalar(&me->abstime)) { | |
145 | me->invokeAction(doit, me, me->owner, me->workLoop); | |
146 | } | |
147 | IOStatisticsOpenGate(); | |
148 | wl->openGate(); | |
149 | } | |
150 | } | |
91447636 | 151 | } |
1c79356b | 152 | |
0a7de745 A |
153 | void |
154 | IOTimerEventSource::timeoutAndRelease(void * self, void * c) | |
91447636 | 155 | { |
0a7de745 | 156 | IOTimerEventSource *me = (IOTimerEventSource *) self; |
b0d623f7 | 157 | /* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count" |
0a7de745 | 158 | * must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */ |
b0d623f7 | 159 | SInt32 count = (SInt32) (long) c; |
91447636 | 160 | |
0a7de745 A |
161 | IOStatisticsTimeout(); |
162 | ||
163 | if (me->enabled && me->action) { | |
164 | IOWorkLoop * | |
165 | wl = me->reserved->workLoop; | |
166 | if (wl) { | |
167 | Action doit; | |
168 | wl->closeGate(); | |
169 | IOStatisticsCloseGate(); | |
170 | doit = (Action) me->action; | |
171 | if (doit && (me->reserved->calloutGeneration == count)) { | |
172 | me->invokeAction(doit, me, me->owner, me->workLoop); | |
173 | } | |
174 | IOStatisticsOpenGate(); | |
175 | wl->openGate(); | |
176 | } | |
177 | } | |
178 | ||
179 | me->reserved->workLoop->release(); | |
180 | me->release(); | |
1c79356b A |
181 | } |
182 | ||
5ba3f43e A |
183 | // -- work loop delivery |
184 | ||
0a7de745 A |
185 | bool |
186 | IOTimerEventSource::checkForWork() | |
5ba3f43e | 187 | { |
0a7de745 | 188 | Action doit; |
5ba3f43e | 189 | |
0a7de745 A |
190 | if (reserved |
191 | && (reserved->calloutGenerationSignaled == reserved->calloutGeneration) | |
192 | && enabled && (doit = (Action) action)) { | |
193 | reserved->calloutGenerationSignaled = ~reserved->calloutGeneration; | |
194 | invokeAction(doit, this, owner, workLoop); | |
195 | } | |
5ba3f43e | 196 | |
0a7de745 | 197 | return false; |
5ba3f43e A |
198 | } |
199 | ||
0a7de745 A |
200 | void |
201 | IOTimerEventSource::timeoutSignaled(void * self, void * c) | |
5ba3f43e | 202 | { |
0a7de745 | 203 | IOTimerEventSource *me = (IOTimerEventSource *) self; |
5ba3f43e | 204 | |
0a7de745 A |
205 | me->reserved->calloutGenerationSignaled = (SInt32)(long) c; |
206 | if (me->enabled) { | |
207 | me->signalWorkAvailable(); | |
208 | } | |
5ba3f43e A |
209 | } |
210 | ||
211 | // -- | |
212 | ||
0a7de745 A |
213 | void |
214 | IOTimerEventSource::setTimeoutFunc() | |
1c79356b | 215 | { |
0a7de745 A |
216 | thread_call_priority_t pri; |
217 | uint32_t options; | |
218 | ||
219 | if (reserved) { | |
220 | panic("setTimeoutFunc already %p, %p", this, reserved); | |
221 | } | |
222 | ||
223 | // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used, | |
224 | // not a subclassed implementation | |
225 | reserved = IONew(ExpansionData, 1); | |
226 | reserved->calloutGenerationSignaled = ~reserved->calloutGeneration; | |
227 | options = abstime; | |
228 | abstime = 0; | |
229 | ||
230 | thread_call_options_t tcoptions = 0; | |
231 | thread_call_func_t func = NULL; | |
232 | ||
233 | switch (kIOTimerEventSourceOptionsPriorityMask & options) { | |
234 | case kIOTimerEventSourceOptionsPriorityHigh: | |
235 | pri = THREAD_CALL_PRIORITY_HIGH; | |
236 | func = &IOTimerEventSource::timeoutAndRelease; | |
237 | break; | |
238 | ||
239 | case kIOTimerEventSourceOptionsPriorityKernel: | |
240 | pri = THREAD_CALL_PRIORITY_KERNEL; | |
241 | func = &IOTimerEventSource::timeoutAndRelease; | |
242 | break; | |
243 | ||
244 | case kIOTimerEventSourceOptionsPriorityKernelHigh: | |
245 | pri = THREAD_CALL_PRIORITY_KERNEL_HIGH; | |
246 | func = &IOTimerEventSource::timeoutAndRelease; | |
247 | break; | |
248 | ||
249 | case kIOTimerEventSourceOptionsPriorityUser: | |
250 | pri = THREAD_CALL_PRIORITY_USER; | |
251 | func = &IOTimerEventSource::timeoutAndRelease; | |
252 | break; | |
253 | ||
254 | case kIOTimerEventSourceOptionsPriorityLow: | |
255 | pri = THREAD_CALL_PRIORITY_LOW; | |
256 | func = &IOTimerEventSource::timeoutAndRelease; | |
257 | break; | |
258 | ||
259 | case kIOTimerEventSourceOptionsPriorityWorkLoop: | |
260 | pri = THREAD_CALL_PRIORITY_KERNEL; | |
261 | tcoptions |= THREAD_CALL_OPTIONS_SIGNAL; | |
262 | if (kIOTimerEventSourceOptionsAllowReenter & options) { | |
263 | break; | |
264 | } | |
265 | func = &IOTimerEventSource::timeoutSignaled; | |
266 | break; | |
267 | ||
268 | default: | |
269 | break; | |
270 | } | |
271 | ||
272 | assertf(func, "IOTimerEventSource options 0x%x", options); | |
273 | if (!func) { | |
274 | return; // init will fail | |
275 | } | |
276 | if (THREAD_CALL_OPTIONS_SIGNAL & tcoptions) { | |
277 | flags |= kActive; | |
278 | } else { | |
279 | flags |= kPassive; | |
280 | } | |
281 | ||
282 | if (!(kIOTimerEventSourceOptionsAllowReenter & options)) { | |
283 | tcoptions |= THREAD_CALL_OPTIONS_ONCE; | |
284 | } | |
285 | ||
286 | calloutEntry = (void *) thread_call_allocate_with_options(func, | |
287 | (thread_call_param_t) this, pri, tcoptions); | |
288 | assert(calloutEntry); | |
1c79356b A |
289 | } |
290 | ||
0a7de745 A |
291 | bool |
292 | IOTimerEventSource::init(OSObject *inOwner, Action inAction) | |
1c79356b | 293 | { |
0a7de745 A |
294 | if (!super::init(inOwner, (IOEventSource::Action) inAction)) { |
295 | return false; | |
296 | } | |
1c79356b | 297 | |
0a7de745 A |
298 | setTimeoutFunc(); |
299 | if (!calloutEntry) { | |
300 | return false; | |
301 | } | |
1c79356b | 302 | |
0a7de745 | 303 | IOStatisticsInitializeCounter(); |
6d2010ae | 304 | |
0a7de745 | 305 | return true; |
1c79356b A |
306 | } |
307 | ||
0a7de745 A |
308 | bool |
309 | IOTimerEventSource::init(uint32_t options, OSObject *inOwner, Action inAction) | |
5ba3f43e | 310 | { |
0a7de745 A |
311 | abstime = options; |
312 | return init(inOwner, inAction); | |
5ba3f43e A |
313 | } |
314 | ||
1c79356b | 315 | IOTimerEventSource * |
5ba3f43e | 316 | IOTimerEventSource::timerEventSource(uint32_t inOptions, OSObject *inOwner, Action inAction) |
1c79356b | 317 | { |
0a7de745 | 318 | IOTimerEventSource *me = new IOTimerEventSource; |
1c79356b | 319 | |
0a7de745 A |
320 | if (me && !me->init(inOptions, inOwner, inAction)) { |
321 | me->release(); | |
cb323159 | 322 | return NULL; |
0a7de745 | 323 | } |
1c79356b | 324 | |
0a7de745 | 325 | return me; |
1c79356b A |
326 | } |
327 | ||
d9a64523 | 328 | IOTimerEventSource * |
cb323159 | 329 | IOTimerEventSource::timerEventSource(uint32_t options, OSObject *inOwner, ActionBlock _action) |
d9a64523 | 330 | { |
0a7de745 A |
331 | IOTimerEventSource * tes; |
332 | tes = IOTimerEventSource::timerEventSource(options, inOwner, (Action) NULL); | |
333 | if (tes) { | |
cb323159 | 334 | tes->setActionBlock((IOEventSource::ActionBlock) _action); |
0a7de745 | 335 | } |
d9a64523 | 336 | |
0a7de745 | 337 | return tes; |
d9a64523 A |
338 | } |
339 | ||
5ba3f43e A |
340 | #define _thread_call_cancel(tc) ((kActive & flags) ? thread_call_cancel_wait((tc)) : thread_call_cancel((tc))) |
341 | ||
342 | IOTimerEventSource * | |
343 | IOTimerEventSource::timerEventSource(OSObject *inOwner, Action inAction) | |
344 | { | |
0a7de745 A |
345 | return IOTimerEventSource::timerEventSource( |
346 | kIOTimerEventSourceOptionsPriorityKernelHigh, | |
347 | inOwner, inAction); | |
5ba3f43e A |
348 | } |
349 | ||
0a7de745 A |
350 | void |
351 | IOTimerEventSource::free() | |
1c79356b | 352 | { |
0a7de745 A |
353 | if (calloutEntry) { |
354 | __assert_only bool freed; | |
5ba3f43e | 355 | |
0a7de745 | 356 | cancelTimeout(); |
5ba3f43e | 357 | |
0a7de745 A |
358 | freed = thread_call_free((thread_call_t) calloutEntry); |
359 | assert(freed); | |
360 | } | |
1c79356b | 361 | |
0a7de745 A |
362 | if (reserved) { |
363 | IODelete(reserved, ExpansionData, 1); | |
364 | } | |
91447636 | 365 | |
0a7de745 | 366 | super::free(); |
1c79356b A |
367 | } |
368 | ||
0a7de745 A |
369 | void |
370 | IOTimerEventSource::cancelTimeout() | |
1c79356b | 371 | { |
0a7de745 A |
372 | if (reserved) { |
373 | reserved->calloutGeneration++; | |
374 | } | |
375 | bool active = _thread_call_cancel((thread_call_t) calloutEntry); | |
376 | AbsoluteTime_to_scalar(&abstime) = 0; | |
377 | if (active && reserved && (kPassive & flags)) { | |
378 | release(); | |
379 | workLoop->release(); | |
380 | } | |
1c79356b A |
381 | } |
382 | ||
0a7de745 A |
383 | void |
384 | IOTimerEventSource::enable() | |
1c79356b | 385 | { |
0a7de745 A |
386 | super::enable(); |
387 | if (kIOReturnSuccess != wakeAtTime(abstime)) { | |
388 | super::disable(); // Problem re-scheduling timeout ignore enable | |
389 | } | |
1c79356b A |
390 | } |
391 | ||
0a7de745 A |
392 | void |
393 | IOTimerEventSource::disable() | |
1c79356b | 394 | { |
0a7de745 A |
395 | if (reserved) { |
396 | reserved->calloutGeneration++; | |
397 | } | |
398 | bool active = _thread_call_cancel((thread_call_t) calloutEntry); | |
399 | super::disable(); | |
400 | if (active && reserved && (kPassive & flags)) { | |
401 | release(); | |
402 | workLoop->release(); | |
403 | } | |
1c79356b A |
404 | } |
405 | ||
0a7de745 A |
406 | IOReturn |
407 | IOTimerEventSource::setTimeoutTicks(UInt32 ticks) | |
1c79356b | 408 | { |
0a7de745 | 409 | return setTimeout(ticks, kTickScale); |
1c79356b A |
410 | } |
411 | ||
0a7de745 A |
412 | IOReturn |
413 | IOTimerEventSource::setTimeoutMS(UInt32 ms) | |
1c79356b | 414 | { |
0a7de745 | 415 | return setTimeout(ms, kMillisecondScale); |
1c79356b A |
416 | } |
417 | ||
0a7de745 A |
418 | IOReturn |
419 | IOTimerEventSource::setTimeoutUS(UInt32 us) | |
1c79356b | 420 | { |
0a7de745 | 421 | return setTimeout(us, kMicrosecondScale); |
1c79356b A |
422 | } |
423 | ||
0a7de745 A |
424 | IOReturn |
425 | IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor) | |
1c79356b | 426 | { |
0a7de745 | 427 | AbsoluteTime end; |
2d21ac55 | 428 | |
0a7de745 A |
429 | clock_interval_to_deadline(interval, scale_factor, &end); |
430 | return wakeAtTime(end); | |
1c79356b A |
431 | } |
432 | ||
b0d623f7 | 433 | #if !defined(__LP64__) |
0a7de745 A |
434 | IOReturn |
435 | IOTimerEventSource::setTimeout(mach_timespec_t interval) | |
1c79356b | 436 | { |
0a7de745 | 437 | AbsoluteTime end, nsecs; |
1c79356b | 438 | |
0a7de745 A |
439 | clock_interval_to_absolutetime_interval |
440 | (interval.tv_nsec, kNanosecondScale, &nsecs); | |
441 | clock_interval_to_deadline | |
442 | (interval.tv_sec, NSEC_PER_SEC, &end); | |
443 | ADD_ABSOLUTETIME(&end, &nsecs); | |
1c79356b | 444 | |
0a7de745 | 445 | return wakeAtTime(end); |
1c79356b | 446 | } |
b0d623f7 | 447 | #endif |
1c79356b | 448 | |
0a7de745 A |
449 | IOReturn |
450 | IOTimerEventSource::setTimeout(AbsoluteTime interval) | |
1c79356b | 451 | { |
0a7de745 A |
452 | AbsoluteTime end; |
453 | clock_absolutetime_interval_to_deadline(interval, &end); | |
454 | return wakeAtTime(end); | |
5ba3f43e | 455 | } |
1c79356b | 456 | |
0a7de745 A |
457 | IOReturn |
458 | IOTimerEventSource::setTimeout(uint32_t options, | |
459 | AbsoluteTime abstime, AbsoluteTime leeway) | |
5ba3f43e | 460 | { |
0a7de745 A |
461 | AbsoluteTime end; |
462 | if (options & kIOTimeOptionsContinuous) { | |
463 | clock_continuoustime_interval_to_deadline(abstime, &end); | |
464 | } else { | |
465 | clock_absolutetime_interval_to_deadline(abstime, &end); | |
466 | } | |
467 | ||
468 | return wakeAtTime(options, end, leeway); | |
1c79356b A |
469 | } |
470 | ||
0a7de745 A |
471 | IOReturn |
472 | IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks) | |
1c79356b | 473 | { |
0a7de745 | 474 | return wakeAtTime(ticks, kTickScale); |
1c79356b A |
475 | } |
476 | ||
0a7de745 A |
477 | IOReturn |
478 | IOTimerEventSource::wakeAtTimeMS(UInt32 ms) | |
1c79356b | 479 | { |
0a7de745 | 480 | return wakeAtTime(ms, kMillisecondScale); |
1c79356b A |
481 | } |
482 | ||
0a7de745 A |
483 | IOReturn |
484 | IOTimerEventSource::wakeAtTimeUS(UInt32 us) | |
1c79356b | 485 | { |
0a7de745 | 486 | return wakeAtTime(us, kMicrosecondScale); |
1c79356b A |
487 | } |
488 | ||
0a7de745 A |
489 | IOReturn |
490 | IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor) | |
1c79356b | 491 | { |
0a7de745 A |
492 | AbsoluteTime end; |
493 | clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end); | |
1c79356b | 494 | |
0a7de745 | 495 | return wakeAtTime(end); |
1c79356b A |
496 | } |
497 | ||
b0d623f7 | 498 | #if !defined(__LP64__) |
0a7de745 A |
499 | IOReturn |
500 | IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime) | |
1c79356b | 501 | { |
0a7de745 | 502 | AbsoluteTime end, nsecs; |
1c79356b | 503 | |
0a7de745 A |
504 | clock_interval_to_absolutetime_interval |
505 | (inAbstime.tv_nsec, kNanosecondScale, &nsecs); | |
506 | clock_interval_to_absolutetime_interval | |
507 | (inAbstime.tv_sec, kSecondScale, &end); | |
508 | ADD_ABSOLUTETIME(&end, &nsecs); | |
1c79356b | 509 | |
0a7de745 | 510 | return wakeAtTime(end); |
1c79356b | 511 | } |
b0d623f7 | 512 | #endif |
1c79356b | 513 | |
0a7de745 A |
514 | void |
515 | IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop) | |
91447636 | 516 | { |
0a7de745 A |
517 | super::setWorkLoop(inWorkLoop); |
518 | if (enabled && AbsoluteTime_to_scalar(&abstime) && workLoop) { | |
519 | wakeAtTime(abstime); | |
520 | } | |
91447636 A |
521 | } |
522 | ||
0a7de745 A |
523 | IOReturn |
524 | IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime) | |
5ba3f43e | 525 | { |
0a7de745 | 526 | return wakeAtTime(0, inAbstime, 0); |
5ba3f43e A |
527 | } |
528 | ||
0a7de745 A |
529 | IOReturn |
530 | IOTimerEventSource::wakeAtTime(uint32_t options, AbsoluteTime inAbstime, AbsoluteTime leeway) | |
1c79356b | 531 | { |
0a7de745 A |
532 | if (!action) { |
533 | return kIOReturnNoResources; | |
534 | } | |
535 | ||
536 | abstime = inAbstime; | |
537 | if (enabled && AbsoluteTime_to_scalar(&inAbstime) && AbsoluteTime_to_scalar(&abstime) && workLoop) { | |
538 | uint32_t tcoptions = 0; | |
539 | ||
540 | if (kIOTimeOptionsWithLeeway & options) { | |
541 | tcoptions |= THREAD_CALL_DELAY_LEEWAY; | |
542 | } | |
543 | if (kIOTimeOptionsContinuous & options) { | |
544 | tcoptions |= THREAD_CALL_CONTINUOUS; | |
545 | } | |
546 | ||
547 | if (reserved) { | |
548 | if (kPassive & flags) { | |
549 | retain(); | |
550 | workLoop->retain(); | |
551 | } | |
552 | reserved->workLoop = workLoop; | |
553 | reserved->calloutGeneration++; | |
554 | if (thread_call_enter_delayed_with_leeway((thread_call_t) calloutEntry, | |
555 | (void *)(uintptr_t) reserved->calloutGeneration, inAbstime, leeway, tcoptions) | |
556 | && (kPassive & flags)) { | |
557 | release(); | |
558 | workLoop->release(); | |
559 | } | |
560 | } else { | |
561 | thread_call_enter_delayed_with_leeway((thread_call_t) calloutEntry, | |
562 | NULL, inAbstime, leeway, tcoptions); | |
563 | } | |
564 | } | |
565 | ||
566 | return kIOReturnSuccess; | |
1c79356b | 567 | } |