Update Mac OS X message pump code for child processes. b=552878 rs=cjones
authorJosh Aas <joshmoz@gmail.com>
Wed, 17 Mar 2010 20:10:42 -0400
changeset 39550 5750e45806ba57a799ee81e2274c9438fe16b932
parent 39549 fd765b970adc49ec6a79c96c20e1fa0d5daadfcf
child 39551 36e430e9901a44bf56bda9d6deb1e8aa7e8b8671
push id12260
push userjosh@mozilla.com
push dateThu, 18 Mar 2010 00:11:09 +0000
treeherdermozilla-central@5750e45806ba [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscjones
bugs552878
milestone1.9.3a4pre
Update Mac OS X message pump code for child processes. b=552878 rs=cjones
ipc/chromium/Makefile.in
ipc/chromium/src/base/chrome_application_mac.h
ipc/chromium/src/base/chrome_application_mac.mm
ipc/chromium/src/base/message_pump_mac.h
ipc/chromium/src/base/message_pump_mac.mm
ipc/chromium/src/chrome/common/main_function_params.h
--- a/ipc/chromium/Makefile.in
+++ b/ipc/chromium/Makefile.in
@@ -217,16 +217,17 @@ CMMSRCS += \
   platform_thread_mac.mm \
   process_util_mac.mm \
   scoped_nsautorelease_pool.mm \
   sys_string_conversions_mac.mm \
   worker_pool_mac.mm \
   chrome_paths_mac.mm \
   mach_ipc_mac.mm \
   platform_util_mac.mm \
+  chrome_application_mac.mm \
   $(NULL)
 
 CPPSRCS += \
   data_pack.cc \
   debug_util_mac.cc \
   hmac_mac.cc \
   idle_timer.cc \
   sys_info_mac.cc \
new file mode 100644
--- /dev/null
+++ b/ipc/chromium/src/base/chrome_application_mac.h
@@ -0,0 +1,60 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_CHROME_APPLICATION_MAC_H_
+#define BASE_CHROME_APPLICATION_MAC_H_
+
+#import <AppKit/AppKit.h>
+
+#include "base/basictypes.h"
+#include "base/scoped_nsobject.h"
+
+// Event hooks must implement this protocol.
+@protocol CrApplicationEventHookProtocol
+- (void)hookForEvent:(NSEvent*)theEvent;
+@end
+
+
+@interface CrApplication : NSApplication {
+ @private
+  BOOL handlingSendEvent_;
+ // Array of objects implementing the CrApplicationEventHookProtocol
+  scoped_nsobject<NSMutableArray> eventHooks_;
+}
+@property(readonly,
+          getter=isHandlingSendEvent,
+          nonatomic) BOOL handlingSendEvent;
+
+// Add or remove an event hook to be called for every sendEvent:
+// that the application receives.  These handlers are called before
+// the normal [NSApplication sendEvent:] call is made.
+
+// This is not a good alternative to a nested event loop.  It should
+// be used only when normal event logic and notification breaks down
+// (e.g. when clicking outside a canBecomeKey:NO window to "switch
+// context" out of it).
+- (void)addEventHook:(id<CrApplicationEventHookProtocol>)hook;
+- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)hook;
+
++ (NSApplication*)sharedApplication;
+@end
+
+namespace chrome_application_mac {
+
+// Controls the state of |handlingSendEvent_| in the event loop so that it is
+// reset properly.
+class ScopedSendingEvent {
+ public:
+  ScopedSendingEvent();
+  ~ScopedSendingEvent();
+
+ private:
+  CrApplication* app_;
+  BOOL handling_;
+  DISALLOW_COPY_AND_ASSIGN(ScopedSendingEvent);
+};
+
+}  // chrome_application_mac
+
+#endif  // BASE_CHROME_APPLICATION_MAC_H_
new file mode 100644
--- /dev/null
+++ b/ipc/chromium/src/base/chrome_application_mac.mm
@@ -0,0 +1,68 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "chrome_application_mac.h"
+
+#include "base/logging.h"
+
+@interface CrApplication ()
+@property(readwrite,
+          getter=isHandlingSendEvent,
+          nonatomic) BOOL handlingSendEvent;
+@end
+
+@implementation CrApplication
+@synthesize handlingSendEvent = handlingSendEvent_;
+
+// Initialize NSApplication using the custom subclass.  Check whether NSApp
+// was already initialized using another class, because that would break
+// some things.
++ (NSApplication*)sharedApplication {
+  NSApplication* app = [super sharedApplication];
+  if (![NSApp isKindOfClass:self]) {
+    LOG(ERROR) << "NSApp should be of type " << [[self className] UTF8String]
+               << ", not " << [[NSApp className] UTF8String];
+    DCHECK(false) << "NSApp is of wrong type";
+  }
+  return app;
+}
+
+- (id)init {
+  if ((self = [super init])) {
+    eventHooks_.reset([[NSMutableArray alloc] init]);
+  }
+  return self;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+  chrome_application_mac::ScopedSendingEvent sendingEventScoper;
+  for (id<CrApplicationEventHookProtocol> handler in eventHooks_.get()) {
+    [handler hookForEvent:event];
+  }
+  [super sendEvent:event];
+}
+
+- (void)addEventHook:(id<CrApplicationEventHookProtocol>)handler {
+  [eventHooks_ addObject:handler];
+}
+
+- (void)removeEventHook:(id<CrApplicationEventHookProtocol>)handler {
+  [eventHooks_ removeObject:handler];
+}
+
+@end
+
+namespace chrome_application_mac {
+
+ScopedSendingEvent::ScopedSendingEvent()
+    : app_(static_cast<CrApplication*>([CrApplication sharedApplication])),
+      handling_([app_ isHandlingSendEvent]) {
+  [app_ setHandlingSendEvent:YES];
+}
+
+ScopedSendingEvent::~ScopedSendingEvent() {
+  [app_ setHandlingSendEvent:handling_];
+}
+
+}  // namespace chrome_application_mac
--- a/ipc/chromium/src/base/message_pump_mac.h
+++ b/ipc/chromium/src/base/message_pump_mac.h
@@ -28,100 +28,190 @@
 // called on.
 
 #ifndef BASE_MESSAGE_PUMP_MAC_H_
 #define BASE_MESSAGE_PUMP_MAC_H_
 
 #include "base/message_pump.h"
 
 #include <CoreFoundation/CoreFoundation.h>
