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