--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -45,18 +45,22 @@
#include "xpcprivate.h"
#include "XPCNativeWrapper.h"
#include "nsBaseHashtable.h"
#include "nsHashKeys.h"
#include "jsatom.h"
#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;
const char XPC_CONTEXT_STACK_CONTRACTID[] = "@mozilla.org/js/xpc/ContextStack;1";
const char XPC_RUNTIME_CONTRACTID[] = "@mozilla.org/js/xpc/RuntimeService;1";
const char XPC_EXCEPTION_CONTRACTID[] = "@mozilla.org/js/xpc/Exception;1";
const char XPC_CONSOLE_CONTRACTID[] = "@mozilla.org/consoleservice;1";
@@ -281,16 +285,20 @@ nsXPConnect::GetXPConnect()
delete gSelf;
gSelf = nsnull;
}
else
{
// 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;
}
// static
nsXPConnect*
nsXPConnect::GetSingleton()
@@ -302,16 +310,17 @@ nsXPConnect::GetSingleton()
// static
void
nsXPConnect::ReleaseXPConnectSingleton()
{
nsXPConnect* xpc = gSelf;
if(xpc)
{
+ NS_SetGlobalThreadObserver(nsnull);
#ifdef XPC_TOOLS_SUPPORT
if(xpc->mProfiler)
{
xpc->mProfiler->Stop();
xpc->mProfiler->WriteResults(xpc->mProfilerOutputFile);
}
#endif
@@ -2009,16 +2018,41 @@ nsXPConnect::FlagSystemFilenamePrefix(co
if(NS_FAILED(rv))
return rv;
if(!JS_FlagScriptFilenamePrefix(rt, aFilenamePrefix, JSFILENAME_SYSTEM))
return NS_ERROR_OUT_OF_MEMORY;
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
void DumpJSStack()
{
nsresult rv;
nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
if(NS_SUCCEEDED(rv) && xpc)
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -121,16 +121,18 @@
#ifdef XPC_USE_SECURITY_CHECKED_COMPONENT
#include "nsISecurityCheckedComponent.h"
#endif
#ifdef XPC_TOOLS_SUPPORT
#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
#include <atlbase.h>
#include "oaidl.h"
// Nasty MS defines
#undef GetClassInfo
#undef GetClassName
@@ -421,24 +423,26 @@ private:
// returned as function call result values they are not addref'd. Exceptions
// to this rule are noted explicitly.
const PRBool OBJ_IS_GLOBAL = PR_TRUE;
const PRBool OBJ_IS_NOT_GLOBAL = PR_FALSE;
struct JSObjectRefcounts;
class nsXPConnect : public nsIXPConnect,
+ public nsIThreadObserver,
public nsSupportsWeakReference,
public nsCycleCollectionLanguageRuntime,
public nsCycleCollectionParticipant
{
public:
// all the interface method declarations...
NS_DECL_ISUPPORTS
NS_DECL_NSIXPCONNECT
+ NS_DECL_NSITHREADOBSERVER
// non-interface implementation
public:
// These get non-addref'd pointers
static nsXPConnect* GetXPConnect();
static XPCJSRuntime* GetRuntime(nsXPConnect* xpc = nsnull);
static XPCContext* GetContext(JSContext* cx, nsXPConnect* xpc = nsnull);
static nsIJSRuntimeService* GetJSRuntimeService(nsXPConnect* xpc = nsnull);
--- a/xpcom/threads/Makefile.in
+++ b/xpcom/threads/Makefile.in
@@ -64,16 +64,17 @@ CPPSRCS = \
nsProcessCommon.cpp \
nsTimerImpl.cpp \
TimerThread.cpp \
$(NULL)
EXPORTS = \
nsProcess.h \
nsEventQueue.h \
+ nsThreadUtilsInternal.h \
$(NULL)
XPIDLSRCS = \
nsIEventTarget.idl \
nsIThread.idl \
nsIThreadInternal.idl \
nsIThreadManager.idl \
nsIThreadPool.idl \
--- a/xpcom/threads/nsThread.cpp
+++ b/xpcom/threads/nsThread.cpp
@@ -39,24 +39,27 @@
#include "nsThread.h"
#include "nsThreadManager.h"
#include "nsIClassInfoImpl.h"
#include "nsIProgrammingLanguage.h"
#include "nsAutoLock.h"
#include "nsAutoPtr.h"
#include "nsCOMPtr.h"
#include "prlog.h"
+#include "nsThreadUtilsInternal.h"
#ifdef PR_LOGGING
static PRLogModuleInfo *sLog = PR_NewLogModule("nsThread");
#endif
#define LOG(args) PR_LOG(sLog, PR_LOG_DEBUG, args)
NS_DECL_CI_INTERFACE_GETTER(nsThread)
+nsIThreadObserver* nsThread::sGlobalObserver;
+
//-----------------------------------------------------------------------------
// Because we do not have our own nsIFactory, we have to implement nsIClassInfo
// somewhat manually.
class nsThreadClassInfo : public nsIClassInfo {
public:
NS_DECL_ISUPPORTS_INHERITED // no mRefCnt
NS_DECL_NSICLASSINFO
@@ -459,16 +462,20 @@ nsThread::HasPendingEvents(PRBool *resul
NS_IMETHODIMP
nsThread::ProcessNextEvent(PRBool mayWait, PRBool *result)
{
LOG(("THRD(%p) ProcessNextEvent [%u %u]\n", this, mayWait, mRunningEvent));
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);
// If we are shutting down, then do not wait for new events.
nsCOMPtr<nsIRunnable> event;
mEvents->GetEvent(mayWait && !ShuttingDown(), getter_AddRefs(event));
@@ -484,16 +491,19 @@ nsThread::ProcessNextEvent(PRBool mayWai
} else if (mayWait) {
NS_ASSERTION(ShuttingDown(), "This should only happen when shutting down");
rv = NS_ERROR_UNEXPECTED;
}
if (obs)
obs->AfterProcessNextEvent(this, mRunningEvent);
+ if (sGlobalObserver)
+ sGlobalObserver->AfterProcessNextEvent(this, mRunningEvent);
+
return rv;
}
//-----------------------------------------------------------------------------
// nsISupportsPriority
NS_IMETHODIMP
nsThread::GetPriority(PRInt32 *priority)
@@ -613,8 +623,23 @@ nsThreadSyncDispatch::Run()
if (mSyncTask) {
mSyncTask->Run();
mSyncTask = nsnull;
// unblock the origin thread
mOrigin->Dispatch(this, NS_DISPATCH_NORMAL);
}
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;
+}
--- a/xpcom/threads/nsThread.h
+++ b/xpcom/threads/nsThread.h
@@ -67,16 +67,19 @@ public:
// The PRThread corresponding to this thread.
PRThread *GetPRThread() { return mThread; }
// If this flag is true, then the nsThread was created using
// nsIThreadManager::NewThread.
PRBool ShutdownRequired() { return mShutdownRequired; }
+ // The global thread observer
+ static nsIThreadObserver* sGlobalObserver;
+
private:
friend class nsThreadShutdownEvent;
~nsThread();
PRBool ShuttingDown() { return mShutdownContext != nsnull; }
PR_STATIC_CALLBACK(void) ThreadFunc(void *arg);