+#include <IOKit/IOKitLib.h>
+
+#if defined(__OBJC__)
+@class NSAutoreleasePool;
+#else  // defined(__OBJC__)
+class NSAutoreleasePool;
+#endif  // defined(__OBJC__)
 
 namespace base {
 
 class Time;
 
 class MessagePumpCFRunLoopBase : public MessagePump {
+  // Needs access to CreateAutoreleasePool.
+  friend class MessagePumpScopedAutoreleasePool;
  public:
   MessagePumpCFRunLoopBase();
   virtual ~MessagePumpCFRunLoopBase();
 
   // Subclasses should implement the work they need to do in MessagePump::Run
   // in the DoRun method.  MessagePumpCFRunLoopBase::Run calls DoRun directly.
   // This arrangement is used because MessagePumpCFRunLoopBase needs to set
   // up and tear down things before and after the "meat" of DoRun.
   virtual void Run(Delegate* delegate);
   virtual void DoRun(Delegate* delegate) = 0;
 
   virtual void ScheduleWork();
   virtual void ScheduleDelayedWork(const Time& delayed_work_time);
 
  protected:
-  // The thread's run loop.
-  CFRunLoopRef run_loop_;
+  // Accessors for private data members to be used by subclasses.
+  CFRunLoopRef run_loop() const { return run_loop_; }
+  int nesting_level() const { return nesting_level_; }
+  int run_nesting_level() const { return run_nesting_level_; }
+
+  // Return an autorelease pool to wrap around any work being performed.
+  // In some cases, CreateAutoreleasePool may return nil intentionally to
+  // preventing an autorelease pool from being created, allowing any
+  // objects autoreleased by work to fall into the current autorelease pool.
+  virtual NSAutoreleasePool* CreateAutoreleasePool();
 
  private:
   // Timer callback scheduled by ScheduleDelayedWork.  This does not do any
   // work, but it signals delayed_work_source_ so that delayed work can be
   // performed within the appropriate priority constraints.
   static void RunDelayedWorkTimer(CFRunLoopTimerRef timer, void* info);
 
   // Perform highest-priority work.  This is associated with work_source_
-  // signalled by ScheduleWork.
-  static void RunWork(void* info);
+  // signalled by ScheduleWork.  The static method calls the instance method;
+  // the instance method returns true if work was done.
+  static void RunWorkSource(void* info);
+  bool RunWork();
 
   // Perform delayed-priority work.  This is associated with
   // delayed_work_source_ signalled by RunDelayedWorkTimer, and is responsible
-  // for calling ScheduleDelayedWork again if appropriate.
-  static void RunDelayedWork(void* info);
+  // for calling ScheduleDelayedWork again if appropriate.  The static method
+  // calls the instance method; the instance method returns true if more
+  // delayed work is available.
+  static void RunDelayedWorkSource(void* info);
+  bool RunDelayedWork();
+
+  // Perform idle-priority work.  This is normally called by PreWaitObserver,
+  // but is also associated with idle_work_source_.  When this function
+  // actually does perform idle work, it will resignal that source.  The
+  // static method calls the instance method; the instance method returns
+  // true if idle work was done.
+  static void RunIdleWorkSource(void* info);
+  bool RunIdleWork();
+
+  // Perform work that may have been deferred because it was not runnable
+  // within a nested run loop.  This is associated with
+  // nesting_deferred_work_source_ and is signalled by
+  // MaybeScheduleNestingDeferredWork when returning from a nested loop,
+  // so that an outer loop will be able to perform the necessary tasks if it
+  // permits nestable tasks.
+  static void RunNestingDeferredWorkSource(void* info);
+  bool RunNestingDeferredWork();
+
+  // Schedules possible nesting-deferred work to be processed before the run
+  // 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
   // the run loop goes to sleep.  Associated with idle_work_observer_.
-  static void RunIdleWork(CFRunLoopObserverRef observer,
-                          CFRunLoopActivity activity, void* info);
+  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_.
+  static void EnterExitObserver(CFRunLoopObserverRef observer,
+                                CFRunLoopActivity activity, void* info);
 
-  // The timer, sources, and observer are described above alongside their
+  // Called by EnterExitObserver after performing maintenance on nesting_level_.
+  // This allows subclasses an opportunity to perform additional processing on
+  // the basis of run loops starting and stopping.
+  virtual void EnterExitRunLoop(CFRunLoopActivity activity);
+
+  // IOKit power state change notification callback, called when the system
+  // enters and leaves the sleep state.
+  static void PowerStateNotification(void* info, io_service_t service,
+                                     uint32_t message_type,
+                                     void* message_argument);
+
+  // The thread's run loop.
+  CFRunLoopRef run_loop_;
+
+  // The timer, sources, and observers are described above alongside their
   // callbacks.
   CFRunLoopTimerRef delayed_work_timer_;
   CFRunLoopSourceRef work_source_;
   CFRunLoopSourceRef delayed_work_source_;
-  CFRunLoopObserverRef idle_work_observer_;
+  CFRunLoopSourceRef idle_work_source_;
+  CFRunLoopSourceRef nesting_deferred_work_source_;
+  CFRunLoopObserverRef pre_wait_observer_;
+  CFRunLoopObserverRef pre_source_observer_;
+  CFRunLoopObserverRef enter_exit_observer_;
+
+  // Objects used for power state notification.  See PowerStateNotification.
+  io_connect_t root_power_domain_;
+  IONotificationPortRef power_notification_port_;
+  io_object_t power_notification_object_;
 
   // (weak) Delegate passed as an argument to the innermost Run call.
   Delegate* delegate_;
 
-  DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
-};
-
-class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
- public:
-  MessagePumpCFRunLoop();
-  virtual ~MessagePumpCFRunLoop();
-
-  virtual void DoRun(Delegate* delegate);
-  virtual void Quit();
-
- private:
-  // 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_ and to handle deferred loop quits.  Associated with
-  // enter_exit_observer_.
-  static void EnterExitRunLoop(CFRunLoopObserverRef observer,
-                               CFRunLoopActivity activity, void* info);
-
-  // Observer for EnterExitRunLoop.
-  CFRunLoopObserverRef enter_exit_observer_;
+  // The time that delayed_work_timer_ is scheduled to fire.  This is tracked
+  // independently of CFRunLoopTimerGetNextFireDate(delayed_work_timer_)
+  // to be able to reset the timer properly after waking from system sleep.
+  // See PowerStateNotification.
+  CFAbsoluteTime delayed_work_fire_time_;
 
   // The recursion depth of the currently-executing CFRunLoopRun loop on the
   // run loop's thread.  0 if no run loops are running inside of whatever scope
   // the object was created in.
   int nesting_level_;
 
   // The recursion depth (calculated in the same way as nesting_level_) of the
   // innermost executing CFRunLoopRun loop started by a call to Run.
-  int innermost_quittable_;
+  int run_nesting_level_;
+
+  // The deepest (numerically highest) recursion depth encountered since the
+  // most recent attempt to run nesting-deferred work.
+  int deepest_nesting_level_;
+
+  // "Delegateless" work flags are set when work is ready to be performed but
+  // must wait until a delegate is available to process it.  This can happen
+  // when a MessagePumpCFRunLoopBase is instantiated and work arrives without
+  // any call to Run on the stack.  The Run method will check for delegateless
+  // work on entry and redispatch it as needed once a delegate is available.
+  bool delegateless_work_;
+  bool delegateless_delayed_work_;
+  bool delegateless_idle_work_;
+
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoopBase);
+};
+
+class MessagePumpCFRunLoop : public MessagePumpCFRunLoopBase {
+ public:
+  MessagePumpCFRunLoop();
+
+  virtual void DoRun(Delegate* delegate);
+  virtual void Quit();
+
+ private:
+  virtual void EnterExitRunLoop(CFRunLoopActivity activity);
 
   // True if Quit is called to stop the innermost MessagePump
   // (innermost_quittable_) but some other CFRunLoopRun loop (nesting_level_)
   // is running inside the MessagePump's innermost Run call.
   bool quit_pending_;
 
   DISALLOW_COPY_AND_ASSIGN(MessagePumpCFRunLoop);
 };
