summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authormark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-22 16:18:03 +0000
committermark@chromium.org <mark@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2009-10-22 16:18:03 +0000
commitaf87d5b0f0bd21e4681ea9e1798bd9fb5b9ee83f (patch)
tree5fd9558628917f58b8c0ac58fcd0482deda32234 /base
parent3e5bf103d2b7199b00610ce6ef1411be91be8a2e (diff)
downloadchromium_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.h13
-rw-r--r--base/message_pump_mac.mm62
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) {