diff options
author | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-22 16:18:03 +0000 |
---|---|---|
committer | mark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-22 16:18:03 +0000 |
commit | af87d5b0f0bd21e4681ea9e1798bd9fb5b9ee83f (patch) | |
tree | 5fd9558628917f58b8c0ac58fcd0482deda32234 /base | |
parent | 3e5bf103d2b7199b00610ce6ef1411be91be8a2e (diff) | |
download | chromium_src-af87d5b0f0bd21e4681ea9e1798bd9fb5b9ee83f.zip chromium_src-af87d5b0f0bd21e4681ea9e1798bd9fb5b9ee83f.tar.gz chromium_src-af87d5b0f0bd21e4681ea9e1798bd9fb5b9ee83f.tar.bz2 |
Call MaybeScheduleNestingDeferredWork at the top of each loop iteration from
a kCFRunLoopBeforeSources observer. A busy loop that's driven with a nonzero
duration might not go to sleep or exit soon after a nested loop exits, so
calling MaybeScheduleNestingDeferredWork from the existing
kCFRunLoopBeforeWaiting and kCFRunLoopExit observers may not be sufficient to
guarantee processing of nesting-deferred work in all situations.
BUG=24968
TEST=All of the test cases listed in the commit message from r29749.
No new test cases; this change addresses a purely theoretical case.
Review URL: http://codereview.chromium.org/315010
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@29775 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/message_pump_mac.h | 13 | ||||
-rw-r--r-- | base/message_pump_mac.mm | 62 |
2 files changed, 58 insertions, 17 deletions
diff --git a/base/message_pump_mac.h b/base/message_pump_mac.h index 9c24d8b..381acbf 100644 --- a/base/message_pump_mac.h +++ b/base/message_pump_mac.h @@ -97,9 +97,10 @@ class MessagePumpCFRunLoopBase : public MessagePump { bool RunNestingDeferredWork(); // Schedules possible nesting-deferred work to be processed before the run - // loop goes to sleep or exits. If this function detects that a nested loop - // had run since the previous attempt to schedule nesting-deferred work, it - // will schedule a call to RunNestingDeferredWorkSource. + // loop goes to sleep, exits, or begins processing sources at the top of its + // loop. If this function detects that a nested loop had run since the + // previous attempt to schedule nesting-deferred work, it will schedule a + // call to RunNestingDeferredWorkSource. void MaybeScheduleNestingDeferredWork(); // Observer callback responsible for performing idle-priority work, before @@ -107,6 +108,11 @@ class MessagePumpCFRunLoopBase : public MessagePump { static void PreWaitObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void* info); + // Observer callback called before the run loop processes any sources. + // Associated with pre_source_observer_. + static void PreSourceObserver(CFRunLoopObserverRef observer, + CFRunLoopActivity activity, void* info); + // Observer callback called when the run loop starts and stops, at the // beginning and end of calls to CFRunLoopRun. This is used to maintain // nesting_level_. Associated with enter_exit_observer_. @@ -129,6 +135,7 @@ class MessagePumpCFRunLoopBase : public MessagePump { CFRunLoopSourceRef idle_work_source_; CFRunLoopSourceRef nesting_deferred_work_source_; CFRunLoopObserverRef pre_wait_observer_; + CFRunLoopObserverRef pre_source_observer_; CFRunLoopObserverRef enter_exit_observer_; // (weak) Delegate passed as an argument to the innermost Run call. diff --git a/base/message_pump_mac.mm b/base/message_pump_mac.mm index 3c448a0..9af77fa 100644 --- a/base/message_pump_mac.mm +++ b/base/message_pump_mac.mm @@ -6,7 +6,8 @@ #import <AppKit/AppKit.h> #import <Foundation/Foundation.h> -#include <float.h> + +#include <limits> #include "base/scoped_nsautorelease_pool.h" #include "base/time.h" @@ -16,6 +17,9 @@ namespace { void NoOp(void* info) { } +const CFTimeInterval kCFTimeIntervalMax = + std::numeric_limits<CFTimeInterval>::max(); + } // namespace namespace base { @@ -37,11 +41,11 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase() // as needed when ScheduleDelayedWork is called. CFRunLoopTimerContext timer_context = CFRunLoopTimerContext(); timer_context.info = this; - delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator - DBL_MAX, // fire time - DBL_MAX, // interval - 0, // flags (ignored) - 0, // priority (ignored) + delayed_work_timer_ = CFRunLoopTimerCreate(NULL, // allocator + kCFTimeIntervalMax, // fire time + kCFTimeIntervalMax, // interval + 0, // flags + 0, // priority RunDelayedWorkTimer, &timer_context); CFRunLoopAddTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes); @@ -83,6 +87,14 @@ MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase() &observer_context); CFRunLoopAddObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes); + pre_source_observer_ = CFRunLoopObserverCreate(NULL, // allocator + kCFRunLoopBeforeSources, + true, // repeat + 0, // priority + PreSourceObserver, + &observer_context); + CFRunLoopAddObserver(run_loop_, pre_source_observer_, kCFRunLoopCommonModes); + enter_exit_observer_ = CFRunLoopObserverCreate(NULL, // allocator kCFRunLoopEntry | kCFRunLoopExit, @@ -101,6 +113,10 @@ MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() { kCFRunLoopCommonModes); CFRelease(enter_exit_observer_); + CFRunLoopRemoveObserver(run_loop_, pre_source_observer_, + kCFRunLoopCommonModes); + CFRelease(pre_source_observer_); + CFRunLoopRemoveObserver(run_loop_, pre_wait_observer_, kCFRunLoopCommonModes); CFRelease(pre_wait_observer_); @@ -351,14 +367,14 @@ bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() { return true; } -// Called before the run loop goes to sleep or exits. +// Called before the run loop goes to sleep or exits, or processes sources. void MessagePumpCFRunLoopBase::MaybeScheduleNestingDeferredWork() { // deepest_nesting_level_ is set as run loops are entered. If the deepest - // level encountered is deeper than the current level (about to sleep or - // exit), a nested loop (relative to the current level) ran since the last - // time nesting-deferred work was scheduled. When that situation is - // encountered, schedule nesting-deferred work in case any work was deferred - // because nested work was disallowed. + // level encountered is deeper than the current level, a nested loop + // (relative to the current level) ran since the last time nesting-deferred + // work was scheduled. When that situation is encountered, schedule + // nesting-deferred work in case any work was deferred because nested work + // was disallowed. if (deepest_nesting_level_ > nesting_level_) { deepest_nesting_level_ = nesting_level_; CFRunLoopSourceSignal(nesting_deferred_work_source_); @@ -384,6 +400,21 @@ void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer, // Called from the run loop. // static +void MessagePumpCFRunLoopBase::PreSourceObserver(CFRunLoopObserverRef observer, + CFRunLoopActivity activity, + void* info) { + MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info); + + // The run loop has reached the top of the loop and is about to begin + // processing sources. If the last iteration of the loop at this nesting + // level did not sleep or exit, nesting-deferred work may have accumulated + // if a nested loop ran. Schedule nesting-deferred work for processing if + // appropriate. + self->MaybeScheduleNestingDeferredWork(); +} + +// Called from the run loop. +// static void MessagePumpCFRunLoopBase::EnterExitObserver(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void* info) { @@ -442,7 +473,9 @@ void MessagePumpCFRunLoop::DoRun(Delegate* delegate) { int result; do { ScopedNSAutoreleasePool autorelease_pool; - result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, DBL_MAX, false); + result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, + kCFTimeIntervalMax, + false); } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished); } @@ -523,10 +556,11 @@ void MessagePumpNSApplication::DoRun(Delegate* delegate) { [NSApp run]; } else { running_own_loop_ = true; + NSDate* distant_future = [NSDate distantFuture]; while (keep_running_) { ScopedNSAutoreleasePool autorelease_pool; NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantFuture] + untilDate:distant_future inMode:NSDefaultRunLoopMode dequeue:YES]; if (event) { |