@@ -148,16 +238,20 @@ class MessagePumpNSRunLoop : public Mess
 
 class MessagePumpNSApplication : public MessagePumpCFRunLoopBase {
  public:
   MessagePumpNSApplication();
 
   virtual void DoRun(Delegate* delegate);
   virtual void Quit();
 
+ protected:
+  // Returns nil if NSApp is currently in the middle of calling -sendEvent.
+  virtual NSAutoreleasePool* CreateAutoreleasePool();
+
  private:
   // False after Quit is called.
   bool keep_running_;
 
   // True if DoRun is managing its own run loop as opposed to letting
   // -[NSApplication run] handle it.  The outermost run loop in the application
   // is managed by -[NSApplication run], inner run loops are handled by a loop
   // in DoRun.
--- a/ipc/chromium/src/base/message_pump_mac.mm
+++ b/ipc/chromium/src/base/message_pump_mac.mm
@@ -1,101 +1,225 @@
 // Copyright (c) 2008 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 #include "base/message_pump_mac.h"
 
 #import <AppKit/AppKit.h>
 #import <Foundation/Foundation.h>
-#include <float.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/pwr_mgt/IOPMLib.h>
 
-#include "base/scoped_nsautorelease_pool.h"
+#include <limits>
+
+#import "base/chrome_application_mac.h"
+#include "base/logging.h"
 #include "base/time.h"
 
 namespace {
 
 void NoOp(void* info) {
 }
 
+const CFTimeInterval kCFTimeIntervalMax =
+    std::numeric_limits<CFTimeInterval>::max();
+
 }  // namespace
 
 namespace base {
 
+// A scoper for autorelease pools created from message pump run loops.
+// Avoids dirtying up the ScopedNSAutoreleasePool interface for the rare
+// case where an autorelease pool needs to be passed in.
+class MessagePumpScopedAutoreleasePool {
+ public:
+  explicit MessagePumpScopedAutoreleasePool(MessagePumpCFRunLoopBase* pump) :
+      pool_(pump->CreateAutoreleasePool()) {
+  }
+   ~MessagePumpScopedAutoreleasePool() {
+    [pool_ drain];
+  }
+
+ private:
+  NSAutoreleasePool* pool_;
+  DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool);
+};
+
 // Must be called on the run loop thread.
 MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
-    : delegate_(NULL) {
+    : delegate_(NULL),
+      delayed_work_fire_time_(kCFTimeIntervalMax),
+      nesting_level_(0),
+      run_nesting_level_(0),
+      deepest_nesting_level_(0),
+      delegateless_work_(false),
+      delegateless_delayed_work_(false),
+      delegateless_idle_work_(false) {
   run_loop_ = CFRunLoopGetCurrent();
   CFRetain(run_loop_);
 
   // Set a repeating timer with a preposterous firing time and interval.  The
   // timer will effectively never fire as-is.  The firing time will be adjusted
   // 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);
 
   CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
   source_context.info = this;
-  source_context.perform = RunWork;
+  source_context.perform = RunWorkSource;
   work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
-                                       0,     // priority
+                                       1,     // priority
                                        &source_context);
   CFRunLoopAddSource(run_loop_, work_source_, kCFRunLoopCommonModes);
 
-  source_context.perform = RunDelayedWork;
+  source_context.perform = RunDelayedWorkSource;
   delayed_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
-                                               1,     // priority
+                                               2,     // priority
                                                &source_context);
   CFRunLoopAddSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
 
+  source_context.perform = RunIdleWorkSource;
+  idle_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                            3,     // priority
+                                            &source_context);
+  CFRunLoopAddSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
+
+  source_context.perform = RunNestingDeferredWorkSource;
+  nesting_deferred_work_source_ = CFRunLoopSourceCreate(NULL,  // allocator
+                                                        0,     // priority
+                                                        &source_context);
+  CFRunLoopAddSource(run_loop_, nesting_deferred_work_source_,
+                     kCFRunLoopCommonModes);
+
   CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
   observer_context.info = this;
