Make sure that we push a null JSContext on the current thread's XPConnect stack

before processing events.  Bug 326777, r=bsmedberg, sr=jst
This commit is contained in:
bzbarsky@mit.edu 2007-07-09 20:48:06 -07:00
parent b6a07ae185
commit 30e205dddb
6 changed files with 128 additions and 1 deletions

View File

@ -50,8 +50,12 @@
#include "jsfun.h"
#include "jsobj.h"
#include "jsscript.h"
#include "nsThreadUtilsInternal.h"
NS_IMPL_THREADSAFE_ISUPPORTS2(nsXPConnect,nsIXPConnect,nsISupportsWeakReference)
NS_IMPL_THREADSAFE_ISUPPORTS3(nsXPConnect,
nsIXPConnect,
nsISupportsWeakReference,
nsIThreadObserver)
nsXPConnect* nsXPConnect::gSelf = nsnull;
JSBool nsXPConnect::gOnceAliveNowDead = JS_FALSE;
@ -286,6 +290,10 @@ nsXPConnect::GetXPConnect()
// Initial extra ref to keep the singleton alive
// balanced by explicit call to ReleaseXPConnectSingleton()
NS_ADDREF(gSelf);
if (NS_FAILED(NS_SetGlobalThreadObserver(gSelf))) {
NS_RELEASE(gSelf);
// Fall through to returning null
}
}
}
return gSelf;
@ -307,6 +315,7 @@ nsXPConnect::ReleaseXPConnectSingleton()
nsXPConnect* xpc = gSelf;
if(xpc)
{
NS_SetGlobalThreadObserver(nsnull);
#ifdef XPC_TOOLS_SUPPORT
if(xpc->mProfiler)
@ -2014,6 +2023,31 @@ nsXPConnect::FlagSystemFilenamePrefix(const char *aFilenamePrefix)
return NS_OK;
}
NS_IMETHODIMP
nsXPConnect::OnProcessNextEvent(nsIThreadInternal *aThread, PRBool aMayWait,
PRUint32 aRecursionDepth)
{
// Push a null JSContext so that we don't see any script during
// event processing.
NS_ENSURE_STATE(mContextStack);
return mContextStack->Push(nsnull);
}
NS_IMETHODIMP
nsXPConnect::AfterProcessNextEvent(nsIThreadInternal *aThread,
PRUint32 aRecursionDepth)
{
NS_ENSURE_STATE(mContextStack);
return mContextStack->Pop(nsnull);
}
NS_IMETHODIMP
nsXPConnect::OnDispatchedEvent(nsIThreadInternal* aThread)
{
NS_NOTREACHED("Why tell us?");
return NS_ERROR_UNEXPECTED;
}
#ifdef DEBUG
/* These are here to be callable from a debugger */
JS_BEGIN_EXTERN_C

View File

@ -126,6 +126,8 @@
#include "nsIXPCToolsProfiler.h"
#endif
#include "nsIThreadInternal.h"
#ifdef XPC_IDISPATCH_SUPPORT
// This goop was added because of EXCEPINFO in ThrowCOMError
// This include is here, because it needs to occur before the undefines below
@ -426,6 +428,7 @@ const PRBool OBJ_IS_NOT_GLOBAL = PR_FALSE;
struct JSObjectRefcounts;
class nsXPConnect : public nsIXPConnect,
public nsIThreadObserver,
public nsSupportsWeakReference,
public nsCycleCollectionLanguageRuntime,
public nsCycleCollectionParticipant
@ -434,6 +437,7 @@ public:
// all the interface method declarations...
NS_DECL_ISUPPORTS
NS_DECL_NSIXPCONNECT
NS_DECL_NSITHREADOBSERVER
// non-interface implementation
public:

View File

@ -69,6 +69,7 @@ CPPSRCS = \
EXPORTS = \
nsProcess.h \
nsEventQueue.h \
nsThreadUtilsInternal.h \
$(NULL)
XPIDLSRCS = \

View File

@ -52,6 +52,8 @@ static PRLogModuleInfo *sLog = PR_NewLogModule("nsThread");
NS_DECL_CI_INTERFACE_GETTER(nsThread)
nsIThreadObserver* nsThread::sGlobalObserver;
//-----------------------------------------------------------------------------
// Because we do not have our own nsIFactory, we have to implement nsIClassInfo
// somewhat manually.
@ -464,6 +466,10 @@ nsThread::ProcessNextEvent(PRBool mayWait, PRBool *result)
NS_ENSURE_STATE(PR_GetCurrentThread() == mThread);
if (sGlobalObserver)
sGlobalObserver->OnProcessNextEvent(this, mayWait && !ShuttingDown(),
mRunningEvent);
nsCOMPtr<nsIThreadObserver> obs = mObserver;
if (obs)
obs->OnProcessNextEvent(this, mayWait && !ShuttingDown(), mRunningEvent);
@ -489,6 +495,9 @@ nsThread::ProcessNextEvent(PRBool mayWait, PRBool *result)
if (obs)
obs->AfterProcessNextEvent(this, mRunningEvent);
if (sGlobalObserver)
sGlobalObserver->AfterProcessNextEvent(this, mRunningEvent);
return rv;
}
@ -618,3 +627,18 @@ nsThreadSyncDispatch::Run()
}
return NS_OK;
}
nsresult
NS_SetGlobalThreadObserver(nsIThreadObserver* aObserver)
{
if (aObserver && nsThread::sGlobalObserver) {
return NS_ERROR_NOT_AVAILABLE;
}
if (!NS_IsMainThread()) {
return NS_ERROR_UNEXPECTED;
}
nsThread::sGlobalObserver = aObserver;
return NS_OK;
}

View File

@ -72,6 +72,9 @@ public:
// nsIThreadManager::NewThread.
PRBool ShutdownRequired() { return mShutdownRequired; }
// The global thread observer
static nsIThreadObserver* sGlobalObserver;
private:
friend class nsThreadShutdownEvent;

View File

@ -0,0 +1,61 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2007
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Boris Zbarsky <bzbarsky@mit.edu>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsThreadUtilsInternal_h_
#define nsThreadUtilsInternal_h_
#ifdef MOZILLA_INTERNAL_API
class nsIThreadObserver;
/**
* Function to set a "global" thread observer that all threads will notify when
* they process an event. This observer will not be notified when events are
* posted to threads. Only one global observer can be set at a time; an
* attempt to change the value without setting it to null first will throw.
* This function does NOT take a reference to the observer; the caller of this
* function is responsible for setting the observer to null when it goes away.
* This method may only be called on the main thread; attempts to do it on
* other threads will return an error.
*/
extern nsresult
NS_COM NS_SetGlobalThreadObserver(nsIThreadObserver* aObserver);
#endif // MOZILLA_INTERNAL_API
#endif // nsThreadUtilsInternal_h_