1 /* 2 * Copyright (c) 1998-2000, 2009-2010 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 #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> 43 #include <IOKit/IOKitDebug.h> 44 #if CONFIG_DTRACE 45 #include <mach/sdt.h> 46 #endif 47 48 #include <libkern/Block.h> 49 50 51 #define super IOEventSource 52 OSDefineMetaClassAndStructors(IOTimerEventSource, IOEventSource) 53 OSMetaClassDefineReservedUsed(IOTimerEventSource, 0); 54 OSMetaClassDefineReservedUsed(IOTimerEventSource, 1); 55 OSMetaClassDefineReservedUsed(IOTimerEventSource, 2); 56 OSMetaClassDefineReservedUnused(IOTimerEventSource, 3); 57 OSMetaClassDefineReservedUnused(IOTimerEventSource, 4); 58 OSMetaClassDefineReservedUnused(IOTimerEventSource, 5); 59 OSMetaClassDefineReservedUnused(IOTimerEventSource, 6); 60 OSMetaClassDefineReservedUnused(IOTimerEventSource, 7); 61 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 93 // 94 // reserved != 0 means IOTimerEventSource::timeoutAndRelease is being used, 95 // not a subclassed implementation. 96 // 97 98 // Timeout handler function. This function is called by the kernel when 99 // the timeout interval expires. 100 // 101 102 __inline__ void 103 IOTimerEventSource::invokeAction(IOTimerEventSource::Action _action, IOTimerEventSource * ts, 104 OSObject * _owner, IOWorkLoop * _workLoop) 105 { 106 bool trace = (gIOKitTrace & kIOTraceTimers) ? true : false; 107 108 if (trace) { 109 IOTimeStampStartConstant(IODBG_TIMES(IOTIMES_ACTION), 110 VM_KERNEL_ADDRHIDE(_action), VM_KERNEL_ADDRHIDE(_owner)); 111 } 112 113 if (kActionBlock & flags) { 114 ((IOTimerEventSource::ActionBlock) actionBlock)(ts); 115 } else { 116 (*_action)(_owner, ts); 117 } 118 119 #if CONFIG_DTRACE 120 DTRACE_TMR3(iotescallout__expire, Action, _action, OSObject, _owner, void, _workLoop); 121 #endif 122 123 if (trace) { 124 IOTimeStampEndConstant(IODBG_TIMES(IOTIMES_ACTION), 125 VM_KERNEL_UNSLIDE(_action), VM_KERNEL_ADDRHIDE(_owner)); 126 } 127 } 128 129 void 130 IOTimerEventSource::timeout(void *self) 131 { 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 } 151 } 152 153 void 154 IOTimerEventSource::timeoutAndRelease(void * self, void * c) 155 { 156 IOTimerEventSource *me = (IOTimerEventSource *) self; 157 /* The second parameter (a pointer) gets abused to carry an SInt32, so on LP64, "count" 158 * must be cast to "long" before, in order to tell GCC we're not truncating a pointer. */ 159 SInt32 count = (SInt32) (long) c; 160 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(); 181 } 182 183 // -- work loop delivery 184 185 bool 186 IOTimerEventSource::checkForWork() 187 { 188 Action doit; 189 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 } 196 197 return false; 198 } 199 200 void 201 IOTimerEventSource::timeoutSignaled(void * self, void * c) 202 { 203 IOTimerEventSource *me = (IOTimerEventSource *) self; 204 205 me->reserved->calloutGenerationSignaled = (SInt32)(long) c; 206 if (me->enabled) { 207 me->signalWorkAvailable(); 208 } 209 } 210 211 // -- 212 213 void 214 IOTimerEventSource::setTimeoutFunc() 215 { 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); 289 } 290 291 bool 292 IOTimerEventSource::init(OSObject *inOwner, Action inAction) 293 { 294 if (!super::init(inOwner, (IOEventSource::Action) inAction)) { 295 return false; 296 } 297 298 setTimeoutFunc(); 299 if (!calloutEntry) { 300 return false; 301 } 302 303 IOStatisticsInitializeCounter(); 304 305 return true; 306 } 307 308 bool 309 IOTimerEventSource::init(uint32_t options, OSObject *inOwner, Action inAction) 310 { 311 abstime = options; 312 return init(inOwner, inAction); 313 } 314 315 IOTimerEventSource * 316 IOTimerEventSource::timerEventSource(uint32_t inOptions, OSObject *inOwner, Action inAction) 317 { 318 IOTimerEventSource *me = new IOTimerEventSource; 319 320 if (me && !me->init(inOptions, inOwner, inAction)) { 321 me->release(); 322 return NULL; 323 } 324 325 return me; 326 } 327 328 IOTimerEventSource * 329 IOTimerEventSource::timerEventSource(uint32_t options, OSObject *inOwner, ActionBlock _action) 330 { 331 IOTimerEventSource * tes; 332 tes = IOTimerEventSource::timerEventSource(options, inOwner, (Action) NULL); 333 if (tes) { 334 tes->setActionBlock((IOEventSource::ActionBlock) _action); 335 } 336 337 return tes; 338 } 339 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 { 345 return IOTimerEventSource::timerEventSource( 346 kIOTimerEventSourceOptionsPriorityKernelHigh, 347 inOwner, inAction); 348 } 349 350 void 351 IOTimerEventSource::free() 352 { 353 if (calloutEntry) { 354 __assert_only bool freed; 355 356 cancelTimeout(); 357 358 freed = thread_call_free((thread_call_t) calloutEntry); 359 assert(freed); 360 } 361 362 if (reserved) { 363 IODelete(reserved, ExpansionData, 1); 364 } 365 366 super::free(); 367 } 368 369 void 370 IOTimerEventSource::cancelTimeout() 371 { 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 } 381 } 382 383 void 384 IOTimerEventSource::enable() 385 { 386 super::enable(); 387 if (kIOReturnSuccess != wakeAtTime(abstime)) { 388 super::disable(); // Problem re-scheduling timeout ignore enable 389 } 390 } 391 392 void 393 IOTimerEventSource::disable() 394 { 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 } 404 } 405 406 IOReturn 407 IOTimerEventSource::setTimeoutTicks(UInt32 ticks) 408 { 409 return setTimeout(ticks, kTickScale); 410 } 411 412 IOReturn 413 IOTimerEventSource::setTimeoutMS(UInt32 ms) 414 { 415 return setTimeout(ms, kMillisecondScale); 416 } 417 418 IOReturn 419 IOTimerEventSource::setTimeoutUS(UInt32 us) 420 { 421 return setTimeout(us, kMicrosecondScale); 422 } 423 424 IOReturn 425 IOTimerEventSource::setTimeout(UInt32 interval, UInt32 scale_factor) 426 { 427 AbsoluteTime end; 428 429 clock_interval_to_deadline(interval, scale_factor, &end); 430 return wakeAtTime(end); 431 } 432 433 #if !defined(__LP64__) 434 IOReturn 435 IOTimerEventSource::setTimeout(mach_timespec_t interval) 436 { 437 AbsoluteTime end, nsecs; 438 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); 444 445 return wakeAtTime(end); 446 } 447 #endif 448 449 IOReturn 450 IOTimerEventSource::setTimeout(AbsoluteTime interval) 451 { 452 AbsoluteTime end; 453 clock_absolutetime_interval_to_deadline(interval, &end); 454 return wakeAtTime(end); 455 } 456 457 IOReturn 458 IOTimerEventSource::setTimeout(uint32_t options, 459 AbsoluteTime abstime, AbsoluteTime leeway) 460 { 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); 469 } 470 471 IOReturn 472 IOTimerEventSource::wakeAtTimeTicks(UInt32 ticks) 473 { 474 return wakeAtTime(ticks, kTickScale); 475 } 476 477 IOReturn 478 IOTimerEventSource::wakeAtTimeMS(UInt32 ms) 479 { 480 return wakeAtTime(ms, kMillisecondScale); 481 } 482 483 IOReturn 484 IOTimerEventSource::wakeAtTimeUS(UInt32 us) 485 { 486 return wakeAtTime(us, kMicrosecondScale); 487 } 488 489 IOReturn 490 IOTimerEventSource::wakeAtTime(UInt32 inAbstime, UInt32 scale_factor) 491 { 492 AbsoluteTime end; 493 clock_interval_to_absolutetime_interval(inAbstime, scale_factor, &end); 494 495 return wakeAtTime(end); 496 } 497 498 #if !defined(__LP64__) 499 IOReturn 500 IOTimerEventSource::wakeAtTime(mach_timespec_t inAbstime) 501 { 502 AbsoluteTime end, nsecs; 503 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); 509 510 return wakeAtTime(end); 511 } 512 #endif 513 514 void 515 IOTimerEventSource::setWorkLoop(IOWorkLoop *inWorkLoop) 516 { 517 super::setWorkLoop(inWorkLoop); 518 if (enabled && AbsoluteTime_to_scalar(&abstime) && workLoop) { 519 wakeAtTime(abstime); 520 } 521 } 522 523 IOReturn 524 IOTimerEventSource::wakeAtTime(AbsoluteTime inAbstime) 525 { 526 return wakeAtTime(0, inAbstime, 0); 527 } 528 529 IOReturn 530 IOTimerEventSource::wakeAtTime(uint32_t options, AbsoluteTime inAbstime, AbsoluteTime leeway) 531 { 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; 567 } 568