-  idle_work_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
-                                                kCFRunLoopBeforeWaiting,
-                                                true,  // repeat
-                                                0,     // priority
-                                                RunIdleWork,
-                                                &observer_context);
-  CFRunLoopAddObserver(run_loop_, idle_work_observer_, kCFRunLoopCommonModes);
+  pre_wait_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
+                                               kCFRunLoopBeforeWaiting,
+                                               true,  // repeat
+                                               0,     // priority
+                                               PreWaitObserver,
+                                               &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,
+                                                 true,  // repeat
+                                                 0,     // priority
+                                                 EnterExitObserver,
+                                                 &observer_context);
+  CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
+
+  root_power_domain_ = IORegisterForSystemPower(this,
+                                                &power_notification_port_,
+                                                PowerStateNotification,
+                                                &power_notification_object_);
+  if (root_power_domain_ != MACH_PORT_NULL) {
+    CFRunLoopAddSource(
+        run_loop_,
+        IONotificationPortGetRunLoopSource(power_notification_port_),
+        kCFRunLoopCommonModes);
+  }
 }
 
-// Ideally called on the run loop thread.
+// Ideally called on the run loop thread.  If other run loops were running
+// lower on the run loop thread's stack when this object was created, the
+// same number of run loops must be running when this object is destroyed.
 MessagePumpCFRunLoopBase::~MessagePumpCFRunLoopBase() {
-  CFRunLoopRemoveObserver(run_loop_, idle_work_observer_,
+  if (root_power_domain_ != MACH_PORT_NULL) {
+    CFRunLoopRemoveSource(
+        run_loop_,
+        IONotificationPortGetRunLoopSource(power_notification_port_),
+        kCFRunLoopCommonModes);
+    IODeregisterForSystemPower(&power_notification_object_);
+    IOServiceClose(root_power_domain_);
+    IONotificationPortDestroy(power_notification_port_);
+  }
+
+  CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
                           kCFRunLoopCommonModes);
-  CFRelease(idle_work_observer_);
+  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_);
+
+  CFRunLoopRemoveSource(run_loop_, nesting_deferred_work_source_,
+                        kCFRunLoopCommonModes);
+  CFRelease(nesting_deferred_work_source_);
+
+  CFRunLoopRemoveSource(run_loop_, idle_work_source_, kCFRunLoopCommonModes);
+  CFRelease(idle_work_source_);
 
   CFRunLoopRemoveSource(run_loop_, delayed_work_source_, kCFRunLoopCommonModes);
   CFRelease(delayed_work_source_);
 
   CFRunLoopRemoveSource(run_loop_, work_source_, kCFRunLoopCommonModes);
   CFRelease(work_source_);
 
   CFRunLoopRemoveTimer(run_loop_, delayed_work_timer_, kCFRunLoopCommonModes);
   CFRelease(delayed_work_timer_);
 
   CFRelease(run_loop_);
 }
 
 // Must be called on the run loop thread.
 void MessagePumpCFRunLoopBase::Run(Delegate* delegate) {
+  // nesting_level_ will be incremented in EnterExitRunLoop, so set
+  // run_nesting_level_ accordingly.
+  int last_run_nesting_level = run_nesting_level_;
+  run_nesting_level_ = nesting_level_ + 1;
+
   Delegate* last_delegate = delegate_;
   delegate_ = delegate;
 
+  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;
+    }
+  }
+
   DoRun(delegate);
 
+  // Restore the previous state of the object.
   delegate_ = last_delegate;
