Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1443)

Unified Diff: base/message_pump_mac.mm

Issue 300044: Change the strategy used to attempt nesting-deferred work to account equally... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/message_pump_mac.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/message_pump_mac.mm
===================================================================
--- base/message_pump_mac.mm (revision 29677)
+++ base/message_pump_mac.mm (working copy)
@@ -22,13 +22,13 @@
// Must be called on the run loop thread.
MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
- : nesting_level_(0),
+ : delegate_(NULL),
+ nesting_level_(0),
run_nesting_level_(0),
- delegate_(NULL),
+ deepest_nesting_level_(0),
delegateless_work_(false),
delegateless_delayed_work_(false),
- delegateless_idle_work_(false)
- {
+ delegateless_idle_work_(false) {
run_loop_ = CFRunLoopGetCurrent();
CFRetain(run_loop_);
@@ -134,28 +134,26 @@
Delegate* last_delegate = delegate_;
delegate_ = delegate;
- // If any work showed up but could not be dispatched for want of a delegate,
- // set it up for dispatch again now that a delegate is available.
- if (delegateless_work_) {
- CFRunLoopSourceSignal(work_source_);
- delegateless_work_ = false;
+ if (delegate) {
+ // If any work showed up but could not be dispatched for want of a
+ // delegate, set it up for dispatch again now that a delegate is
+ // available.
+ if (delegateless_work_) {
+ CFRunLoopSourceSignal(work_source_);
+ delegateless_work_ = false;
+ }
+ if (delegateless_delayed_work_) {
+ CFRunLoopSourceSignal(delayed_work_source_);
+ delegateless_delayed_work_ = false;
+ }
+ if (delegateless_idle_work_) {
+ CFRunLoopSourceSignal(idle_work_source_);
+ delegateless_idle_work_ = false;
+ }
}
- if (delegateless_delayed_work_) {
- CFRunLoopSourceSignal(delayed_work_source_);
- delegateless_delayed_work_ = false;
- }
- if (delegateless_idle_work_) {
- CFRunLoopSourceSignal(idle_work_source_);
- delegateless_idle_work_ = false;
- }
DoRun(delegate);
- // If this was an inner Run invocation, arrange to run nesting-deferred work
- // when the stack has unwound to an outer invocation.
- if (nesting_level_)
- CFRunLoopSourceSignal(nesting_deferred_work_source_);
-
// Restore the previous state of the object.
delegate_ = last_delegate;
run_nesting_level_ = last_run_nesting_level;
@@ -220,9 +218,11 @@
return false;
}
- // If we're on the main event loop, the NSApp runloop won't clean up the
- // autorelease pool until there is a UI event, so use a local one for any
- // autoreleased objects to ensure they go away sooner.
+ // The NSApplication-based run loop only drains the autorelease pool at each
+ // UI event (NSEvent). The autorelease pool is not drained for each
+ // CFRunLoopSource target that's run. Use a local pool for any autoreleased
+ // objects to ensure they're released promptly even in the absence of UI
+ // events.
ScopedNSAutoreleasePool autorelease_pool;
// Call DoWork once, and if something was done, arrange to come back here
@@ -252,9 +252,11 @@
return false;
}
- // If we're on the main event loop, the NSApp runloop won't clean up the
- // autorelease pool until there is a UI event, so use a local one for any
- // autoreleased objects to ensure they go away sooner.
+ // The NSApplication-based run loop only drains the autorelease pool at each
+ // UI event (NSEvent). The autorelease pool is not drained for each
+ // CFRunLoopSource target that's run. Use a local pool for any autoreleased
+ // objects to ensure they're released promptly even in the absence of UI
+ // events.
ScopedNSAutoreleasePool autorelease_pool;
Time next_time;
@@ -294,9 +296,11 @@
return false;
}
- // If we're on the main event loop, the NSApp runloop won't clean up the
- // autorelease pool until there is a UI event, so use a local one for any
- // autoreleased objects to ensure they go away sooner.
+ // The NSApplication-based run loop only drains the autorelease pool at each
+ // UI event (NSEvent). The autorelease pool is not drained for each
+ // CFRunLoopSource target that's run. Use a local pool for any autoreleased
+ // objects to ensure they're released promptly even in the absence of UI
+ // events.
ScopedNSAutoreleasePool autorelease_pool;
// Call DoIdleWork once, and if something was done, arrange to come back here
@@ -347,6 +351,20 @@
return true;
}
+// Called before the run loop goes to sleep or exits.
+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.
+ if (deepest_nesting_level_ > nesting_level_) {
+ deepest_nesting_level_ = nesting_level_;
+ CFRunLoopSourceSignal(nesting_deferred_work_source_);
+ }
+}
+
// Called from the run loop.
// static
void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
@@ -356,6 +374,12 @@
// Attempt to do some idle work before going to sleep.
self->RunIdleWork();
+
+ // The run loop is about to go to sleep. If any of the work done since it
+ // started or woke up resulted in a nested run loop running,
+ // nesting-deferred work may have accumulated. Schedule it for processing
+ // if appropriate.
+ self->MaybeScheduleNestingDeferredWork();
}
// Called from the run loop.
@@ -368,24 +392,29 @@
switch (activity) {
case kCFRunLoopEntry:
++self->nesting_level_;
+ if (self->nesting_level_ > self->deepest_nesting_level_) {
+ self->deepest_nesting_level_ = self->nesting_level_;
+ }
break;
case kCFRunLoopExit:
- // After decrementing self->nesting_level_, it will be one less than
- // self->run_nesting_level_ if the loop that is now exiting was directly
- // started by a DoRun call.
+ // Not all run loops go to sleep. If a run loop is stopped before it
+ // goes to sleep due to a CFRunLoopStop call, or if the timeout passed
+ // to CFRunLoopRunInMode expires, the run loop may proceed directly from
+ // handling sources to exiting without any sleep. This most commonly
+ // occurs when CFRunLoopRunInMode is passed a timeout of 0, causing it
+ // to make a single pass through the loop and exit without sleep. Some
+ // native loops use CFRunLoop in this way. Because PreWaitObserver will
+ // not be called in these case, MaybeScheduleNestingDeferredWork needs
+ // to be called here, as the run loop exits.
+ //
+ // MaybeScheduleNestingDeferredWork consults self->nesting_level_
+ // to determine whether to schedule nesting-deferred work. It expects
+ // the nesting level to be set to the depth of the loop that is going
+ // to sleep or exiting. It must be called before decrementing the
+ // value so that the value still corresponds to the level of the exiting
+ // loop.
+ self->MaybeScheduleNestingDeferredWork();
--self->nesting_level_;
-
- if (self->nesting_level_ >= self->run_nesting_level_ &&
- self->nesting_level_) {
- // It's possible that some work was not performed because it was
- // inappropriate to do within a nested loop. When leaving any inner
- // loop not directly supervised by a DoRun call, such as nested native
- // loops, signal the nesting-deferred work source to ensure that such
- // work be afforded an opportunity to be processed if appropriate.
- // This is not done for loops being run directly by Run/DoRun because
- // it can be done directly as Run exits.
- CFRunLoopSourceSignal(self->nesting_deferred_work_source_);
- }
break;
default:
break;
@@ -420,15 +449,15 @@
// Must be called on the run loop thread.
void MessagePumpCFRunLoop::Quit() {
// Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
- if (nesting_level_ == run_nesting_level_) {
+ if (nesting_level() == run_nesting_level()) {
// This object is running the innermost loop, just stop it.
- CFRunLoopStop(run_loop_);
+ CFRunLoopStop(run_loop());
} else {
// There's another loop running inside the loop managed by this object.
- // In other words, someone else called CFRunLoopRun on the same thread,
- // higher on the stack than our highest Run call. Don't preempt other
- // run loops, just mark the object to quit our innermost run loop as soon
- // as the other inner loops we don't manage are done.
+ // In other words, someone else called CFRunLoopRunInMode on the same
+ // thread, deeper on the stack than the deepest Run call. Don't preempt
+ // other run loops, just mark this object to quit the innermost Run as
+ // soon as the other inner loops not managed by Run are done.
quit_pending_ = true;
}
}
@@ -436,13 +465,13 @@
// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
if (activity == kCFRunLoopExit &&
- nesting_level_ == run_nesting_level_ &&
+ nesting_level() == run_nesting_level() &&
quit_pending_) {
// Quit was called while loops other than those managed by this object
// were running further inside a run loop managed by this object. Now
// that all unmanaged inner run loops are gone, stop the loop running
// just inside Run.
- CFRunLoopStop(run_loop_);
+ CFRunLoopStop(run_loop());
quit_pending_ = false;
}
}
@@ -454,11 +483,11 @@
quit_source_ = CFRunLoopSourceCreate(NULL, // allocator
0, // priority
&source_context);
- CFRunLoopAddSource(run_loop_, quit_source_, kCFRunLoopCommonModes);
+ CFRunLoopAddSource(run_loop(), quit_source_, kCFRunLoopCommonModes);
}
MessagePumpNSRunLoop::~MessagePumpNSRunLoop() {
- CFRunLoopRemoveSource(run_loop_, quit_source_, kCFRunLoopCommonModes);
+ CFRunLoopRemoveSource(run_loop(), quit_source_, kCFRunLoopCommonModes);
CFRelease(quit_source_);
}
@@ -475,7 +504,7 @@
void MessagePumpNSRunLoop::Quit() {
keep_running_ = false;
CFRunLoopSourceSignal(quit_source_);
- CFRunLoopWakeUp(run_loop_);
+ CFRunLoopWakeUp(run_loop());
}
MessagePumpNSApplication::MessagePumpNSApplication()
« no previous file with comments | « base/message_pump_mac.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698