diff --git a/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp b/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp index db65ea369eb..10cb47cf604 100644 --- a/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp +++ b/mozilla/modules/plugin/base/src/nsPluginHostImpl.cpp @@ -299,14 +299,14 @@ void DisplayNoDefaultPluginDialog(const char *mimeType) return; } -nsActivePlugin::nsActivePlugin(nsCOMPtr aPlugin, +nsActivePlugin::nsActivePlugin(nsPluginTag* aPluginTag, nsIPluginInstance* aInstance, char * url, PRBool aDefaultPlugin) { mNext = nsnull; mPeer = nsnull; - mPlugin = aPlugin; + mPluginTag = aPluginTag; mURL = PL_strdup(url); mInstance = aInstance; @@ -323,7 +323,7 @@ nsActivePlugin::nsActivePlugin(nsCOMPtr aPlugin, nsActivePlugin::~nsActivePlugin() { - mPlugin = nsnull; + mPluginTag = nsnull; if(mInstance != nsnull) { mInstance->Destroy(); @@ -364,7 +364,11 @@ void nsActivePluginList::shut() for(nsActivePlugin * plugin = mFirst; plugin != nsnull;) { nsActivePlugin * next = plugin->mNext; - remove(plugin); + + PRBool unloadLibLater = PR_FALSE; + remove(plugin, &unloadLibLater); + NS_ASSERTION(!unloadLibLater, "Plugin doesn't want to be unloaded"); + plugin = next; } mFirst = nsnull; @@ -394,15 +398,18 @@ PRBool nsActivePluginList::IsLastInstance(nsActivePlugin * plugin) if(!plugin) return PR_FALSE; + if(!plugin->mPluginTag) + return PR_FALSE; + for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext) { - if((p->mPlugin.get() == plugin->mPlugin.get()) && (p != plugin)) + if((p->mPluginTag == plugin->mPluginTag) && (p != plugin)) return PR_FALSE; } return PR_TRUE; } -PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * lastInstance) +PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * aUnloadLibraryLater) { if(mFirst == nsnull) return PR_FALSE; @@ -412,6 +419,8 @@ PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * lastInstance { if(p == plugin) { + PRBool lastInstance = IsLastInstance(p); + if(p == mFirst) mFirst = p->mNext; else @@ -421,19 +430,32 @@ PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * lastInstance mLast = prev; // see if this is going to be the last instance of a plugin - PRBool lastinst = IsLastInstance(p); - + // if so we should perform nsIPlugin::Shutdown and unload the library + // by calling nsPluginTag::TryUnloadPlugin() if(lastInstance) - *lastInstance = lastinst; - - if(lastinst) { - nsIPlugin *nsiplugin = p->mPlugin.get(); + // cache some things as we are going to destroy it right now + nsPluginTag *pluginTag = p->mPluginTag; delete p; // plugin instance is destroyed here - if(nsiplugin) - nsiplugin->Shutdown(); + if(pluginTag) + { + // xpconnected plugins from the old world should postpone unloading library + // to avoid crash check, if so add library to the list of unloaded libraries + if(pluginTag->mXPConnected && (pluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL)) + { + pluginTag->mCanUnloadLibrary = PR_FALSE; + + if(aUnloadLibraryLater) + *aUnloadLibraryLater = PR_TRUE; + } + + pluginTag->TryUnloadPlugin(); + } + else + NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown"); + } else delete p; @@ -467,7 +489,6 @@ void nsActivePluginList::removeAllStopped() if(mFirst == nsnull) return; - nsActivePlugin * prev = nsnull; nsActivePlugin * next = nsnull; for(nsActivePlugin * p = mFirst; p != nsnull;) @@ -476,20 +497,12 @@ void nsActivePluginList::removeAllStopped() if(p->mStopped) { - if(p == mFirst) - mFirst = next; - else - prev->mNext = next; - - if(p == mLast) - mLast = prev; - - delete p; - mCount--; - p = next; - continue; + // we don't care about unloading library problem for + // plugins that are already in the 'stop' state + PRBool unloadLibLater = PR_FALSE; + remove(p, &unloadLibLater); } - prev = p; + p = next; } return; @@ -602,12 +615,12 @@ nsActivePlugin * nsActivePluginList::findOldestStopped() return res; } -nsUnloadedLibrary::nsUnloadedLibrary(PRLibrary * aLibrary) +nsUnusedLibrary::nsUnusedLibrary(PRLibrary * aLibrary) { mLibrary = aLibrary; } -nsUnloadedLibrary::~nsUnloadedLibrary() +nsUnusedLibrary::~nsUnusedLibrary() { if(mLibrary) PR_UnloadLibrary(mLibrary); @@ -626,6 +639,7 @@ nsPluginTag::nsPluginTag() mCanUnloadLibrary = PR_TRUE; mEntryPoint = nsnull; mFlags = NS_PLUGIN_FLAG_ENABLED; + mXPConnected = PR_FALSE; mFileName = nsnull; } @@ -676,6 +690,7 @@ nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag) mCanUnloadLibrary = PR_TRUE; mEntryPoint = nsnull; mFlags = NS_PLUGIN_FLAG_ENABLED; + mXPConnected = PR_FALSE; mFileName = new_str(aPluginTag->mFileName); } @@ -717,6 +732,7 @@ nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo) mCanUnloadLibrary = PR_TRUE; mEntryPoint = nsnull; mFlags = NS_PLUGIN_FLAG_ENABLED; + mXPConnected = PR_FALSE; } @@ -735,7 +751,9 @@ nsPluginTag::nsPluginTag(const char* aName, mLibrary(nsnull), mCanUnloadLibrary(PR_TRUE), mEntryPoint(nsnull), - mFlags(0) + mFlags(0), + mXPConnected(PR_FALSE) + { mName = new_str(aName); mDescription = new_str(aDescription); @@ -756,7 +774,7 @@ nsPluginTag::nsPluginTag(const char* aName, nsPluginTag::~nsPluginTag() { - NS_IF_RELEASE(mEntryPoint); + TryUnloadPlugin(); if (nsnull != mName) { delete[] (mName); @@ -792,13 +810,6 @@ nsPluginTag::~nsPluginTag() mExtensionsArray = nsnull; } - if ((nsnull != mLibrary) && mCanUnloadLibrary) - { - // before we unload check if we are allowed to, see bug #61388 - PR_UnloadLibrary(mLibrary); - mLibrary = nsnull; - } - if(nsnull != mFileName) { delete [] mFileName; @@ -806,6 +817,26 @@ nsPluginTag::~nsPluginTag() } } +void nsPluginTag::TryUnloadPlugin() +{ + if (mEntryPoint) + { + mEntryPoint->Shutdown(); + mEntryPoint->Release(); + mEntryPoint = nsnull; + } + + // before we unload check if we are allowed to, see bug #61388 + if (mLibrary && mCanUnloadLibrary) + PR_UnloadLibrary(mLibrary); + + // we should zero it anyway, it is going to be unloaded by + // CleanUnsedLibraries before we need to call the library + // again so the calling code should not be fooled and reload + // the library fresh + mLibrary = nsnull; +} + class nsPluginStreamInfo : public nsIPluginStreamInfo { public: @@ -1705,7 +1736,7 @@ nsPluginHostImpl::nsPluginHostImpl() mPluginsLoaded = PR_FALSE; mDontShowBadPluginMessage = PR_FALSE; mIsDestroyed = PR_FALSE; - mUnloadedLibraries = nsnull; + mUnusedLibraries = nsnull; nsCOMPtr obsService = do_GetService(NS_OBSERVERSERVICE_CONTRACTID); if (obsService) @@ -1798,31 +1829,40 @@ PRBool nsPluginHostImpl::IsRunningPlugin(nsPluginTag * plugin) return PR_FALSE; } -// this will unload loaded but no longer needed libs which are -// gathered in mUnloadedLibraries list, see bug #61388 -void nsPluginHostImpl::CleanUnloadedLibraries() +void nsPluginHostImpl::AddToUnusedLibraryList(PRLibrary * aLibrary) { - if(!mUnloadedLibraries) + NS_ASSERTION(aLibrary, "nsPluginHostImpl::AddToUnusedLibraryList: Nothing to add"); + if(!aLibrary) return; - while (nsnull != mUnloadedLibraries) + nsUnusedLibrary * unusedLibrary = new nsUnusedLibrary(aLibrary); + if(unusedLibrary) { - nsUnloadedLibrary *temp = mUnloadedLibraries->mNext; - delete mUnloadedLibraries; - mUnloadedLibraries = temp; + unusedLibrary->mNext = mUnusedLibraries; + mUnusedLibraries = unusedLibrary; + } +} + +// this will unload loaded but no longer needed libs which are +// gathered in mUnusedLibraries list, see bug #61388 +void nsPluginHostImpl::CleanUnusedLibraries() +{ + if(!mUnusedLibraries) + return; + + while (nsnull != mUnusedLibraries) + { + nsUnusedLibrary *temp = mUnusedLibraries->mNext; + delete mUnusedLibraries; + mUnusedLibraries = temp; } } nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages) { - // XXX don't we want to nuke the old mPlugins right now? - // we should. Otherwise LoadPlugins will add the same plugins to the list - // XXX for new-style plugins, we should also call nsIComponentManager::AutoRegister() - // we are re-scanning plugins. New plugins may have been added, also some // plugins may have been removed, so we should probably shut everything down // but don't touch running (active and not stopped) plugins - if(reloadPages) { // if we have currently running plugins we should set a flag not to @@ -1830,15 +1870,10 @@ nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages) // and form a list of libs to be unloaded later for(nsPluginTag * p = mPlugins; p != nsnull; p = p->mNext) { - if(IsRunningPlugin(p)) + if(IsRunningPlugin(p) && (p->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL)) { p->mCanUnloadLibrary = PR_FALSE; - nsUnloadedLibrary * unloadedLibrary = new nsUnloadedLibrary(p->mLibrary); - if(unloadedLibrary) - { - unloadedLibrary->mNext = mUnloadedLibraries; - mUnloadedLibraries = unloadedLibrary; - } + AddToUnusedLibraryList(p->mLibrary); } } @@ -1864,9 +1899,6 @@ nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages) else prev->mNext = next; - if(p->mEntryPoint) - p->mEntryPoint->Shutdown(); - delete p; p = next; continue; @@ -2393,26 +2425,17 @@ NS_IMETHODIMP nsPluginHostImpl::Destroy(void) { nsPluginTag *temp = mPlugins->mNext; - // while walking through the list of the plugins see if we still have anything to shutdown - // some plugins may have never created an instance but still expect a shutdown call - // see bugzilla bug 73071 - if(mPlugins->mEntryPoint != nsnull) - { - mPlugins->mEntryPoint->Shutdown(); - mPlugins->mEntryPoint = nsnull; - } - - if ((nsnull != mPlugins->mLibrary) && mPlugins->mCanUnloadLibrary) - { - PR_UnloadLibrary(mPlugins->mLibrary); - mPlugins->mLibrary = nsnull; - } + // while walking through the list of the plugins see if we still have anything + // to shutdown some plugins may have never created an instance but still expect + // the shutdown call see bugzilla bug 73071 + // with current logic, no need to do anything special as nsIPlugin::Shutdown + // will be performed in the destructor delete mPlugins; mPlugins = temp; } - CleanUnloadedLibraries(); + CleanUnusedLibraries(); return NS_OK; } @@ -2706,10 +2729,6 @@ void nsPluginHostImpl::AddInstanceToActiveList(nsCOMPtr aPlugin, PRBool aDefaultPlugin) { - // first, determine if the plugin wants to be cached - // Code moved to StopPluginInstance as we still need running - // plugins to be present in the 'active' list - char* url; if(!aURL) @@ -2717,7 +2736,30 @@ void nsPluginHostImpl::AddInstanceToActiveList(nsCOMPtr aPlugin, (void)aURL->GetSpec(&url); - nsActivePlugin * plugin = new nsActivePlugin(aPlugin, aInstance, url, aDefaultPlugin); + // find corresponding plugin tag + // this is legal for xpcom plugins not to have nsIPlugin implemented + nsPluginTag * pluginTag = nsnull; + if(aPlugin) + { + for(pluginTag = mPlugins; pluginTag != nsnull; pluginTag = pluginTag->mNext) + { + if(pluginTag->mEntryPoint == aPlugin) + break; + } + NS_ASSERTION(pluginTag, "Plugin tag not found"); + } + else + { + // we don't need it for xpcom plugins because the only purpose to have it + // is to be able to postpone unloading library dll in some circumstances + // which we don't do for xpcom plugins. In case we need it in the future + // we can probably use the following + /* + FindPluginEnabledForType(mimetype, pluginTag); + */ + } + + nsActivePlugin * plugin = new nsActivePlugin(pluginTag, aInstance, url, aDefaultPlugin); if(plugin == nsnull) return; @@ -3233,7 +3275,7 @@ NS_IMETHODIMP nsPluginHostImpl::GetPluginFactory(const char *aMimeType, nsIPlugi return NS_ERROR_ILLEGAL_VALUE; // unload any libs that can remain after plugins.refresh(1), see #61388 - CleanUnloadedLibraries(); + CleanUnusedLibraries(); // If plugins haven't been scanned yet, do so now LoadPlugins(); @@ -4130,42 +4172,25 @@ nsPluginHostImpl::StopPluginInstance(nsIPluginInstance* aInstance) aInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache); // we also do that for 4x plugin, shall we? Let's see if it is - nsPluginTag * pluginTag = nsnull; - PRBool oldSchool = PR_FALSE; - for(pluginTag = mPlugins; pluginTag != nsnull; pluginTag = pluginTag->mNext) - { - if(pluginTag->mEntryPoint == plugin->mPlugin) - { - oldSchool = pluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL ? PR_TRUE : PR_FALSE; - break; - } - } + PRBool oldSchool = PR_TRUE; + if(plugin->mPluginTag) + oldSchool = plugin->mPluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL ? PR_TRUE : PR_FALSE; if (!doCache || oldSchool) - { - PRBool lastInstance = PR_FALSE; - PRBool xpConnected = plugin->mXPConnected; - - mActivePluginList.remove(plugin, &lastInstance); - - // and if this was the last instance we should unload the library - // and clear mEntryPoint and mLibrary member of the pluginTag - if(lastInstance) { - pluginTag->mEntryPoint = nsnull; + PRLibrary * library = plugin->mPluginTag->mLibrary; - if(xpConnected) - pluginTag->mCanUnloadLibrary = PR_FALSE; + PRBool unloadLibLater = PR_FALSE; + mActivePluginList.remove(plugin, &unloadLibLater); - if ((nsnull != pluginTag->mLibrary) && pluginTag->mCanUnloadLibrary) - { - PR_UnloadLibrary(pluginTag->mLibrary); - pluginTag->mLibrary = nsnull; + if(unloadLibLater) + AddToUnusedLibraryList(library); } - } - } else { + // if it is allowed to be cached simply stop it, but first we should check + // if we haven't exceeded the maximum allowed number of cached instances + // try to get the max cached plugins from a pref or use default PRUint32 max_num; nsresult rv; @@ -4177,8 +4202,17 @@ nsPluginHostImpl::StopPluginInstance(nsIPluginInstance* aInstance) { nsActivePlugin * oldest = mActivePluginList.findOldestStopped(); if(oldest != nsnull) - mActivePluginList.remove(oldest); + { + PRLibrary * library = oldest->mPluginTag->mLibrary; + + PRBool unloadLibLater = PR_FALSE; + mActivePluginList.remove(oldest, &unloadLibLater); + + if(unloadLibLater) + AddToUnusedLibraryList(library); + } } + plugin->setStopped(PR_TRUE); } } @@ -4372,6 +4406,9 @@ nsPluginHostImpl::SetIsScriptableInstance(nsCOMPtr aPluginIns return NS_ERROR_FAILURE; p->mXPConnected = aScriptable; + if(p->mPluginTag) + p->mPluginTag->mXPConnected = aScriptable; + return NS_OK; } diff --git a/mozilla/modules/plugin/base/src/nsPluginHostImpl.h b/mozilla/modules/plugin/base/src/nsPluginHostImpl.h index 45d8b93f31a..852957a7e75 100644 --- a/mozilla/modules/plugin/base/src/nsPluginHostImpl.h +++ b/mozilla/modules/plugin/base/src/nsPluginHostImpl.h @@ -64,6 +64,8 @@ public: ~nsPluginTag(); + void TryUnloadPlugin(); + nsPluginTag *mNext; char *mName; char *mDescription; @@ -75,6 +77,7 @@ public: PRBool mCanUnloadLibrary; nsIPlugin *mEntryPoint; PRUint32 mFlags; + PRBool mXPConnected; char *mFileName; }; @@ -83,14 +86,14 @@ struct nsActivePlugin nsActivePlugin* mNext; char* mURL; nsIPluginInstancePeer* mPeer; - nsCOMPtr mPlugin; + nsPluginTag* mPluginTag; nsIPluginInstance* mInstance; PRBool mStopped; PRTime mllStopTime; PRBool mDefaultPlugin; PRBool mXPConnected; - nsActivePlugin(nsCOMPtr aPlugin, + nsActivePlugin(nsPluginTag* aPluginTag, nsIPluginInstance* aInstance, char * url, PRBool aDefaultPlugin); @@ -111,7 +114,7 @@ public: void shut(); PRBool add(nsActivePlugin * plugin); - PRBool remove(nsActivePlugin * plugin, PRBool * lastInstance = nsnull); + PRBool remove(nsActivePlugin * plugin, PRBool * aUnloadLibraryLater); nsActivePlugin * find(nsIPluginInstance* instance); nsActivePlugin * find(char * mimetype); nsActivePlugin * findStopped(char * url); @@ -126,17 +129,16 @@ public: // we need to keep some libs in memory when we destroy mPlugins list // during refresh with reload if the plugin is currently running // on the page. They should be unloaded later, see bug #61388 -// The list is only created during plugins.refresh(1) and should -// go away when we hit a page with a plugin again. It should not -// exist under any other circumstances -class nsUnloadedLibrary +// There could also be other reasons to have this list. XPConnected +// plugins e.g. may still be held at the time we normally unload the library +class nsUnusedLibrary { public: - nsUnloadedLibrary *mNext; + nsUnusedLibrary *mNext; PRLibrary *mLibrary; - nsUnloadedLibrary(PRLibrary * aLibrary); - ~nsUnloadedLibrary(); + nsUnusedLibrary(PRLibrary * aLibrary); + ~nsUnusedLibrary(); }; #define NS_PLUGIN_FLAG_ENABLED 0x0001 //is this plugin enabled? @@ -406,7 +408,8 @@ private: PRBool checkForUnwantedPlugins = PR_FALSE); PRBool IsRunningPlugin(nsPluginTag * plugin); - void CleanUnloadedLibraries(); + void AddToUnusedLibraryList(PRLibrary * aLibrary); + void CleanUnusedLibraries(); char *mPluginPath; nsPluginTag *mPlugins; @@ -415,7 +418,7 @@ private: PRBool mIsDestroyed; nsActivePluginList mActivePluginList; - nsUnloadedLibrary *mUnloadedLibraries; + nsUnusedLibrary *mUnusedLibraries; }; #endif diff --git a/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.cpp b/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.cpp index db65ea369eb..10cb47cf604 100644 --- a/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.cpp +++ b/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.cpp @@ -299,14 +299,14 @@ void DisplayNoDefaultPluginDialog(const char *mimeType) return; } -nsActivePlugin::nsActivePlugin(nsCOMPtr aPlugin, +nsActivePlugin::nsActivePlugin(nsPluginTag* aPluginTag, nsIPluginInstance* aInstance, char * url, PRBool aDefaultPlugin) { mNext = nsnull; mPeer = nsnull; - mPlugin = aPlugin; + mPluginTag = aPluginTag; mURL = PL_strdup(url); mInstance = aInstance; @@ -323,7 +323,7 @@ nsActivePlugin::nsActivePlugin(nsCOMPtr aPlugin, nsActivePlugin::~nsActivePlugin() { - mPlugin = nsnull; + mPluginTag = nsnull; if(mInstance != nsnull) { mInstance->Destroy(); @@ -364,7 +364,11 @@ void nsActivePluginList::shut() for(nsActivePlugin * plugin = mFirst; plugin != nsnull;) { nsActivePlugin * next = plugin->mNext; - remove(plugin); + + PRBool unloadLibLater = PR_FALSE; + remove(plugin, &unloadLibLater); + NS_ASSERTION(!unloadLibLater, "Plugin doesn't want to be unloaded"); + plugin = next; } mFirst = nsnull; @@ -394,15 +398,18 @@ PRBool nsActivePluginList::IsLastInstance(nsActivePlugin * plugin) if(!plugin) return PR_FALSE; + if(!plugin->mPluginTag) + return PR_FALSE; + for(nsActivePlugin * p = mFirst; p != nsnull; p = p->mNext) { - if((p->mPlugin.get() == plugin->mPlugin.get()) && (p != plugin)) + if((p->mPluginTag == plugin->mPluginTag) && (p != plugin)) return PR_FALSE; } return PR_TRUE; } -PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * lastInstance) +PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * aUnloadLibraryLater) { if(mFirst == nsnull) return PR_FALSE; @@ -412,6 +419,8 @@ PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * lastInstance { if(p == plugin) { + PRBool lastInstance = IsLastInstance(p); + if(p == mFirst) mFirst = p->mNext; else @@ -421,19 +430,32 @@ PRBool nsActivePluginList::remove(nsActivePlugin * plugin, PRBool * lastInstance mLast = prev; // see if this is going to be the last instance of a plugin - PRBool lastinst = IsLastInstance(p); - + // if so we should perform nsIPlugin::Shutdown and unload the library + // by calling nsPluginTag::TryUnloadPlugin() if(lastInstance) - *lastInstance = lastinst; - - if(lastinst) { - nsIPlugin *nsiplugin = p->mPlugin.get(); + // cache some things as we are going to destroy it right now + nsPluginTag *pluginTag = p->mPluginTag; delete p; // plugin instance is destroyed here - if(nsiplugin) - nsiplugin->Shutdown(); + if(pluginTag) + { + // xpconnected plugins from the old world should postpone unloading library + // to avoid crash check, if so add library to the list of unloaded libraries + if(pluginTag->mXPConnected && (pluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL)) + { + pluginTag->mCanUnloadLibrary = PR_FALSE; + + if(aUnloadLibraryLater) + *aUnloadLibraryLater = PR_TRUE; + } + + pluginTag->TryUnloadPlugin(); + } + else + NS_ASSERTION(pluginTag, "pluginTag was not set, plugin not shutdown"); + } else delete p; @@ -467,7 +489,6 @@ void nsActivePluginList::removeAllStopped() if(mFirst == nsnull) return; - nsActivePlugin * prev = nsnull; nsActivePlugin * next = nsnull; for(nsActivePlugin * p = mFirst; p != nsnull;) @@ -476,20 +497,12 @@ void nsActivePluginList::removeAllStopped() if(p->mStopped) { - if(p == mFirst) - mFirst = next; - else - prev->mNext = next; - - if(p == mLast) - mLast = prev; - - delete p; - mCount--; - p = next; - continue; + // we don't care about unloading library problem for + // plugins that are already in the 'stop' state + PRBool unloadLibLater = PR_FALSE; + remove(p, &unloadLibLater); } - prev = p; + p = next; } return; @@ -602,12 +615,12 @@ nsActivePlugin * nsActivePluginList::findOldestStopped() return res; } -nsUnloadedLibrary::nsUnloadedLibrary(PRLibrary * aLibrary) +nsUnusedLibrary::nsUnusedLibrary(PRLibrary * aLibrary) { mLibrary = aLibrary; } -nsUnloadedLibrary::~nsUnloadedLibrary() +nsUnusedLibrary::~nsUnusedLibrary() { if(mLibrary) PR_UnloadLibrary(mLibrary); @@ -626,6 +639,7 @@ nsPluginTag::nsPluginTag() mCanUnloadLibrary = PR_TRUE; mEntryPoint = nsnull; mFlags = NS_PLUGIN_FLAG_ENABLED; + mXPConnected = PR_FALSE; mFileName = nsnull; } @@ -676,6 +690,7 @@ nsPluginTag::nsPluginTag(nsPluginTag* aPluginTag) mCanUnloadLibrary = PR_TRUE; mEntryPoint = nsnull; mFlags = NS_PLUGIN_FLAG_ENABLED; + mXPConnected = PR_FALSE; mFileName = new_str(aPluginTag->mFileName); } @@ -717,6 +732,7 @@ nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo) mCanUnloadLibrary = PR_TRUE; mEntryPoint = nsnull; mFlags = NS_PLUGIN_FLAG_ENABLED; + mXPConnected = PR_FALSE; } @@ -735,7 +751,9 @@ nsPluginTag::nsPluginTag(const char* aName, mLibrary(nsnull), mCanUnloadLibrary(PR_TRUE), mEntryPoint(nsnull), - mFlags(0) + mFlags(0), + mXPConnected(PR_FALSE) + { mName = new_str(aName); mDescription = new_str(aDescription); @@ -756,7 +774,7 @@ nsPluginTag::nsPluginTag(const char* aName, nsPluginTag::~nsPluginTag() { - NS_IF_RELEASE(mEntryPoint); + TryUnloadPlugin(); if (nsnull != mName) { delete[] (mName); @@ -792,13 +810,6 @@ nsPluginTag::~nsPluginTag() mExtensionsArray = nsnull; } - if ((nsnull != mLibrary) && mCanUnloadLibrary) - { - // before we unload check if we are allowed to, see bug #61388 - PR_UnloadLibrary(mLibrary); - mLibrary = nsnull; - } - if(nsnull != mFileName) { delete [] mFileName; @@ -806,6 +817,26 @@ nsPluginTag::~nsPluginTag() } } +void nsPluginTag::TryUnloadPlugin() +{ + if (mEntryPoint) + { + mEntryPoint->Shutdown(); + mEntryPoint->Release(); + mEntryPoint = nsnull; + } + + // before we unload check if we are allowed to, see bug #61388 + if (mLibrary && mCanUnloadLibrary) + PR_UnloadLibrary(mLibrary); + + // we should zero it anyway, it is going to be unloaded by + // CleanUnsedLibraries before we need to call the library + // again so the calling code should not be fooled and reload + // the library fresh + mLibrary = nsnull; +} + class nsPluginStreamInfo : public nsIPluginStreamInfo { public: @@ -1705,7 +1736,7 @@ nsPluginHostImpl::nsPluginHostImpl() mPluginsLoaded = PR_FALSE; mDontShowBadPluginMessage = PR_FALSE; mIsDestroyed = PR_FALSE; - mUnloadedLibraries = nsnull; + mUnusedLibraries = nsnull; nsCOMPtr obsService = do_GetService(NS_OBSERVERSERVICE_CONTRACTID); if (obsService) @@ -1798,31 +1829,40 @@ PRBool nsPluginHostImpl::IsRunningPlugin(nsPluginTag * plugin) return PR_FALSE; } -// this will unload loaded but no longer needed libs which are -// gathered in mUnloadedLibraries list, see bug #61388 -void nsPluginHostImpl::CleanUnloadedLibraries() +void nsPluginHostImpl::AddToUnusedLibraryList(PRLibrary * aLibrary) { - if(!mUnloadedLibraries) + NS_ASSERTION(aLibrary, "nsPluginHostImpl::AddToUnusedLibraryList: Nothing to add"); + if(!aLibrary) return; - while (nsnull != mUnloadedLibraries) + nsUnusedLibrary * unusedLibrary = new nsUnusedLibrary(aLibrary); + if(unusedLibrary) { - nsUnloadedLibrary *temp = mUnloadedLibraries->mNext; - delete mUnloadedLibraries; - mUnloadedLibraries = temp; + unusedLibrary->mNext = mUnusedLibraries; + mUnusedLibraries = unusedLibrary; + } +} + +// this will unload loaded but no longer needed libs which are +// gathered in mUnusedLibraries list, see bug #61388 +void nsPluginHostImpl::CleanUnusedLibraries() +{ + if(!mUnusedLibraries) + return; + + while (nsnull != mUnusedLibraries) + { + nsUnusedLibrary *temp = mUnusedLibraries->mNext; + delete mUnusedLibraries; + mUnusedLibraries = temp; } } nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages) { - // XXX don't we want to nuke the old mPlugins right now? - // we should. Otherwise LoadPlugins will add the same plugins to the list - // XXX for new-style plugins, we should also call nsIComponentManager::AutoRegister() - // we are re-scanning plugins. New plugins may have been added, also some // plugins may have been removed, so we should probably shut everything down // but don't touch running (active and not stopped) plugins - if(reloadPages) { // if we have currently running plugins we should set a flag not to @@ -1830,15 +1870,10 @@ nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages) // and form a list of libs to be unloaded later for(nsPluginTag * p = mPlugins; p != nsnull; p = p->mNext) { - if(IsRunningPlugin(p)) + if(IsRunningPlugin(p) && (p->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL)) { p->mCanUnloadLibrary = PR_FALSE; - nsUnloadedLibrary * unloadedLibrary = new nsUnloadedLibrary(p->mLibrary); - if(unloadedLibrary) - { - unloadedLibrary->mNext = mUnloadedLibraries; - mUnloadedLibraries = unloadedLibrary; - } + AddToUnusedLibraryList(p->mLibrary); } } @@ -1864,9 +1899,6 @@ nsresult nsPluginHostImpl::ReloadPlugins(PRBool reloadPages) else prev->mNext = next; - if(p->mEntryPoint) - p->mEntryPoint->Shutdown(); - delete p; p = next; continue; @@ -2393,26 +2425,17 @@ NS_IMETHODIMP nsPluginHostImpl::Destroy(void) { nsPluginTag *temp = mPlugins->mNext; - // while walking through the list of the plugins see if we still have anything to shutdown - // some plugins may have never created an instance but still expect a shutdown call - // see bugzilla bug 73071 - if(mPlugins->mEntryPoint != nsnull) - { - mPlugins->mEntryPoint->Shutdown(); - mPlugins->mEntryPoint = nsnull; - } - - if ((nsnull != mPlugins->mLibrary) && mPlugins->mCanUnloadLibrary) - { - PR_UnloadLibrary(mPlugins->mLibrary); - mPlugins->mLibrary = nsnull; - } + // while walking through the list of the plugins see if we still have anything + // to shutdown some plugins may have never created an instance but still expect + // the shutdown call see bugzilla bug 73071 + // with current logic, no need to do anything special as nsIPlugin::Shutdown + // will be performed in the destructor delete mPlugins; mPlugins = temp; } - CleanUnloadedLibraries(); + CleanUnusedLibraries(); return NS_OK; } @@ -2706,10 +2729,6 @@ void nsPluginHostImpl::AddInstanceToActiveList(nsCOMPtr aPlugin, PRBool aDefaultPlugin) { - // first, determine if the plugin wants to be cached - // Code moved to StopPluginInstance as we still need running - // plugins to be present in the 'active' list - char* url; if(!aURL) @@ -2717,7 +2736,30 @@ void nsPluginHostImpl::AddInstanceToActiveList(nsCOMPtr aPlugin, (void)aURL->GetSpec(&url); - nsActivePlugin * plugin = new nsActivePlugin(aPlugin, aInstance, url, aDefaultPlugin); + // find corresponding plugin tag + // this is legal for xpcom plugins not to have nsIPlugin implemented + nsPluginTag * pluginTag = nsnull; + if(aPlugin) + { + for(pluginTag = mPlugins; pluginTag != nsnull; pluginTag = pluginTag->mNext) + { + if(pluginTag->mEntryPoint == aPlugin) + break; + } + NS_ASSERTION(pluginTag, "Plugin tag not found"); + } + else + { + // we don't need it for xpcom plugins because the only purpose to have it + // is to be able to postpone unloading library dll in some circumstances + // which we don't do for xpcom plugins. In case we need it in the future + // we can probably use the following + /* + FindPluginEnabledForType(mimetype, pluginTag); + */ + } + + nsActivePlugin * plugin = new nsActivePlugin(pluginTag, aInstance, url, aDefaultPlugin); if(plugin == nsnull) return; @@ -3233,7 +3275,7 @@ NS_IMETHODIMP nsPluginHostImpl::GetPluginFactory(const char *aMimeType, nsIPlugi return NS_ERROR_ILLEGAL_VALUE; // unload any libs that can remain after plugins.refresh(1), see #61388 - CleanUnloadedLibraries(); + CleanUnusedLibraries(); // If plugins haven't been scanned yet, do so now LoadPlugins(); @@ -4130,42 +4172,25 @@ nsPluginHostImpl::StopPluginInstance(nsIPluginInstance* aInstance) aInstance->GetValue(nsPluginInstanceVariable_DoCacheBool, (void *) &doCache); // we also do that for 4x plugin, shall we? Let's see if it is - nsPluginTag * pluginTag = nsnull; - PRBool oldSchool = PR_FALSE; - for(pluginTag = mPlugins; pluginTag != nsnull; pluginTag = pluginTag->mNext) - { - if(pluginTag->mEntryPoint == plugin->mPlugin) - { - oldSchool = pluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL ? PR_TRUE : PR_FALSE; - break; - } - } + PRBool oldSchool = PR_TRUE; + if(plugin->mPluginTag) + oldSchool = plugin->mPluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL ? PR_TRUE : PR_FALSE; if (!doCache || oldSchool) - { - PRBool lastInstance = PR_FALSE; - PRBool xpConnected = plugin->mXPConnected; - - mActivePluginList.remove(plugin, &lastInstance); - - // and if this was the last instance we should unload the library - // and clear mEntryPoint and mLibrary member of the pluginTag - if(lastInstance) { - pluginTag->mEntryPoint = nsnull; + PRLibrary * library = plugin->mPluginTag->mLibrary; - if(xpConnected) - pluginTag->mCanUnloadLibrary = PR_FALSE; + PRBool unloadLibLater = PR_FALSE; + mActivePluginList.remove(plugin, &unloadLibLater); - if ((nsnull != pluginTag->mLibrary) && pluginTag->mCanUnloadLibrary) - { - PR_UnloadLibrary(pluginTag->mLibrary); - pluginTag->mLibrary = nsnull; + if(unloadLibLater) + AddToUnusedLibraryList(library); } - } - } else { + // if it is allowed to be cached simply stop it, but first we should check + // if we haven't exceeded the maximum allowed number of cached instances + // try to get the max cached plugins from a pref or use default PRUint32 max_num; nsresult rv; @@ -4177,8 +4202,17 @@ nsPluginHostImpl::StopPluginInstance(nsIPluginInstance* aInstance) { nsActivePlugin * oldest = mActivePluginList.findOldestStopped(); if(oldest != nsnull) - mActivePluginList.remove(oldest); + { + PRLibrary * library = oldest->mPluginTag->mLibrary; + + PRBool unloadLibLater = PR_FALSE; + mActivePluginList.remove(oldest, &unloadLibLater); + + if(unloadLibLater) + AddToUnusedLibraryList(library); + } } + plugin->setStopped(PR_TRUE); } } @@ -4372,6 +4406,9 @@ nsPluginHostImpl::SetIsScriptableInstance(nsCOMPtr aPluginIns return NS_ERROR_FAILURE; p->mXPConnected = aScriptable; + if(p->mPluginTag) + p->mPluginTag->mXPConnected = aScriptable; + return NS_OK; } diff --git a/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.h b/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.h index 45d8b93f31a..852957a7e75 100644 --- a/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.h +++ b/mozilla/modules/plugin/nglsrc/nsPluginHostImpl.h @@ -64,6 +64,8 @@ public: ~nsPluginTag(); + void TryUnloadPlugin(); + nsPluginTag *mNext; char *mName; char *mDescription; @@ -75,6 +77,7 @@ public: PRBool mCanUnloadLibrary; nsIPlugin *mEntryPoint; PRUint32 mFlags; + PRBool mXPConnected; char *mFileName; }; @@ -83,14 +86,14 @@ struct nsActivePlugin nsActivePlugin* mNext; char* mURL; nsIPluginInstancePeer* mPeer; - nsCOMPtr mPlugin; + nsPluginTag* mPluginTag; nsIPluginInstance* mInstance; PRBool mStopped; PRTime mllStopTime; PRBool mDefaultPlugin; PRBool mXPConnected; - nsActivePlugin(nsCOMPtr aPlugin, + nsActivePlugin(nsPluginTag* aPluginTag, nsIPluginInstance* aInstance, char * url, PRBool aDefaultPlugin); @@ -111,7 +114,7 @@ public: void shut(); PRBool add(nsActivePlugin * plugin); - PRBool remove(nsActivePlugin * plugin, PRBool * lastInstance = nsnull); + PRBool remove(nsActivePlugin * plugin, PRBool * aUnloadLibraryLater); nsActivePlugin * find(nsIPluginInstance* instance); nsActivePlugin * find(char * mimetype); nsActivePlugin * findStopped(char * url); @@ -126,17 +129,16 @@ public: // we need to keep some libs in memory when we destroy mPlugins list // during refresh with reload if the plugin is currently running // on the page. They should be unloaded later, see bug #61388 -// The list is only created during plugins.refresh(1) and should -// go away when we hit a page with a plugin again. It should not -// exist under any other circumstances -class nsUnloadedLibrary +// There could also be other reasons to have this list. XPConnected +// plugins e.g. may still be held at the time we normally unload the library +class nsUnusedLibrary { public: - nsUnloadedLibrary *mNext; + nsUnusedLibrary *mNext; PRLibrary *mLibrary; - nsUnloadedLibrary(PRLibrary * aLibrary); - ~nsUnloadedLibrary(); + nsUnusedLibrary(PRLibrary * aLibrary); + ~nsUnusedLibrary(); }; #define NS_PLUGIN_FLAG_ENABLED 0x0001 //is this plugin enabled? @@ -406,7 +408,8 @@ private: PRBool checkForUnwantedPlugins = PR_FALSE); PRBool IsRunningPlugin(nsPluginTag * plugin); - void CleanUnloadedLibraries(); + void AddToUnusedLibraryList(PRLibrary * aLibrary); + void CleanUnusedLibraries(); char *mPluginPath; nsPluginTag *mPlugins; @@ -415,7 +418,7 @@ private: PRBool mIsDestroyed; nsActivePluginList mActivePluginList; - nsUnloadedLibrary *mUnloadedLibraries; + nsUnusedLibrary *mUnusedLibraries; }; #endif