+  run_nesting_level_ = last_run_nesting_level;
 }
 
 // May be called on any thread.
 void MessagePumpCFRunLoopBase::ScheduleWork() {
   CFRunLoopSourceSignal(work_source_);
   CFRunLoopWakeUp(run_loop_);
 }
 
@@ -111,242 +235,458 @@ void MessagePumpCFRunLoopBase::ScheduleD
   CFGregorianDate gregorian = {
     exploded.year,
     exploded.month,
     exploded.day_of_month,
     exploded.hour,
     exploded.minute,
     seconds
   };
-  CFAbsoluteTime fire_time = CFGregorianDateGetAbsoluteTime(gregorian, NULL);
+  delayed_work_fire_time_ = CFGregorianDateGetAbsoluteTime(gregorian, NULL);
 
-  CFRunLoopTimerSetNextFireDate(delayed_work_timer_, fire_time);
+  CFRunLoopTimerSetNextFireDate(delayed_work_timer_, delayed_work_fire_time_);
 }
 
 // Called from the run loop.
 // static
 void MessagePumpCFRunLoopBase::RunDelayedWorkTimer(CFRunLoopTimerRef timer,
                                                    void* info) {
-  MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  // The timer won't fire again until it's reset.
+  self->delayed_work_fire_time_ = kCFTimeIntervalMax;
 
   // CFRunLoopTimers fire outside of the priority scheme for CFRunLoopSources.
   // In order to establish the proper priority where delegate_->DoDelayedWork
   // can only be called if delegate_->DoWork returns false, the timer used
   // to schedule delayed work must signal a CFRunLoopSource set at a lower
   // priority than the one used for delegate_->DoWork.
   CFRunLoopSourceSignal(self->delayed_work_source_);
 }
 
 // Called from the run loop.
 // static
-void MessagePumpCFRunLoopBase::RunWork(void* info) {
-  MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+void MessagePumpCFRunLoopBase::RunWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunWork();
+}
 
-  // If we're on the main event loop, the NSApp runloop won't clean up the
-  // autoreleasepool until there is UI event, so use a local one for any
-  // autoreleased objects to ensure they go away sooner.
-  ScopedNSAutoreleasePool autorelease_pool;
+// Called by MessagePumpCFRunLoopBase::RunWorkSource.
+bool MessagePumpCFRunLoopBase::RunWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  Arrange to come back
+    // here when a delegate is available.
+    delegateless_work_ = true;
+    return false;
+  }
+
+  // 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 if the app is not currently handling a UI event to ensure they're
+  // released promptly even in the absence of UI events.
+  MessagePumpScopedAutoreleasePool autorelease_pool(this);
 
   // Call DoWork once, and if something was done, arrange to come back here
   // again as long as the loop is still running.
-  if (self->delegate_->DoWork()) {
-    CFRunLoopSourceSignal(self->work_source_);
+  bool did_work = delegate_->DoWork();
+  if (did_work) {
+    CFRunLoopSourceSignal(work_source_);
+  }
+
+  return did_work;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunDelayedWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunDelayedWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunDelayedWorkSource.
+bool MessagePumpCFRunLoopBase::RunDelayedWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  Arrange to come back
+    // here when a delegate is available.
+    delegateless_delayed_work_ = true;
+    return false;
   }
+
+  // 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 if the app is not currently handling a UI event to ensure they're
+  // released promptly even in the absence of UI events.
+  MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+  Time next_time;
+  delegate_->DoDelayedWork(&next_time);
+
+  bool more_work = !next_time.is_null();
+  if (more_work) {
+    TimeDelta delay = next_time - Time::Now();
+    if (delay > TimeDelta()) {
+      // There's more delayed work to be done in the future.
+      ScheduleDelayedWork(next_time);
+    } else {
+      // There's more delayed work to be done, and its time is in the past.
+      // Arrange to come back here directly as long as the loop is still
+      // running.
+      CFRunLoopSourceSignal(delayed_work_source_);
+    }
+  }
+
+  return more_work;
 }
 
 // Called from the run loop.
 // static
-void MessagePumpCFRunLoopBase::RunDelayedWork(void* info) {
-  MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+void MessagePumpCFRunLoopBase::RunIdleWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunIdleWork();
+}
+
+// Called by MessagePumpCFRunLoopBase::RunIdleWorkSource.
+bool MessagePumpCFRunLoopBase::RunIdleWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  Arrange to come back
+    // here when a delegate is available.
+    delegateless_idle_work_ = true;
+    return false;
+  }
 
-  // If we're on the main event loop, the NSApp runloop won't clean up the
-  // autoreleasepool until there is UI event, so use a local one for any
-  // autoreleased objects to ensure they go away sooner.
-  ScopedNSAutoreleasePool autorelease_pool;
+  // 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 if the app is not currently handling a UI event to ensure they're
+  // released promptly even in the absence of UI events.
+  MessagePumpScopedAutoreleasePool autorelease_pool(this);
+
+  // Call DoIdleWork once, and if something was done, arrange to come back here
+  // again as long as the loop is still running.
+  bool did_work = delegate_->DoIdleWork();
+  if (did_work) {
+    CFRunLoopSourceSignal(idle_work_source_);
+  }
+
+  return did_work;
+}
+
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource(void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+  self->RunNestingDeferredWork();
+}
 
