Cleanup at shutdown the JSContexts that xpconnect manages on a per thread basis. This should fix some shutdown leaks.

This commit is contained in:
jband%netscape.com 2000-04-25 04:57:32 +00:00
parent d4388bb67f
commit 35d002f3fe
3 changed files with 124 additions and 24 deletions

View File

@ -176,6 +176,13 @@ nsXPConnect::nsXPConnect()
nsXPConnect::~nsXPConnect()
{
// Calling this Cleanup *before* doing the ShutDown stuff below is
// fairly aggressive. There is some danger that we could get into trouble
// With reentrancy into the xpconnect runtime as we are in the process of
// kiling it. But, this seems to be working. This call could be moved lower
// in this dtor (or commented out!) if problems develop.
xpcPerThreadData::CleanupAllThreads();
NS_IF_RELEASE(mArbitraryScriptable);
NS_IF_RELEASE(mInterfaceInfoManager);
NS_IF_RELEASE(mContextStack);

View File

@ -1348,8 +1348,8 @@ class xpcPerThreadData
public:
// Get the instance of this object for the current thread
static xpcPerThreadData* GetData();
static void CleanupAllThreads();
xpcPerThreadData();
~xpcPerThreadData();
nsIXPCException* GetException();
@ -1360,10 +1360,21 @@ public:
PRBool IsValid() const;
void Cleanup();
private:
nsIXPCException* mException;
nsDeque* mJSContextStack;
JSContext* mSafeJSContext;
xpcPerThreadData();
private:
nsIXPCException* mException;
nsDeque* mJSContextStack;
JSContext* mSafeJSContext;
xpcPerThreadData* mNextThread;
static PRLock* gLock;
static xpcPerThreadData* gThreads;
static PRUintn gTLSIndex;
};
/**************************************************************/
@ -1464,10 +1475,6 @@ extern JSBool
xpc_InstallJSDebuggerKeywordHandler(JSRuntime* rt);
/***************************************************************************/
// the include of declarations of the maps comes last because they have
// inlines which call methods on classes above.
#include "xpcmaps.h"
// Definition of nsScriptError, defined here because we lack a place to put
// XPCOM objects associated with the JavaScript engine.
@ -1493,4 +1500,11 @@ private:
nsCString mCategory;
};
/***************************************************************************/
// the include of declarations of the maps comes last because they have
// inlines which call methods on classes above.
#include "xpcmaps.h"
#endif /* xpcprivate_h___ */

View File

@ -187,21 +187,74 @@ nsXPCThreadJSContextStackImpl::GetSafeJSContext(JSContext * *aSafeJSContext)
/***************************************************************************/
static const PRUintn BAD_TLS_INDEX = (PRUintn) -1;
PRUintn xpcPerThreadData::gTLSIndex = BAD_TLS_INDEX;
PRLock* xpcPerThreadData::gLock = nsnull;
xpcPerThreadData* xpcPerThreadData::gThreads = nsnull;
xpcPerThreadData::xpcPerThreadData()
: mException(nsnull),
mJSContextStack(new nsDeque(nsnull)),
mSafeJSContext(nsnull)
mSafeJSContext(nsnull),
mNextThread(nsnull)
{
// empty...
if(gLock)
{
nsAutoLock lock(gLock);
mNextThread = gThreads;
gThreads = this;
}
}
void
xpcPerThreadData::Cleanup()
{
NS_IF_RELEASE(mException);
if(mJSContextStack)
{
delete mJSContextStack;
mJSContextStack = nsnull;
}
if(mSafeJSContext)
{
JS_DestroyContext(mSafeJSContext);
mSafeJSContext = nsnull;
}
}
xpcPerThreadData::~xpcPerThreadData()
{
NS_IF_RELEASE(mException);
if(mJSContextStack)
delete mJSContextStack;
if(mSafeJSContext)
JS_DestroyContext(mSafeJSContext);
Cleanup();
// Unlink 'this' from the list of threads.
if(gLock)
{
nsAutoLock lock(gLock);
if(gThreads == this)
gThreads = mNextThread;
else
{
xpcPerThreadData* cur = gThreads;
while(cur)
{
if(cur->mNextThread == this)
{
cur->mNextThread = mNextThread;
break;
}
cur = cur->mNextThread;
}
}
}
if(gLock && !gThreads)
{
PR_DestroyLock(gLock);
gLock = nsnull;
}
}
PRBool
@ -283,20 +336,32 @@ xpc_ThreadDataDtorCB(void* ptr)
xpcPerThreadData*
xpcPerThreadData::GetData()
{
static const PRUintn BAD_TLS_INDEX = (PRUintn) -1;
static PRUintn index = BAD_TLS_INDEX;
xpcPerThreadData* data;
if(index == BAD_TLS_INDEX)
if(!gLock)
{
if(PR_FAILURE == PR_NewThreadPrivateIndex(&index, xpc_ThreadDataDtorCB))
{
NS_ASSERTION(0, "PR_NewThreadPrivateIndex failed!");
index = BAD_TLS_INDEX;
gLock = PR_NewLock();
if(!gLock)
return nsnull;
}
if(gTLSIndex == BAD_TLS_INDEX)
{
nsAutoLock lock(gLock);
// check again now that we have the lock...
if(gTLSIndex == BAD_TLS_INDEX)
{
if(PR_FAILURE ==
PR_NewThreadPrivateIndex(&gTLSIndex, xpc_ThreadDataDtorCB))
{
NS_ASSERTION(0, "PR_NewThreadPrivateIndex failed!");
gTLSIndex = BAD_TLS_INDEX;
return nsnull;
}
}
}
data = (xpcPerThreadData*) PR_GetThreadPrivate(index);
data = (xpcPerThreadData*) PR_GetThreadPrivate(gTLSIndex);
if(!data)
{
data = new xpcPerThreadData();
@ -307,7 +372,7 @@ xpcPerThreadData::GetData()
delete data;
return nsnull;
}
if(PR_FAILURE == PR_SetThreadPrivate(index, data))
if(PR_FAILURE == PR_SetThreadPrivate(gTLSIndex, data))
{
NS_ASSERTION(0, "PR_SetThreadPrivate failed!");
delete data;
@ -316,3 +381,17 @@ xpcPerThreadData::GetData()
}
return data;
}
// static
void
xpcPerThreadData::CleanupAllThreads()
{
if(gLock)
{
nsAutoLock lock(gLock);
for(xpcPerThreadData* cur = gThreads; cur; cur = cur->mNextThread)
cur->Cleanup();
}
}