| OLD | NEW |
| 1 // Copyright (c) 2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/message_pump_mac.h" | 5 #include "base/message_pump_mac.h" |
| 6 | 6 |
| 7 #import <AppKit/AppKit.h> | 7 #import <AppKit/AppKit.h> |
| 8 #import <Foundation/Foundation.h> | 8 #import <Foundation/Foundation.h> |
| 9 #include <IOKit/IOMessage.h> | |
| 10 #include <IOKit/pwr_mgt/IOPMLib.h> | |
| 11 | 9 |
| 12 #include <limits> | 10 #include <limits> |
| 13 | 11 |
| 14 #include "base/logging.h" | 12 #include "base/logging.h" |
| 15 #include "base/time.h" | 13 #include "base/time.h" |
| 16 | 14 |
| 17 namespace { | 15 namespace { |
| 18 | 16 |
| 19 void NoOp(void* info) { | 17 void NoOp(void* info) { |
| 20 } | 18 } |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes); | 107 CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes); |
| 110 | 108 |
| 111 enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator | 109 enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator |
| 112 kCFRunLoopEntry | | 110 kCFRunLoopEntry | |
| 113 kCFRunLoopExit, | 111 kCFRunLoopExit, |
| 114 true, // repeat | 112 true, // repeat |
| 115 0, // priority | 113 0, // priority |
| 116 EnterExitObserver, | 114 EnterExitObserver, |
| 117 &observer_context); | 115 &observer_context); |
| 118 CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes); | 116 CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes); |
| 119 | |
| 120 root_power_domain_ = IORegisterForSystemPower(this, | |
| 121 &power_notification_port_, | |
| 122 PowerStateNotification, | |
| 123 &power_notification_object_); | |
| 124 if (root_power_domain_ != MACH_PORT_NULL) { | |
| 125 CFRunLoopAddSource( | |
| 126 run_loop_, | |
| 127 IONotificationPortGetRunLoopSource(power_notification_port_), | |
| 128 kCFRunLoopCommonModes); | |
| 129 } | |
| 130 } | 117 } |
| 131 | 118 |
| 132 // Ideally called on the run loop thread. If other run loops were running | 119 // Ideally called on the run loop thread. If other run loops were running |
| 133 // lower on the run loop thread's stack when this object was created, the | 120 // lower on the run loop thread's stack when this object was created, the |
| 134 // same number of run loops must be running when this object is destroyed. | 121 // same number of run loops must be running when this object is destroyed. |
| 135 MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() { | 122 MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() { |
| 136 if (root_power_domain_ != MACH_PORT_NULL) { | |
| 137 CFRunLoopRemoveSource( | |
| 138 run_loop_, | |
| 139 IONotificationPortGetRunLoopSource(power_notification_port_), | |
| 140 kCFRunLoopCommonModes); | |
| 141 IODeregisterForSystemPower(&power_notification_object_); | |
| 142 IOServiceClose(root_power_domain_); | |
| 143 IONotificationPortDestroy(power_notification_port_); | |
| 144 } | |
| 145 | |
| 146 CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_, | 123 CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_, |
| 147 kCFRunLoopCommonModes); | 124 kCFRunLoopCommonModes); |
| 148 CFRelease(enter_exit_observer_); | 125 CFRelease(enter_exit_observer_); |
| 149 | 126 |
| 150 CFRunLoopRemoveObserver(run_loop_, pre_source_observer_, | 127 CFRunLoopRemoveObserver(run_loop_, pre_source_observer_, |
| 151 kCFRunLoopCommonModes); | 128 kCFRunLoopCommonModes); |
| 152 CFRelease(pre_source_observer_); | 129 CFRelease(pre_source_observer_); |
| 153 | 130 |
| 154 CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, | 131 CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, |
| 155 kCFRunLoopCommonModes); | 132 kCFRunLoopCommonModes); |
| (...skipping 302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 --self->nesting_level_; | 435 --self->nesting_level_; |
| 459 break; | 436 break; |
| 460 | 437 |
| 461 default: | 438 default: |
| 462 break; | 439 break; |
| 463 } | 440 } |
| 464 | 441 |
| 465 self->EnterExitRunLoop(activity); | 442 self->EnterExitRunLoop(activity); |
| 466 } | 443 } |
| 467 | 444 |
| 468 // Called from the run loop. | |
| 469 // static | |
| 470 void MessagePumpCFRunLoopBase::PowerStateNotification(void* info, | |
| 471 io_service_t service, | |
| 472 uint32_t message_type, | |
| 473 void* message_argument) { | |
| 474 // CFRunLoopTimer (NSTimer) is scheduled in terms of CFAbsoluteTime, which | |
| 475 // measures the number of seconds since 2001-01-01 00:00:00.0 Z. It is | |
| 476 // implemented in terms of kernel ticks, as in mach_absolute_time. While an | |
| 477 // offset and scale factor can be applied to convert between the two time | |
| 478 // bases at any time after boot, the kernel clock stops while the system is | |
| 479 // asleep, altering the offset. (The offset will also change when the | |
| 480 // real-time clock is adjusted.) CFRunLoopTimers are not readjusted to take | |
| 481 // this into account when the system wakes up, so any timers that were | |
| 482 // pending while the system was asleep will be delayed by the sleep | |
| 483 // duration. | |
| 484 // | |
| 485 // The MessagePump interface assumes that scheduled delayed work will be | |
| 486 // performed at the time ScheduleDelayedWork was asked to perform it. The | |
| 487 // delay caused by the CFRunLoopTimer not firing at the appropriate time | |
| 488 // results in a stall of queued delayed work when the system wakes up. | |
| 489 // With this limitation, scheduled work would not be performed until | |
| 490 // (system wake time + scheduled work time - system sleep time), while it | |
| 491 // would be expected to be performed at (scheduled work time). | |
| 492 // | |
| 493 // To work around this problem, when the system wakes up from sleep, if a | |
| 494 // delayed work timer is pending, it is rescheduled to fire at the original | |
| 495 // time that it was scheduled to fire. | |
| 496 // | |
| 497 // This mechanism is not resilient if the real-time clock does not maintain | |
| 498 // stable time while the system is sleeping, but it matches the behavior of | |
| 499 // the various other MessagePump implementations, and MessageLoop seems to | |
| 500 // be limited in the same way. | |
| 501 // | |
| 502 // References | |
| 503 // - Chris Kane, "NSTimer and deep sleep," cocoa-dev@lists.apple.com, | |
| 504 // http://lists.apple.com/archives/Cocoa-dev/2002/May/msg01547.html | |
| 505 // - Apple Technical Q&A QA1340, "Registering and unregistering for sleep | |
| 506 // and wake notifications," | |
| 507 // http://developer.apple.com/mac/library/qa/qa2004/qa1340.html | |
| 508 // - Core Foundation source code, CF-550/CFRunLoop.c and CF-550/CFDate.c, | |
| 509 // http://www.opensource.apple.com/ | |
| 510 | |
| 511 MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); | |
| 512 | |
| 513 switch (message_type) { | |
| 514 case kIOMessageSystemWillPowerOn: | |
| 515 if (self->delayed_work_fire_time_ != kCFTimeIntervalMax) { | |
| 516 CFRunLoopTimerSetNextFireDate(self->delayed_work_timer_, | |
| 517 self->delayed_work_fire_time_); | |
| 518 } | |
| 519 break; | |
| 520 | |
| 521 case kIOMessageSystemWillSleep: | |
| 522 case kIOMessageCanSystemSleep: | |
| 523 // The system will wait for 30 seconds before entering sleep if neither | |
| 524 // IOAllowPowerChange nor IOCancelPowerChange are called. That would be | |
| 525 // pretty antisocial. | |
| 526 IOAllowPowerChange(self->root_power_domain_, | |
| 527 reinterpret_cast<long>(message_argument)); | |
| 528 break; | |
| 529 | |
| 530 default: | |
| 531 break; | |
| 532 } | |
| 533 } | |
| 534 | |
| 535 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default | 445 // Called by MessagePumpCFRunLoopBase::EnterExitRunLoop. The default |
| 536 // implementation is a no-op. | 446 // implementation is a no-op. |
| 537 void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) { | 447 void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) { |
| 538 } | 448 } |
| 539 | 449 |
| 540 // Base version returns a standard NSAutoreleasePool. | 450 // Base version returns a standard NSAutoreleasePool. |
| 541 NSAutoreleasePool* MessagePumpCFRunLoopBase::CreateAutoreleasePool() { | 451 NSAutoreleasePool* MessagePumpCFRunLoopBase::CreateAutoreleasePool() { |
| 542 return [[NSAutoreleasePool alloc] init]; | 452 return [[NSAutoreleasePool alloc] init]; |
| 543 } | 453 } |
| 544 | 454 |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 724 // static | 634 // static |
| 725 MessagePump* MessagePumpMac::Create() { | 635 MessagePump* MessagePumpMac::Create() { |
| 726 if ([NSThread isMainThread]) { | 636 if ([NSThread isMainThread]) { |
| 727 return new MessagePumpNSApplication; | 637 return new MessagePumpNSApplication; |
| 728 } | 638 } |
| 729 | 639 |
| 730 return new MessagePumpNSRunLoop; | 640 return new MessagePumpNSRunLoop; |
| 731 } | 641 } |
| 732 | 642 |
| 733 } // namespace base | 643 } // namespace base |
| OLD | NEW |