-  Time next_time;
-  self->delegate_->DoDelayedWork(&next_time);
-  if (!next_time.is_null()) {
-    TimeDelta delay = next_time - Time::Now();
-    if (delay > TimeDelta()) {
-      // There's more delayed work to be done in the future.
-      self->ScheduleDelayedWork(next_time);
+// Called by MessagePumpCFRunLoopBase::RunNestingDeferredWorkSource.
+bool MessagePumpCFRunLoopBase::RunNestingDeferredWork() {
+  if (!delegate_) {
+    // This point can be reached with a NULL delegate_ if Run is not on the
+    // stack but foreign code is spinning the CFRunLoop.  There's no sense in
+    // attempting to do any work or signalling the work sources because
+    // without a delegate, work is not possible.
+    return false;
+  }
+
+  // Immediately try work in priority order.
+  if (!RunWork()) {
+    if (!RunDelayedWork()) {
+      if (!RunIdleWork()) {
+        return false;
+      }
     } else {
-      // There's more delayed work to be done, and its time is in the past.
-      // Arrange to come back here directly as long as the loop is still
-      // running.
-      CFRunLoopSourceSignal(self->delayed_work_source_);
+      // There was no work, and delayed work was done.  Arrange for the loop
+      // to try non-nestable idle work on a subsequent pass.
+      CFRunLoopSourceSignal(idle_work_source_);
     }
+  } else {
+    // Work was done.  Arrange for the loop to try non-nestable delayed and
+    // idle work on a subsequent pass.
+    CFRunLoopSourceSignal(delayed_work_source_);
+    CFRunLoopSourceSignal(idle_work_source_);
+  }
+
+  return true;
+}
+
+// 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, 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::RunIdleWork(CFRunLoopObserverRef observer,
-                                           CFRunLoopActivity activity,
-                                           void* info) {
-  MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
+void MessagePumpCFRunLoopBase::PreWaitObserver(CFRunLoopObserverRef observer,
+                                               CFRunLoopActivity activity,
+                                               void* info) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  // 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.
+// 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) {
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  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:
+      // 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_;
+      break;
 
-  // If we're on the main event loop, the NSApp runloop won't clean up the
-  // autoreleasepool until there is UI event, so use a local one for any
-  // autoreleased objects to ensure they go away sooner.
-  ScopedNSAutoreleasePool autorelease_pool;
+    default:
+      break;
+  }
+
+  self->EnterExitRunLoop(activity);
+}
 
