mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-19 09:30:44 +00:00
340032 nsIThreadObserver needs a method called after processing an event to support Cocoa autorelease pools. r=darin sr=bryner
This commit is contained in:
parent
3c9961813f
commit
a6b04ae8c0
@ -477,6 +477,13 @@ nsSocketTransportService::OnProcessNextEvent(nsIThreadInternal *thread,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::AfterProcessNextEvent(nsIThreadInternal* thread,
|
||||
PRUint32 depth)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSocketTransportService::Run()
|
||||
{
|
||||
|
@ -55,6 +55,10 @@ public:
|
||||
nsresult Init();
|
||||
|
||||
NS_IMETHOD Run(void);
|
||||
NS_IMETHOD OnProcessNextEvent(nsIThreadInternal *aThread, PRBool aMayWait,
|
||||
PRUint32 aRecursionDepth);
|
||||
NS_IMETHOD AfterProcessNextEvent(nsIThreadInternal *aThread,
|
||||
PRUint32 aRecursionDepth);
|
||||
|
||||
// public only to be visible to Objective-C code that must call it
|
||||
void ProcessGeckoEvents();
|
||||
@ -67,6 +71,7 @@ protected:
|
||||
|
||||
protected:
|
||||
NSAutoreleasePool* mMainPool;
|
||||
CFMutableArrayRef mAutoreleasePools;
|
||||
|
||||
NSPort* mPort;
|
||||
AppShellDelegate* mDelegate;
|
||||
|
@ -70,7 +70,8 @@
|
||||
// nsAppShell implementation
|
||||
|
||||
nsAppShell::nsAppShell()
|
||||
: mPort(nil)
|
||||
: mAutoreleasePools(nsnull)
|
||||
, mPort(nil)
|
||||
, mDelegate(nil)
|
||||
, mRunningEventLoop(PR_FALSE)
|
||||
{
|
||||
@ -85,6 +86,12 @@ nsAppShell::nsAppShell()
|
||||
|
||||
nsAppShell::~nsAppShell()
|
||||
{
|
||||
if (mAutoreleasePools) {
|
||||
NS_ASSERTION(::CFArrayGetCount(mAutoreleasePools) == 0,
|
||||
"nsAppShell destroyed without popping all autorelease pools");
|
||||
::CFRelease(mAutoreleasePools);
|
||||
}
|
||||
|
||||
if (mPort) {
|
||||
[[NSRunLoop currentRunLoop] removePort:mPort forMode:NSDefaultRunLoopMode];
|
||||
[mPort release];
|
||||
@ -108,6 +115,13 @@ nsAppShell::Init()
|
||||
// and will release them as appropriate.
|
||||
NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
|
||||
|
||||
// mAutoreleasePools is used as a stack of NSAutoreleasePool objects created
|
||||
// by |this|. CFArray is used instead of NSArray because NSArray wants to
|
||||
// retain each object you add to it, and you can't retain an
|
||||
// NSAutoreleasePool.
|
||||
mAutoreleasePools = ::CFArrayCreateMutable(nsnull, 0, nsnull);
|
||||
NS_ENSURE_STATE(mAutoreleasePools);
|
||||
|
||||
// Get the path of the nib file, which lives in the GRE location
|
||||
nsCOMPtr<nsIFile> nibFile;
|
||||
nsresult rv = NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(nibFile));
|
||||
@ -230,10 +244,10 @@ nsAppShell::ProcessNextNativeEvent(PRBool aMayWait)
|
||||
waitUntil = [NSDate distantFuture];
|
||||
|
||||
do {
|
||||
// Handle the event on its own autorelease pool.
|
||||
// Ordinarily, each event gets a new pool when dispatched by
|
||||
// [NSApp run].
|
||||
NSAutoreleasePool* localPool = [[NSAutoreleasePool alloc] init];
|
||||
// No autorelease pool is provided here, because OnProcessNextEvent
|
||||
// and AfterProcessNextEvent are responsible for maintaining it.
|
||||
NS_ASSERTION(mAutoreleasePools && ::CFArrayGetCount(mAutoreleasePools),
|
||||
"No autorelease pool for native event");
|
||||
|
||||
if (NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
|
||||
untilDate:waitUntil
|
||||
@ -253,8 +267,6 @@ nsAppShell::ProcessNextNativeEvent(PRBool aMayWait)
|
||||
|
||||
eventProcessed = PR_TRUE;
|
||||
}
|
||||
|
||||
[localPool release];
|
||||
} while (mRunningEventLoop);
|
||||
|
||||
mRunningEventLoop = wasRunningEventLoop;
|
||||
@ -289,6 +301,54 @@ nsAppShell::Run(void)
|
||||
return nsBaseAppShell::Run();
|
||||
}
|
||||
|
||||
// OnProcessNextEvent
|
||||
//
|
||||
// This nsIThreadObserver method is called prior to processing an event.
|
||||
// Set up an autorelease pool that will service any autoreleased Cocoa
|
||||
// objects during this event. This includes native events processed by
|
||||
// ProcessNextNativeEvent. The autorelease pool will be popped by
|
||||
// AfterProcessNextEvent, it is important for these two methods to be
|
||||
// tightly coupled.
|
||||
//
|
||||
// public
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::OnProcessNextEvent(nsIThreadInternal *aThread, PRBool aMayWait,
|
||||
PRUint32 aRecursionDepth)
|
||||
{
|
||||
NS_ASSERTION(mAutoreleasePools,
|
||||
"No stack on which to store autorelease pool");
|
||||
|
||||
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
|
||||
::CFArrayAppendValue(mAutoreleasePools, pool);
|
||||
|
||||
return nsBaseAppShell::OnProcessNextEvent(aThread, aMayWait, aRecursionDepth);
|
||||
}
|
||||
|
||||
// AfterProcessNextEvent
|
||||
//
|
||||
// This nsIThreadObserver method is called after event processing is complete.
|
||||
// The Cocoa implementation cleans up the autorelease pool create by the
|
||||
// previous OnProcessNextEvent call.
|
||||
//
|
||||
// public
|
||||
NS_IMETHODIMP
|
||||
nsAppShell::AfterProcessNextEvent(nsIThreadInternal *aThread,
|
||||
PRUint32 aRecursionDepth)
|
||||
{
|
||||
CFIndex count = ::CFArrayGetCount(mAutoreleasePools);
|
||||
|
||||
NS_ASSERTION(mAutoreleasePools && count,
|
||||
"Processed an event, but there's no autorelease pool?");
|
||||
|
||||
NSAutoreleasePool* pool = NS_STATIC_CAST(const NSAutoreleasePool*,
|
||||
::CFArrayGetValueAtIndex(mAutoreleasePools,
|
||||
count - 1));
|
||||
::CFArrayRemoveValueAtIndex(mAutoreleasePools, count - 1);
|
||||
[pool release];
|
||||
|
||||
return nsBaseAppShell::AfterProcessNextEvent(aThread, aRecursionDepth);
|
||||
}
|
||||
|
||||
// AppShellDelegate implementation
|
||||
|
||||
@implementation AppShellDelegate
|
||||
|
@ -244,6 +244,14 @@ nsBaseAppShell::OnProcessNextEvent(nsIThreadInternal *thr, PRBool mayWait,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Called from the main thread
|
||||
NS_IMETHODIMP
|
||||
nsBaseAppShell::AfterProcessNextEvent(nsIThreadInternal *thr,
|
||||
PRUint32 recursionDepth)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsBaseAppShell::Observe(nsISupports *subject, const char *topic,
|
||||
const PRUnichar *data)
|
||||
|
@ -101,7 +101,7 @@ interface nsIThreadInternal : nsIThread
|
||||
* NOTE: It is valid to change the thread's observer during a call to an
|
||||
* observer method.
|
||||
*/
|
||||
[scriptable, uuid(719d2fb9-54ce-4847-b15b-fa9960e22f9f)]
|
||||
[scriptable, uuid(81D0B509-F198-4417-8020-08EB4271491F)]
|
||||
interface nsIThreadObserver : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -128,6 +128,19 @@ interface nsIThreadObserver : nsISupports
|
||||
*/
|
||||
void onProcessNextEvent(in nsIThreadInternal thread, in boolean mayWait,
|
||||
in unsigned long recursionDepth);
|
||||
|
||||
/**
|
||||
* This method is called (from nsIThread::ProcessNextEvent) after an event
|
||||
* is processed. This method is only called on the target thread.
|
||||
*
|
||||
* @param thread
|
||||
* The thread that processed another event.
|
||||
* @param recursionDepth
|
||||
* Indicates the number of calls to ProcessNextEvent on the call stack in
|
||||
* addition to the current call.
|
||||
*/
|
||||
void afterProcessNextEvent(in nsIThreadInternal thread,
|
||||
in unsigned long recursionDepth);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -486,6 +486,9 @@ nsThread::ProcessNextEvent(PRBool mayWait, PRBool *result)
|
||||
rv = NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (obs)
|
||||
obs->AfterProcessNextEvent(this, mRunningEvent);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user