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

Unified Diff: base/message_pump_mac.mm

Issue 345051: Cleans up our autorelease handling so that we don't create a layered ... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: '' Created 11 years, 1 month 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/chrome_application_mac.mm ('k') | chrome/app/app-Info.plist » ('j') | 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 31104)
+++ base/message_pump_mac.mm (working copy)
@@ -11,7 +11,8 @@
#include <limits>
-#include "base/scoped_nsautorelease_pool.h"
+#import "base/chrome_application_mac.h"
+#include "base/logging.h"
#include "base/time.h"
namespace {
@@ -26,6 +27,23 @@
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()) {
Mark Mentovai 2009/11/05 20:28:40 Final really tiny minor insignificant nit that you
+ }
+ ~MessagePumpScopedAutoreleasePool() {
Scott Hess - ex-Googler 2009/11/05 20:36:12 Nit: indentation.
+ [pool_ drain];
+ }
+
+ private:
+ NSAutoreleasePool* pool_;
+ DISALLOW_COPY_AND_ASSIGN(MessagePumpScopedAutoreleasePool);
+};
+
// Must be called on the run loop thread.
MessagePumpCFRunLoopBase::MessagePumpCFRunLoopBase()
: delegate_(NULL),
@@ -264,9 +282,9 @@
// 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;
+ // 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.
@@ -298,9 +316,9 @@
// 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;
+ // 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);
@@ -342,9 +360,9 @@
// 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;
+ // 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.
@@ -555,6 +573,11 @@
void MessagePumpCFRunLoopBase::EnterExitRunLoop(CFRunLoopActivity activity) {
}
+// Base version returns a standard NSAutoreleasePool.
+NSAutoreleasePool* MessagePumpCFRunLoopBase::CreateAutoreleasePool() {
+ return [[NSAutoreleasePool alloc] init];
+}
+
MessagePumpCFRunLoop::MessagePumpCFRunLoop()
: quit_pending_(false) {
}
@@ -568,7 +591,7 @@
// pool management is introduced.
int result;
do {
- ScopedNSAutoreleasePool autorelease_pool;
+ MessagePumpScopedAutoreleasePool autorelease_pool(this);
result = CFRunLoopRunInMode(kCFRunLoopDefaultMode,
kCFTimeIntervalMax,
false);
@@ -644,7 +667,9 @@
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;
@@ -654,7 +679,7 @@
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:distant_future
inMode:NSDefaultRunLoopMode
@@ -689,6 +714,46 @@
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]) {
« no previous file with comments | « base/chrome_application_mac.mm ('k') | chrome/app/app-Info.plist » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698