-  if (self->delegate_->DoIdleWork()) {
-    // If idle work was done, don't let the loop go to sleep.  More idle work
-    // might be waiting.
-    CFRunLoopWakeUp(self->run_loop_);
+// Called from the run loop.
+// static
+void MessagePumpCFRunLoopBase::PowerStateNotification(void* info,
+                                                      io_service_t service,
+                                                      uint32_t message_type,
+                                                      void* message_argument) {
+  // CFRunLoopTimer (NSTimer) is scheduled in terms of CFAbsoluteTime, which
+  // measures the number of seconds since 2001-01-01 00:00:00.0 Z.  It is
+  // implemented in terms of kernel ticks, as in mach_absolute_time.  While an
+  // offset and scale factor can be applied to convert between the two time
+  // bases at any time after boot, the kernel clock stops while the system is
+  // asleep, altering the offset.  (The offset will also change when the
+  // real-time clock is adjusted.)  CFRunLoopTimers are not readjusted to take
+  // this into account when the system wakes up, so any timers that were
+  // pending while the system was asleep will be delayed by the sleep
+  // duration.
+  //
+  // The MessagePump interface assumes that scheduled delayed work will be
+  // performed at the time ScheduleDelayedWork was asked to perform it.  The
+  // delay caused by the CFRunLoopTimer not firing at the appropriate time
+  // results in a stall of queued delayed work when the system wakes up.
+  // With this limitation, scheduled work would not be performed until
+  // (system wake time + scheduled work time - system sleep time), while it
+  // would be expected to be performed at (scheduled work time).
+  //
+  // To work around this problem, when the system wakes up from sleep, if a
+  // delayed work timer is pending, it is rescheduled to fire at the original
+  // time that it was scheduled to fire.
+  //
+  // This mechanism is not resilient if the real-time clock does not maintain
+  // stable time while the system is sleeping, but it matches the behavior of
+  // the various other MessagePump implementations, and MessageLoop seems to
+  // be limited in the same way.
+  //
+  // References
+  //  - Chris Kane, "NSTimer and deep sleep," cocoa-dev@lists.apple.com,
+  //    http://lists.apple.com/archives/Cocoa-dev/2002/May/msg01547.html
+  //  - Apple Technical Q&A QA1340, "Registering and unregistering for sleep
+  //    and wake notifications,"
+  //    http://developer.apple.com/mac/library/qa/qa2004/qa1340.html
+  //  - Core Foundation source code, CF-550/CFRunLoop.c and CF-550/CFDate.c,
+  //    http://www.opensource.apple.com/
+
+  MessagePumpCFRunLoopBase* self = static_cast<MessagePumpCFRunLoopBase*>(info);
+
+  switch (message_type) {
+    case kIOMessageSystemWillPowerOn:
+      if (self->delayed_work_fire_time_ != kCFTimeIntervalMax) {
+        CFRunLoopTimerSetNextFireDate(self->delayed_work_timer_,
+                                      self->delayed_work_fire_time_);
+      }
+      break;
+
+    case kIOMessageSystemWillSleep:
+    case kIOMessageCanSystemSleep:
+      // The system will wait for 30 seconds before entering sleep if neither
+      // IOAllowPowerChange nor IOCancelPowerChange are called.  That would be
+      // pretty antisocial.
+      IOAllowPowerChange(self->root_power_domain_,
+                         reinterpret_cast<long>(message_argument));
+      break;
+
+    default:
+      break;
   }
 }
 
-// Must be called on the run loop thread.
-MessagePumpCFRunLoop::MessagePumpCFRunLoop()
-    : nesting_level_(0),
-      innermost_quittable_(0),
-      quit_pending_(false) {
-  CFRunLoopObserverContext observer_context = CFRunLoopObserverContext();
-  observer_context.info = this;
-  enter_exit_observer_ = CFRunLoopObserverCreate(NULL,  // allocator
-                                                 kCFRunLoopEntry |
-                                                     kCFRunLoopExit,
-                                                 true,  // repeat
-                                                 0,     // priority
-                                                 EnterExitRunLoop,
-                                                 &observer_context);
-  CFRunLoopAddObserver(run_loop_, enter_exit_observer_, kCFRunLoopCommonModes);
+// Called by MessagePumpCFRunLoopBase::EnterExitRunLoop.  The default
+// implementation is a no-op.
+void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) {
+}
+
+// Base version returns a standard NSAutoreleasePool.
+NSAutoreleasePool* MessagePumpCFRunLoopBase::CreateAutoreleasePool() {
+  return [[NSAutoreleasePool alloc] init];
 }
 
-// Ideally called on the run loop thread.  If other CFRunLoopRun loops were
-// running lower on the run loop thread's stack when this object was created,
-// the same number of CFRunLoopRun loops must be running when this object is
-// destroyed.
-MessagePumpCFRunLoop::~MessagePumpCFRunLoop() {
-  CFRunLoopRemoveObserver(run_loop_, enter_exit_observer_,
-                          kCFRunLoopCommonModes);
-  CFRelease(enter_exit_observer_);
+MessagePumpCFRunLoop::MessagePumpCFRunLoop()
+    : quit_pending_(false) {
 }
 
-// Called by CFRunLoopBase::DoRun.  If other CFRunLoopRun loops were running
-// lower on the run loop thread's stack when this object was created, the same
-// number of CFRunLoopRun loops must be running for the outermost call to Run.
-// Run/DoRun are reentrant after that point.
+// Called by MessagePumpCFRunLoopBase::DoRun.  If other CFRunLoopRun loops were
+// running lower on the run loop thread's stack when this object was created,
+// the same number of CFRunLoopRun loops must be running for the outermost call
+// to Run.  Run/DoRun are reentrant after that point.
 void MessagePumpCFRunLoop::DoRun(Delegate* delegate) {
-  // nesting_level_ will be incremented in EnterExitRunLoop, so set
-  // innermost_quittable_ accordingly.
-  int last_innermost_quittable = innermost_quittable_;
-  innermost_quittable_ = nesting_level_ + 1;
-
   // This is completely identical to calling CFRunLoopRun(), except autorelease
   // pool management is introduced.
   int result;
   do {
-    ScopedNSAutoreleasePool autorelease_pool;
-    result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, DBL_MAX, false);
+    MessagePumpScopedAutoreleasePool autorelease_pool(this);
+    result = CFRunLoopRunInMode(kCFRunLoopDefaultMode,
+                                kCFTimeIntervalMax,
+                                false);
   } while (result != kCFRunLoopRunStopped && result != kCFRunLoopRunFinished);
-
-  // Restore the previous state of the object.
-  innermost_quittable_ = last_innermost_quittable;
 }
 
 // Must be called on the run loop thread.
 void MessagePumpCFRunLoop::Quit() {
   // Stop the innermost run loop managed by this MessagePumpCFRunLoop object.
-  if (nesting_level_ == innermost_quittable_) {
+  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;
   }
 }
 
-// Called from the run loop.
-// static
-void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopObserverRef observer,
-                                            CFRunLoopActivity activity,
-                                            void* info) {
-  MessagePumpCFRunLoop* self = static_cast<MessagePumpCFRunLoop*>(info);
-
-  switch (activity) {
-    case kCFRunLoopEntry:
-      // If the run loop was entered by a call to Run, this will properly
-      // balance the decrement done in Run before entering the loop.
-      ++self->nesting_level_;
-      break;
-    case kCFRunLoopExit:
-      if (--self->nesting_level_ == self->innermost_quittable_ &&
-          self->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(self->run_loop_);
-        self->quit_pending_ = false;
-      }
-      break;
-    default:
-      break;
+// Called by MessagePumpCFRunLoopBase::EnterExitObserver.
+void MessagePumpCFRunLoop::EnterExitRunLoop(CFRunLoopActivity activity) {
+  if (activity == kCFRunLoopExit &&
+      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());
+    quit_pending_ = false;
   }
 }
 
 MessagePumpNSRunLoop::MessagePumpNSRunLoop()
     : keep_running_(true) {
   CFRunLoopSourceContext source_context = CFRunLoopSourceContext();
   source_context.perform = NoOp;
   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_);
 }
 
 void MessagePumpNSRunLoop::DoRun(Delegate* delegate) {
   while (keep_running_) {
     // NSRunLoop manages autorelease pools itself.
     [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode
                              beforeDate:[NSDate distantFuture]];
   }
 
   keep_running_ = true;
 }
 
 void MessagePumpNSRunLoop::Quit() {
   keep_running_ = false;
   CFRunLoopSourceSignal(quit_source_);
-  CFRunLoopWakeUp(run_loop_);
+  CFRunLoopWakeUp(run_loop());
 }
 
 MessagePumpNSApplication::MessagePumpNSApplication()
     : keep_running_(true),
       running_own_loop_(false) {
 }
 
 void MessagePumpNSApplication::DoRun(Delegate* delegate) {
   bool last_running_own_loop_ = running_own_loop_;
 
-  [NSApplication sharedApplication];
+  // TODO(dmaclach): Get rid of this gratuitous sharedApplication.
+  // Tests should be setting up their applications on their own.
+  [CrApplication sharedApplication];
 
   if (![NSApp isRunning]) {
     running_own_loop_ = false;
     // NSApplication manages autorelease pools itself when run this way.
     [NSApp run];
   } else {
     running_own_loop_ = true;
+    NSDate* distant_future = [NSDate distantFuture];
     while (keep_running_) {
-      ScopedNSAutoreleasePool autorelease_pool;
+      MessagePumpScopedAutoreleasePool autorelease_pool(this);
       NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
-                                          untilDate:[NSDate distantFuture]
+                                          untilDate:distant_future
                                              inMode:NSDefaultRunLoopMode
                                             dequeue:YES];
       if (event) {
         [NSApp sendEvent:event];
       }
     }
     keep_running_ = true;
   }
