Fixing bug 410946. Prevent plugins from being destroyed while there's code from those plugins on the stack. r+sr=bzbarsky@mit.edu, a=beltzner@mozilla.com
git-svn-id: svn://10.0.0.236/trunk@246771 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -944,6 +944,8 @@ MakeNew4xStreamInternal(NPP npp, const char *relativeURL, const char *target,
|
||||
if (!npp)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
|
||||
|
||||
NS_ASSERTION(inst != NULL, "null instance");
|
||||
@@ -993,6 +995,8 @@ _geturl(NPP npp, const char* relativeURL, const char* target)
|
||||
("NPN_GetURL: npp=%p, target=%s, url=%s\n", (void *)npp, target,
|
||||
relativeURL));
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
// Block Adobe Acrobat from loading URLs that are not http:, https:,
|
||||
// or ftp: URLs if the given target is null.
|
||||
if (target == nsnull && relativeURL &&
|
||||
@@ -1022,6 +1026,8 @@ _geturlnotify(NPP npp, const char* relativeURL, const char* target,
|
||||
("NPN_GetURLNotify: npp=%p, target=%s, notify=%p, url=%s\n", (void*)npp,
|
||||
target, notifyData, relativeURL));
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
return MakeNew4xStreamInternal (npp, relativeURL, target,
|
||||
eNPPStreamTypeInternal_Get, PR_TRUE,
|
||||
notifyData);
|
||||
@@ -1039,6 +1045,8 @@ _posturlnotify(NPP npp, const char *relativeURL, const char *target,
|
||||
(void*)npp, target, len, file, notifyData, relativeURL,
|
||||
buf));
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
return MakeNew4xStreamInternal(npp, relativeURL, target,
|
||||
eNPPStreamTypeInternal_Post, PR_TRUE,
|
||||
notifyData, len, buf, file);
|
||||
@@ -1055,9 +1063,11 @@ _posturl(NPP npp, const char *relativeURL, const char *target,
|
||||
"buf=%s\n",
|
||||
(void*)npp, target, file, len, relativeURL, buf));
|
||||
|
||||
return MakeNew4xStreamInternal(npp, relativeURL, target,
|
||||
eNPPStreamTypeInternal_Post, PR_FALSE, nsnull,
|
||||
len, buf, file);
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
return MakeNew4xStreamInternal(npp, relativeURL, target,
|
||||
eNPPStreamTypeInternal_Post, PR_FALSE, nsnull,
|
||||
len, buf, file);
|
||||
}
|
||||
|
||||
|
||||
@@ -1121,6 +1131,9 @@ _newstream(NPP npp, NPMIMEType type, const char* target, NPStream* *result)
|
||||
NPError err = NPERR_INVALID_INSTANCE_ERROR;
|
||||
if (npp && npp->ndata) {
|
||||
nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
|
||||
|
||||
PluginDestructionGuard guard(inst);
|
||||
|
||||
nsCOMPtr<nsIOutputStream> stream;
|
||||
nsCOMPtr<nsIPluginInstancePeer> peer;
|
||||
if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) &&
|
||||
@@ -1154,6 +1167,8 @@ _write(NPP npp, NPStream *pstream, int32 len, void *buffer)
|
||||
if (!npp)
|
||||
return -1;
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
ns4xStreamWrapper* wrapper = (ns4xStreamWrapper*) pstream->ndata;
|
||||
NS_ASSERTION(wrapper != NULL, "null stream");
|
||||
|
||||
@@ -1185,6 +1200,8 @@ _destroystream(NPP npp, NPStream *pstream, NPError reason)
|
||||
if (!npp)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
nsCOMPtr<nsIPluginStreamListener> listener =
|
||||
do_QueryInterface((nsISupports *)pstream->ndata);
|
||||
|
||||
@@ -1229,6 +1246,8 @@ _status(NPP npp, const char *message)
|
||||
|
||||
nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
|
||||
|
||||
PluginDestructionGuard guard(inst);
|
||||
|
||||
nsCOMPtr<nsIPluginInstancePeer> peer;
|
||||
if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
|
||||
peer->ShowStatus(message);
|
||||
@@ -1287,6 +1306,8 @@ _invalidaterect(NPP npp, NPRect *invalidRect)
|
||||
|
||||
nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
|
||||
|
||||
PluginDestructionGuard guard(inst);
|
||||
|
||||
nsCOMPtr<nsIPluginInstancePeer> peer;
|
||||
if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
|
||||
nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
|
||||
@@ -1313,6 +1334,8 @@ _invalidateregion(NPP npp, NPRegion invalidRegion)
|
||||
|
||||
nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
|
||||
|
||||
PluginDestructionGuard guard(inst);
|
||||
|
||||
nsCOMPtr<nsIPluginInstancePeer> peer;
|
||||
if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
|
||||
nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
|
||||
@@ -1337,6 +1360,8 @@ _forceredraw(NPP npp)
|
||||
|
||||
nsIPluginInstance *inst = (nsIPluginInstance *) npp->ndata;
|
||||
|
||||
PluginDestructionGuard guard(inst);
|
||||
|
||||
nsCOMPtr<nsIPluginInstancePeer> peer;
|
||||
if (NS_SUCCEEDED(inst->GetPeer(getter_AddRefs(peer))) && peer) {
|
||||
nsCOMPtr<nsIWindowlessPluginInstancePeer> wpeer(do_QueryInterface(peer));
|
||||
@@ -1354,6 +1379,8 @@ GetDocumentFromNPP(NPP npp)
|
||||
ns4xPluginInstance *inst = (ns4xPluginInstance *)npp->ndata;
|
||||
NS_ENSURE_TRUE(inst, nsnull);
|
||||
|
||||
PluginDestructionGuard guard(inst);
|
||||
|
||||
nsCOMPtr<nsIPluginInstancePeer> pip;
|
||||
inst->GetPeer(getter_AddRefs(pip));
|
||||
nsCOMPtr<nsPIPluginInstancePeer> pp(do_QueryInterface(pip));
|
||||
@@ -1541,6 +1568,8 @@ _createobject(NPP npp, NPClass* aClass)
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
if (!aClass) {
|
||||
NS_ERROR("Null class passed to _createobject()!");
|
||||
|
||||
@@ -1562,6 +1591,9 @@ _createobject(NPP npp, NPClass* aClass)
|
||||
npobj->referenceCount = 1;
|
||||
}
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("Created NPObject %p, NPClass %p\n", npobj, aClass));
|
||||
|
||||
return npobj;
|
||||
}
|
||||
|
||||
@@ -1586,6 +1618,9 @@ _releaseobject(NPObject* npobj)
|
||||
if (refCnt == 0) {
|
||||
nsNPObjWrapper::OnDestroy(npobj);
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("Deleting NPObject %p, refcount hit 0\n", npobj));
|
||||
|
||||
if (npobj->_class && npobj->_class->deallocate) {
|
||||
npobj->_class->deallocate(npobj);
|
||||
} else {
|
||||
@@ -1601,9 +1636,15 @@ _invoke(NPP npp, NPObject* npobj, NPIdentifier method, const NPVariant *args,
|
||||
if (!npp || !npobj || !npobj->_class || !npobj->_class->invoke)
|
||||
return false;
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
NPPExceptionAutoHolder nppExceptionHolder;
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_Invoke(npp %p, npobj %p, method %p, args %d\n", npp,
|
||||
npobj, method, argCount));
|
||||
|
||||
return npobj->_class->invoke(npobj, method, args, argCount, result);
|
||||
}
|
||||
|
||||
@@ -1617,6 +1658,10 @@ _invokeDefault(NPP npp, NPObject* npobj, const NPVariant *args,
|
||||
NPPExceptionAutoHolder nppExceptionHolder;
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_InvokeDefault(npp %p, npobj %p, args %d\n", npp,
|
||||
npobj, argCount));
|
||||
|
||||
return npobj->_class->invokeDefault(npobj, args, argCount, result);
|
||||
}
|
||||
|
||||
@@ -1694,6 +1739,10 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
|
||||
}
|
||||
}
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_Evaluate(npp %p, npobj %p, script <<<%s>>>) called\n",
|
||||
npp, npobj, script->utf8characters));
|
||||
|
||||
nsresult rv = scx->EvaluateStringWithValue(utf16script, obj, principal,
|
||||
spec, 0, 0, rval, nsnull);
|
||||
|
||||
@@ -1711,6 +1760,10 @@ _getproperty(NPP npp, NPObject* npobj, NPIdentifier property,
|
||||
NPPExceptionAutoHolder nppExceptionHolder;
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_GetProperty(npp %p, npobj %p, property %p) called\n",
|
||||
npp, npobj, property));
|
||||
|
||||
return npobj->_class->getProperty(npobj, property, result);
|
||||
}
|
||||
|
||||
@@ -1724,6 +1777,10 @@ _setproperty(NPP npp, NPObject* npobj, NPIdentifier property,
|
||||
NPPExceptionAutoHolder nppExceptionHolder;
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_SetProperty(npp %p, npobj %p, property %p) called\n",
|
||||
npp, npobj, property));
|
||||
|
||||
return npobj->_class->setProperty(npobj, property, value);
|
||||
}
|
||||
|
||||
@@ -1736,6 +1793,10 @@ _removeproperty(NPP npp, NPObject* npobj, NPIdentifier property)
|
||||
NPPExceptionAutoHolder nppExceptionHolder;
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_RemoveProperty(npp %p, npobj %p, property %p) called\n",
|
||||
npp, npobj, property));
|
||||
|
||||
return npobj->_class->removeProperty(npobj, property);
|
||||
}
|
||||
|
||||
@@ -1748,6 +1809,10 @@ _hasproperty(NPP npp, NPObject* npobj, NPIdentifier propertyName)
|
||||
NPPExceptionAutoHolder nppExceptionHolder;
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_HasProperty(npp %p, npobj %p, property %p) called\n",
|
||||
npp, npobj, propertyName));
|
||||
|
||||
return npobj->_class->hasProperty(npobj, propertyName);
|
||||
}
|
||||
|
||||
@@ -1760,6 +1825,10 @@ _hasmethod(NPP npp, NPObject* npobj, NPIdentifier methodName)
|
||||
NPPExceptionAutoHolder nppExceptionHolder;
|
||||
NPPAutoPusher nppPusher(npp);
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_HasMethod(npp %p, npobj %p, property %p) called\n",
|
||||
npp, npobj, methodName));
|
||||
|
||||
return npobj->_class->hasProperty(npobj, methodName);
|
||||
}
|
||||
|
||||
@@ -1770,6 +1839,9 @@ _enumerate(NPP npp, NPObject *npobj, NPIdentifier **identifier,
|
||||
if (!npp || !npobj || !npobj->_class)
|
||||
return false;
|
||||
|
||||
NPN_PLUGIN_LOG(PLUGIN_LOG_NOISY,
|
||||
("NPN_Enumerate(npp %p, npobj %p) called\n", npp, npobj));
|
||||
|
||||
if (!NP_CLASS_STRUCT_VERSION_HAS_ENUM(npobj->_class) ||
|
||||
!npobj->_class->enumerate) {
|
||||
*identifier = 0;
|
||||
@@ -1896,6 +1968,8 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
|
||||
nsresult res;
|
||||
|
||||
PluginDestructionGuard guard(npp);
|
||||
|
||||
switch(variable) {
|
||||
#if defined(XP_UNIX) && !defined(XP_MACOSX)
|
||||
case NPNVxDisplay : {
|
||||
@@ -2110,6 +2184,8 @@ _setvalue(NPP npp, NPPVariable variable, void *result)
|
||||
if (inst == NULL)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
|
||||
PluginDestructionGuard guard(inst);
|
||||
|
||||
switch (variable) {
|
||||
|
||||
// we should keep backward compatibility with 4x where the
|
||||
@@ -2357,6 +2433,8 @@ NS_IMETHODIMP
|
||||
nsPluginThreadRunnable::Run()
|
||||
{
|
||||
if (mFunc) {
|
||||
PluginDestructionGuard guard(mInstance);
|
||||
|
||||
NS_TRY_SAFE_CALL_VOID(mFunc(mUserData), nsnull, nsnull);
|
||||
}
|
||||
|
||||
|
||||
@@ -280,11 +280,22 @@ protected:
|
||||
static NPP sCurrentNPP;
|
||||
};
|
||||
|
||||
class NPPAutoPusher : public NPPStack
|
||||
// XXXjst: The NPPAutoPusher stack is a bit redundant now that
|
||||
// PluginDestructionGuard exists, and could thus be replaced by code
|
||||
// that uses the PluginDestructionGuard list of plugins on the
|
||||
// stack. But they're not identical, and to minimize code changes
|
||||
// we're keeping both for the moment, and making NPPAutoPusher inherit
|
||||
// the PluginDestructionGuard class to avoid having to keep two
|
||||
// separate objects on the stack since we always want a
|
||||
// PluginDestructionGuard where we use an NPPAutoPusher.
|
||||
|
||||
class NPPAutoPusher : public NPPStack,
|
||||
protected PluginDestructionGuard
|
||||
{
|
||||
public:
|
||||
NPPAutoPusher(NPP npp)
|
||||
: mOldNPP(sCurrentNPP)
|
||||
: PluginDestructionGuard(npp),
|
||||
mOldNPP(sCurrentNPP)
|
||||
{
|
||||
NS_ASSERTION(npp, "Uh, null npp passed to NPPAutoPusher!");
|
||||
|
||||
|
||||
@@ -152,6 +152,8 @@ nsresult ns4xPluginStreamListener::CleanUpStream(NPReason reason)
|
||||
if(!mInst || !mInst->IsStarted())
|
||||
return rv;
|
||||
|
||||
PluginDestructionGuard guard(mInst);
|
||||
|
||||
const NPPluginFuncs *callbacks = nsnull;
|
||||
mInst->GetCallbacks(&callbacks);
|
||||
if(!callbacks)
|
||||
@@ -196,6 +198,8 @@ void ns4xPluginStreamListener::CallURLNotify(NPReason reason)
|
||||
if(!mCallNotify || !mInst || !mInst->IsStarted())
|
||||
return;
|
||||
|
||||
PluginDestructionGuard guard(mInst);
|
||||
|
||||
mCallNotify = PR_FALSE; // only do this ONCE and prevent recursion
|
||||
|
||||
const NPPluginFuncs *callbacks = nsnull;
|
||||
@@ -228,6 +232,8 @@ ns4xPluginStreamListener::OnStartBinding(nsIPluginStreamInfo* pluginInfo)
|
||||
if(!mInst)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PluginDestructionGuard guard(mInst);
|
||||
|
||||
NPP npp;
|
||||
const NPPluginFuncs *callbacks = nsnull;
|
||||
|
||||
@@ -390,6 +396,8 @@ ns4xPluginStreamListener::OnDataAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
if (!mInst || !mInst->IsStarted())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PluginDestructionGuard guard(mInst);
|
||||
|
||||
// Just in case the caller switches plugin info on us.
|
||||
mStreamInfo = pluginInfo;
|
||||
|
||||
@@ -661,6 +669,8 @@ ns4xPluginStreamListener::OnFileAvailable(nsIPluginStreamInfo* pluginInfo,
|
||||
if(!mInst || !mInst->IsStarted())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PluginDestructionGuard guard(mInst);
|
||||
|
||||
const NPPluginFuncs *callbacks = nsnull;
|
||||
mInst->GetCallbacks(&callbacks);
|
||||
if(!callbacks || !callbacks->asfile)
|
||||
@@ -908,6 +918,12 @@ NS_IMETHODIMP ns4xPluginInstance::Stop(void)
|
||||
if(!mStarted)
|
||||
return NS_OK;
|
||||
|
||||
// If there's code from this plugin instance on the stack, delay the
|
||||
// destroy.
|
||||
if (PluginDestructionGuard::DelayDestroy(this)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Make sure we lock while we're writing to mStarted after we've
|
||||
// started as other threads might be checking that inside a lock.
|
||||
EnterAsyncPluginThreadCallLock();
|
||||
@@ -985,6 +1001,8 @@ nsresult ns4xPluginInstance::InitializePlugin(nsIPluginInstancePeer* peer)
|
||||
nsCOMPtr<nsIPluginTagInfo2> taginfo = do_QueryInterface(peer);
|
||||
NS_ENSURE_TRUE(taginfo, NS_ERROR_NO_INTERFACE);
|
||||
|
||||
PluginDestructionGuard guard(this);
|
||||
|
||||
PRUint16 count = 0;
|
||||
const char* const* names = nsnull;
|
||||
const char* const* values = nsnull;
|
||||
@@ -1142,6 +1160,8 @@ NS_IMETHODIMP ns4xPluginInstance::SetWindow(nsPluginWindow* window)
|
||||
#endif // MOZ_WIDGET
|
||||
|
||||
if (fCallbacks->setwindow) {
|
||||
PluginDestructionGuard guard(this);
|
||||
|
||||
// XXX Turns out that NPPluginWindow and NPWindow are structurally
|
||||
// identical (on purpose!), so there's no need to make a copy.
|
||||
|
||||
@@ -1212,6 +1232,8 @@ NS_IMETHODIMP ns4xPluginInstance::Print(nsPluginPrint* platformPrint)
|
||||
{
|
||||
NS_ENSURE_TRUE(platformPrint, NS_ERROR_NULL_POINTER);
|
||||
|
||||
PluginDestructionGuard guard(this);
|
||||
|
||||
NPPrint* thePrint = (NPPrint *)platformPrint;
|
||||
|
||||
// to be compatible with the older SDK versions and to match what
|
||||
@@ -1264,6 +1286,8 @@ NS_IMETHODIMP ns4xPluginInstance::HandleEvent(nsPluginEvent* event, PRBool* hand
|
||||
if (event == nsnull)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
PluginDestructionGuard guard(this);
|
||||
|
||||
PRInt16 result = 0;
|
||||
|
||||
if (fCallbacks->event) {
|
||||
@@ -1302,6 +1326,7 @@ nsresult ns4xPluginInstance::GetValueInternal(NPPVariable variable, void* value)
|
||||
{
|
||||
nsresult res = NS_OK;
|
||||
if(fCallbacks->getvalue && mStarted) {
|
||||
PluginDestructionGuard guard(this);
|
||||
|
||||
NS_TRY_SAFE_CALL_RETURN(res,
|
||||
CallNPP_GetValueProc(fCallbacks->getvalue,
|
||||
|
||||
@@ -205,11 +205,8 @@ static const char *kPluginRegistryVersion = "0.08";
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// CID's && IID's
|
||||
static NS_DEFINE_IID(kIPluginInstanceIID, NS_IPLUGININSTANCE_IID);
|
||||
static NS_DEFINE_IID(kIPluginInstancePeerIID, NS_IPLUGININSTANCEPEER_IID);
|
||||
static NS_DEFINE_IID(kIPluginStreamInfoIID, NS_IPLUGINSTREAMINFO_IID);
|
||||
static NS_DEFINE_CID(kPluginCID, NS_PLUGIN_CID);
|
||||
static NS_DEFINE_IID(kIPluginTagInfo2IID, NS_IPLUGINTAGINFO2_IID);
|
||||
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
|
||||
static const char kDirectoryServiceContractID[] = "@mozilla.org/file/directory_service;1";
|
||||
// for the dialog
|
||||
static NS_DEFINE_CID(kCPluginManagerCID, NS_PLUGINMANAGER_CID); // needed for NS_TRY_SAFE_CALL
|
||||
@@ -6165,6 +6162,10 @@ nsPluginHostImpl::AddHeadersToChannel(const char *aHeadersData,
|
||||
NS_IMETHODIMP
|
||||
nsPluginHostImpl::StopPluginInstance(nsIPluginInstance* aInstance)
|
||||
{
|
||||
if (PluginDestructionGuard::DelayDestroy(aInstance)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("nsPluginHostImpl::StopPluginInstance called instance=%p\n",aInstance));
|
||||
|
||||
@@ -7183,3 +7184,124 @@ nsPluginStreamInfo::SetStreamComplete(const PRBool complete)
|
||||
SetRequest(nsnull);
|
||||
}
|
||||
}
|
||||
|
||||
// Runnable that does an async destroy of a plugin.
|
||||
|
||||
class nsPluginDestroyRunnable : public nsRunnable,
|
||||
public PRCList
|
||||
{
|
||||
public:
|
||||
nsPluginDestroyRunnable(nsIPluginInstance *aInstance)
|
||||
: mInstance(aInstance)
|
||||
{
|
||||
PR_INIT_CLIST(this);
|
||||
PR_APPEND_LINK(this, &sRunnableListHead);
|
||||
}
|
||||
|
||||
virtual ~nsPluginDestroyRunnable()
|
||||
{
|
||||
PR_REMOVE_LINK(this);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
nsCOMPtr<nsIPluginInstance> instance;
|
||||
|
||||
// Null out mInstance to make sure this code in another runnable
|
||||
// will do the right thing even if someone was holding on to this
|
||||
// runnable longer than we expect.
|
||||
instance.swap(mInstance);
|
||||
|
||||
if (PluginDestructionGuard::DelayDestroy(instance)) {
|
||||
// It's still not safe to destroy the plugin, it's now up to the
|
||||
// outermost guard on the stack to take care of the destruction.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsPluginDestroyRunnable *r =
|
||||
static_cast<nsPluginDestroyRunnable*>(PR_NEXT_LINK(&sRunnableListHead));
|
||||
|
||||
while (r != &sRunnableListHead) {
|
||||
if (r != this && r->mInstance == instance) {
|
||||
// There's another runnable scheduled to tear down
|
||||
// instance. Let it do the job.
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
r = static_cast<nsPluginDestroyRunnable*>
|
||||
(PR_NEXT_LINK(&sRunnableListHead));
|
||||
}
|
||||
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("Doing delayed destroy of instance %p\n", instance.get()));
|
||||
|
||||
instance->Stop();
|
||||
|
||||
nsRefPtr<nsPluginHostImpl> host = nsPluginHostImpl::GetInst();
|
||||
|
||||
if (host) {
|
||||
host->StopPluginInstance(instance);
|
||||
}
|
||||
|
||||
PLUGIN_LOG(PLUGIN_LOG_NORMAL,
|
||||
("Done with delayed destroy of instance %p\n", instance.get()));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIPluginInstance> mInstance;
|
||||
|
||||
static PRCList sRunnableListHead;
|
||||
};
|
||||
|
||||
PRCList nsPluginDestroyRunnable::sRunnableListHead =
|
||||
PR_INIT_STATIC_CLIST(&nsPluginDestroyRunnable::sRunnableListHead);
|
||||
|
||||
PRCList PluginDestructionGuard::sListHead =
|
||||
PR_INIT_STATIC_CLIST(&PluginDestructionGuard::sListHead);
|
||||
|
||||
PluginDestructionGuard::~PluginDestructionGuard()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
|
||||
|
||||
PR_REMOVE_LINK(this);
|
||||
|
||||
if (mDelayedDestroy) {
|
||||
// We've attempted to destroy the plugin instance we're holding on
|
||||
// to while we were guarding it. Do the actual destroy now, off of
|
||||
// a runnable.
|
||||
nsRefPtr<nsPluginDestroyRunnable> evt =
|
||||
new nsPluginDestroyRunnable(mInstance);
|
||||
|
||||
NS_DispatchToMainThread(evt);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
PRBool
|
||||
PluginDestructionGuard::DelayDestroy(nsIPluginInstance *aInstance)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
|
||||
NS_ASSERTION(aInstance, "Uh, I need an instance!");
|
||||
|
||||
// Find the first guard on the stack and make it do a delayed
|
||||
// destroy upon destruction.
|
||||
|
||||
PluginDestructionGuard *g =
|
||||
static_cast<PluginDestructionGuard*>(PR_LIST_HEAD(&sListHead));
|
||||
|
||||
while (g != &sListHead) {
|
||||
if (g->mInstance == aInstance) {
|
||||
g->mDelayedDestroy = PR_TRUE;
|
||||
|
||||
return PR_TRUE;
|
||||
}
|
||||
|
||||
g = static_cast<PluginDestructionGuard*>(PR_NEXT_LINK(g));
|
||||
}
|
||||
|
||||
return PR_FALSE;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
#include "nsCRT.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "prlink.h"
|
||||
#include "prclist.h"
|
||||
#include "npapi.h"
|
||||
#include "ns4xPluginInstance.h"
|
||||
|
||||
#include "nsIPlugin.h"
|
||||
#include "nsIPluginTag.h"
|
||||
@@ -64,6 +67,7 @@
|
||||
#include "nsPluginNativeWindow.h"
|
||||
#include "nsIPrefBranch.h"
|
||||
#include "nsWeakReference.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
// XXX this file really doesn't think this is possible, but ...
|
||||
#include "nsIFactory.h"
|
||||
@@ -459,4 +463,40 @@ private:
|
||||
static nsPluginHostImpl* sInst;
|
||||
};
|
||||
|
||||
class PluginDestructionGuard : protected PRCList
|
||||
{
|
||||
public:
|
||||
PluginDestructionGuard(nsIPluginInstance *aInstance)
|
||||
: mInstance(aInstance)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
PluginDestructionGuard(NPP npp)
|
||||
: mInstance(npp ? static_cast<ns4xPluginInstance*>(npp->ndata) : nsnull)
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
~PluginDestructionGuard();
|
||||
|
||||
static PRBool DelayDestroy(nsIPluginInstance *aInstance);
|
||||
|
||||
protected:
|
||||
void Init()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
|
||||
|
||||
mDelayedDestroy = PR_FALSE;
|
||||
|
||||
PR_INIT_CLIST(this);
|
||||
PR_INSERT_BEFORE(this, &sListHead);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPluginInstance> mInstance;
|
||||
PRBool mDelayedDestroy;
|
||||
|
||||
static PRCList sListHead;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user