From 9d50498a31e524b27e2b3b3fc302fb716319f627 Mon Sep 17 00:00:00 2001 From: "bzbarsky%mit.edu" Date: Tue, 10 Jul 2007 03:48:07 +0000 Subject: [PATCH] Make sure that we push a null JSContext on the current thread's XPConnect stack before processing events. Bug 326777, r=bsmedberg, sr=jst git-svn-id: svn://10.0.0.236/trunk@229584 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/src/xpconnect/src/nsXPConnect.cpp | 36 ++++++++++- mozilla/js/src/xpconnect/src/xpcprivate.h | 4 ++ mozilla/xpcom/threads/Makefile.in | 1 + mozilla/xpcom/threads/nsThread.cpp | 24 ++++++++ mozilla/xpcom/threads/nsThread.h | 3 + mozilla/xpcom/threads/nsThreadUtilsInternal.h | 61 +++++++++++++++++++ 6 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 mozilla/xpcom/threads/nsThreadUtilsInternal.h diff --git a/mozilla/js/src/xpconnect/src/nsXPConnect.cpp b/mozilla/js/src/xpconnect/src/nsXPConnect.cpp index 93e657b5506..88c91f2f2a7 100644 --- a/mozilla/js/src/xpconnect/src/nsXPConnect.cpp +++ b/mozilla/js/src/xpconnect/src/nsXPConnect.cpp @@ -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 diff --git a/mozilla/js/src/xpconnect/src/xpcprivate.h b/mozilla/js/src/xpconnect/src/xpcprivate.h index 6b08247e5c7..1d2cb447b03 100644 --- a/mozilla/js/src/xpconnect/src/xpcprivate.h +++ b/mozilla/js/src/xpconnect/src/xpcprivate.h @@ -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: diff --git a/mozilla/xpcom/threads/Makefile.in b/mozilla/xpcom/threads/Makefile.in index 3b94734c392..8fc4dc0be74 100644 --- a/mozilla/xpcom/threads/Makefile.in +++ b/mozilla/xpcom/threads/Makefile.in @@ -69,6 +69,7 @@ CPPSRCS = \ EXPORTS = \ nsProcess.h \ nsEventQueue.h \ + nsThreadUtilsInternal.h \ $(NULL) XPIDLSRCS = \ diff --git a/mozilla/xpcom/threads/nsThread.cpp b/mozilla/xpcom/threads/nsThread.cpp index 761f42a334b..afd1de13fbc 100644 --- a/mozilla/xpcom/threads/nsThread.cpp +++ b/mozilla/xpcom/threads/nsThread.cpp @@ -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 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; +} diff --git a/mozilla/xpcom/threads/nsThread.h b/mozilla/xpcom/threads/nsThread.h index b71ef2fc6f4..40d719b6fa6 100644 --- a/mozilla/xpcom/threads/nsThread.h +++ b/mozilla/xpcom/threads/nsThread.h @@ -72,6 +72,9 @@ public: // nsIThreadManager::NewThread. PRBool ShutdownRequired() { return mShutdownRequired; } + // The global thread observer + static nsIThreadObserver* sGlobalObserver; + private: friend class nsThreadShutdownEvent; diff --git a/mozilla/xpcom/threads/nsThreadUtilsInternal.h b/mozilla/xpcom/threads/nsThreadUtilsInternal.h new file mode 100644 index 00000000000..f99929030e0 --- /dev/null +++ b/mozilla/xpcom/threads/nsThreadUtilsInternal.h @@ -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 + * + * 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_