@@ -358,27 +698,67 @@ void MessagePumpNSApplication::Quit() {
   if (!running_own_loop_) {
     [NSApp stop:nil];
   } else {
     keep_running_ = false;
   }
 
   // Send a fake event to wake the loop up.
   [NSApp postEvent:[NSEvent otherEventWithType:NSApplicationDefined
-                                      location:NSMakePoint(0,0)
+                                      location:NSMakePoint(0, 0)
                                  modifierFlags:0
                                      timestamp:0
                                   windowNumber:0
                                        context:NULL
                                        subtype:0
                                          data1:0
                                          data2:0]
            atStart:NO];
 }
 
+// Prevents an autorelease pool from being created if the app is in the midst of
+// handling a UI event because various parts of AppKit depend on objects that
+// are created while handling a UI event to be autoreleased in the event loop.
+// An example of this is NSWindowController. When a window with a window
+// controller is closed it goes through a stack like this:
+// (Several stack frames elided for clarity)
+//
+// #0 [NSWindowController autorelease]
+// #1 DoAClose
+// #2 MessagePumpCFRunLoopBase::DoWork()
+// #3 [NSRunLoop run]
+// #4 [NSButton performClick:]
+// #5 [NSWindow sendEvent:]
+// #6 [NSApp sendEvent:]
+// #7 [NSApp run]
+//
+// -performClick: spins a nested run loop. If the pool created in DoWork was a
+// standard NSAutoreleasePool, it would release the objects that were
+// autoreleased into it once DoWork released it. This would cause the window
+// controller, which autoreleased itself in frame #0, to release itself, and
+// possibly free itself. Unfortunately this window controller controls the
+// window in frame #5. When the stack is unwound to frame #5, the window would
+// no longer exists and crashes may occur. Apple gets around this by never
+// releasing the pool it creates in frame #4, and letting frame #7 clean it up
+// when it cleans up the pool that wraps frame #7. When an autorelease pool is
+// released it releases all other pools that were created after it on the
+// autorelease pool stack.
+//
+// CrApplication is responsible for setting handlingSendEvent to true just
+// before it sends the event throught the event handling mechanism, and
+// returning it to its previous value once the event has been sent.
+NSAutoreleasePool* MessagePumpNSApplication::CreateAutoreleasePool() {
+  NSAutoreleasePool* pool = nil;
+  DCHECK([NSApp isKindOfClass:[CrApplication class]]);
+  if (![static_cast<CrApplication*>(NSApp) isHandlingSendEvent]) {
+    pool = MessagePumpCFRunLoopBase::CreateAutoreleasePool();
+  }
+  return pool;
+}
+
 // static
 MessagePump* MessagePumpMac::Create() {
   if ([NSThread isMainThread]) {
     return new MessagePumpNSApplication;
   }
 
   return new MessagePumpNSRunLoop;
 }
--- a/ipc/chromium/src/chrome/common/main_function_params.h
+++ b/ipc/chromium/src/chrome/common/main_function_params.h
@@ -1,18 +1,18 @@
 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
 // Wrapper to the parameter list for the "main" entry points (browser, renderer,
 // plugin) to shield the call sites from the differences between platforms
 // (e.g., POSIX doesn't need to pass any sandbox information).
 
-#ifndef CHROME_COMMON_MAIN_FUNCTINON_PARAMS_H_
-#define CHROME_COMMON_MAIN_FUNCTINON_PARAMS_H_
+#ifndef CHROME_COMMON_MAIN_FUNCTION_PARAMS_H_
+#define CHROME_COMMON_MAIN_FUNCTION_PARAMS_H_
 
 #include "base/command_line.h"
 #include "chrome/common/sandbox_init_wrapper.h"
 
 namespace base {
 class ScopedNSAutoreleasePool;
 };
 class Task;
@@ -25,9 +25,9 @@ struct MainFunctionParams {
   const CommandLine& command_line_;
   const SandboxInitWrapper& sandbox_info_;
   base::ScopedNSAutoreleasePool* autorelease_pool_;
   // Used by InProcessBrowserTest. If non-null BrowserMain schedules this
   // task to run on the MessageLoop and BrowserInit is not invoked.
   Task* ui_task;
 };
 
-#endif  // CHROME_COMMON_MAIN_FUNCTINON_PARAMS_H_
+#endif  // CHROME_COMMON_MAIN_FUNCTION_PARAMS_H_