Bug 684938 - Proxy nsXPCWrappedJS::Release to the main thread. r=mrbkap.

--HG--
extra : rebase_source : faf9c46616c52bc03b776a4aae8fd3f87e11f132
This commit is contained in:
Peter Van der Beken 2011-09-14 08:44:27 -07:00
Родитель 20669cb83c
Коммит 1d05a88d12
2 изменённых файлов: 64 добавлений и 2 удалений

Просмотреть файл

@ -43,6 +43,7 @@
#include "xpcprivate.h" #include "xpcprivate.h"
#include "nsAtomicRefcnt.h" #include "nsAtomicRefcnt.h"
#include "nsProxyRelease.h"
#include "nsThreadUtils.h" #include "nsThreadUtils.h"
#include "nsTextFormatter.h" #include "nsTextFormatter.h"
@ -196,6 +197,21 @@ nsXPCWrappedJS::Release(void)
{ {
NS_PRECONDITION(0 != mRefCnt, "dup release"); NS_PRECONDITION(0 != mRefCnt, "dup release");
if (mMainThreadOnly && !NS_IsMainThread()) {
// We'd like to abort here, but this can happen if someone uses a proxy
// for the nsXPCWrappedJS.
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
// If we can't get the main thread anymore we just leak, but this really
// shouldn't happen.
NS_ASSERTION(mainThread,
"Can't get main thread, leaking nsXPCWrappedJS!");
if (mainThread) {
NS_ProxyRelease(mainThread,
static_cast<nsIXPConnectWrappedJS*>(this));
}
return mRefCnt;
}
// need to take the map lock here to prevent GetNewOrUsed from trying // need to take the map lock here to prevent GetNewOrUsed from trying
// to reuse a wrapper on one thread while it's being destroyed on another // to reuse a wrapper on one thread while it's being destroyed on another
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance(); XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
@ -264,6 +280,28 @@ nsXPCWrappedJS::GetJSObject(JSObject** aJSObj)
return NS_OK; return NS_OK;
} }
static bool
CheckMainThreadOnly(nsXPCWrappedJS *aWrapper)
{
if(aWrapper->IsMainThreadOnly())
return NS_IsMainThread();
nsCOMPtr<nsIClassInfo> ci;
CallQueryInterface(aWrapper, getter_AddRefs(ci));
if (ci) {
PRUint32 flags;
if (NS_SUCCEEDED(ci->GetFlags(&flags)) && !(flags & nsIClassInfo::MAIN_THREAD_ONLY))
return true;
if (!NS_IsMainThread())
return false;
}
aWrapper->SetIsMainThreadOnly();
return true;
}
// static // static
nsresult nsresult
nsXPCWrappedJS::GetNewOrUsed(XPCCallContext& ccx, nsXPCWrappedJS::GetNewOrUsed(XPCCallContext& ccx,
@ -317,7 +355,9 @@ nsXPCWrappedJS::GetNewOrUsed(XPCCallContext& ccx,
// the root will do double duty as the interface wrapper // the root will do double duty as the interface wrapper
wrapper = root = new nsXPCWrappedJS(ccx, aJSObj, clazz, nsnull, wrapper = root = new nsXPCWrappedJS(ccx, aJSObj, clazz, nsnull,
aOuter); aOuter);
if (root) if (!root)
goto return_wrapper;
{ // scoped lock { // scoped lock
#if DEBUG_xpc_leaks #if DEBUG_xpc_leaks
printf("Created nsXPCWrappedJS %p, JSObject is %p\n", printf("Created nsXPCWrappedJS %p, JSObject is %p\n",
@ -326,6 +366,14 @@ nsXPCWrappedJS::GetNewOrUsed(XPCCallContext& ccx,
XPCAutoLock lock(rt->GetMapLock()); XPCAutoLock lock(rt->GetMapLock());
map->Add(root); map->Add(root);
} }
if (!CheckMainThreadOnly(root)) {
XPCAutoLock lock(rt->GetMapLock());
map->Remove(root);
wrapper = NULL;
}
goto return_wrapper; goto return_wrapper;
} else { } else {
// just a root wrapper // just a root wrapper
@ -351,6 +399,13 @@ nsXPCWrappedJS::GetNewOrUsed(XPCCallContext& ccx,
XPCAutoLock lock(rt->GetMapLock()); XPCAutoLock lock(rt->GetMapLock());
map->Add(root); map->Add(root);
} }
if (!CheckMainThreadOnly(root)) {
XPCAutoLock lock(rt->GetMapLock());
map->Remove(root);
goto return_wrapper;
}
} }
} }
@ -395,7 +450,8 @@ nsXPCWrappedJS::nsXPCWrappedJS(XPCCallContext& ccx,
mRoot(root ? root : this), mRoot(root ? root : this),
mNext(nsnull), mNext(nsnull),
mOuter(root ? nsnull : aOuter), mOuter(root ? nsnull : aOuter),
mMainThread(NS_IsMainThread()) mMainThread(NS_IsMainThread()),
mMainThreadOnly(root && root->mMainThreadOnly)
{ {
#ifdef DEBUG_stats_jband #ifdef DEBUG_stats_jband
static int count = 0; static int count = 0;
@ -404,6 +460,8 @@ nsXPCWrappedJS::nsXPCWrappedJS(XPCCallContext& ccx,
printf("//////// %d instances of nsXPCWrappedJS created\n", count); printf("//////// %d instances of nsXPCWrappedJS created\n", count);
#endif #endif
JS_ASSERT_IF(mMainThreadOnly, mMainThread);
InitStub(GetClass()->GetIID()); InitStub(GetClass()->GetIID());
// intentionally do double addref - see Release(). // intentionally do double addref - see Release().

Просмотреть файл

@ -3036,6 +3036,9 @@ public:
JSBool IsAggregatedToNative() const {return mRoot->mOuter != nsnull;} JSBool IsAggregatedToNative() const {return mRoot->mOuter != nsnull;}
nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;} nsISupports* GetAggregatedNativeObject() const {return mRoot->mOuter;}
void SetIsMainThreadOnly() {JS_ASSERT(mMainThread); mMainThreadOnly = true;}
bool IsMainThreadOnly() const {return mMainThreadOnly;}
void TraceJS(JSTracer* trc); void TraceJS(JSTracer* trc);
#ifdef DEBUG #ifdef DEBUG
static void PrintTraceName(JSTracer* trc, char *buf, size_t bufsize); static void PrintTraceName(JSTracer* trc, char *buf, size_t bufsize);
@ -3059,6 +3062,7 @@ private:
nsXPCWrappedJS* mNext; nsXPCWrappedJS* mNext;
nsISupports* mOuter; // only set in root nsISupports* mOuter; // only set in root
bool mMainThread; bool mMainThread;
bool mMainThreadOnly;
}; };
/***************************************************************************/ /***************************************************************************/