Closed Bug 74485 Opened 23 years ago Closed 23 years ago

nsIPlugin::Shutdown called too often

Categories

(Core Graveyard :: Plug-ins, defect, P2)

x86
All
defect

Tracking

(Not tracked)

VERIFIED FIXED
mozilla0.9

People

(Reporter: sean, Assigned: serhunt)

References

()

Details

(Whiteboard: regression)

Attachments

(7 files)

Due to the fix for bug http://bugzilla.mozilla.org/show_bug.cgi?id=73071, 
nsIPlugin::Shutdown() is now called multiple times for plugins.  

It is first called when the activePluginList is being destroyed.  It is then 
called by the patch for bug 73071 in nsPluginHostImpl::Destroy.

First time:
BeatnikPlugin::Shutdown
nsActivePluginList::remove
nsActivePluginList::shut
nsPluginHostImpl::Destroy
nsPluginHostImpl::Observe
nsObserverService::Notify
NS_ShutdownXPCOM
main
mainCRTStartup()

Second:
BeatnikPlugin::Shutdown
nsPluginHostImpl::Destroy
nsPluginHostImpl::Observe
nsObserverService::Notify
NS_ShutdownXPCOM
main
mainCRTStartup

The new PR_UnloadLibrary is also a problem.  PR_UnloadLibrary is explicitly 
called from nsPluginHostImpl::Destroy() and then again from the dtor of 
mPlugins when nsPluginHostImpl::Destroy() calls delete mPlugins.
Maybe the problem with bug 73017 is in nsPluginHostImpl::StopPluginInstance() 
where uncached or old school plugins are unloaded without a call to Shutdown:

      if(lastInstance)
      {
+  // XXX need to call pluginTag->mEntryPoint->Shutdown() here?
        pluginTag->mEntryPoint = nsnull;
        if ((nsnull != pluginTag->mLibrary) && pluginTag->mCanUnloadLibrary)
        {
          PR_UnloadLibrary(pluginTag->mLibrary);
          pluginTag->mLibrary = nsnull;
        }
      }
scratch the last comment - mActivePluginList.remove(plugin, &lastInstance) does 
the right thing.

Under what circumstances is nsIPlugin::Initialize() called without any 
nsIPluginInstances getting created?  That's the cause of bug 73071, correct?  
Maybe nsPluginHostImpl::SetUpPluginInstance() needs to be modified to Shutdown 
and Release the plugin factory if it created and initialized it but then failed 
to create a pluginInstance?

This was added by request of Patric Beard. From what he told me I learnes that 
the MRJ plugin on Mac doesn't create instances. It is not that it failed to 
initialize during SetUpPluginInstance, it is just how it works.

I'll try to get it fixed as soon as I can. If this is blocking you now just 
comment out this shutdown line in nsPluginHostImpl::Destroy which I added in 
the mPlugin list demolition loop.
Status: NEW → ASSIGNED
OS: Windows 2000 → All
Priority: -- → P2
Whiteboard: regression
Target Milestone: --- → mozilla0.9
Attached patch possible fixSplinter Review
Sean, this patch should fix it. I basically moved last instance business so it 
is hidden in nsActivePluginList::remove. Now it will take care of zeroing 
nsPluginTag's mEntryPoint and mLibrary members, so they will not be used more 
than once.

I did not try it yet. Will do tomorrow as soon as I get back in the office.
I'll look at it tomorrow also - agree it's best to handle shutdown, unload, etc
from one place.
Why do you think it is not safe to have shut() in the destructor? If it all goes 
by scenario this shut() is not going to do anything and thus is not needed. But 
why not to have it just in case as a bulletproofing mechanism for potential 
bugs?
Attached patch one more timeSplinter Review
The original patch does not compile.  One problem is that shut() now takes an 
argument and the argument, mPlugins, is not accessible from nsActivePluginList.

Added a new patch that fixes nsIPlugin refcnt leak.  It isolates the Shutdown, 
Release and PR_UnloadLibrary calls to a single new method - 
nsPluginTag::ShutdownPluginModule.
Ah! You just got me. This is right thing and I was just going to implement it. 
I'll take a look.
I attached the patch which I think could be what we want. I tried to make the 
code cleaner and all shutdown related logic clearer so the code should look less 
messy now.

Sean, Peter, please apply and let it run to see I didn't introduce any 
regressions and the actual bug is really fixed. You will probably need to update 
the tree before apply the patch.
This line (1904) can be removed:
      p->TryShutdownPlugin();
since the next line calls TryShutdownPlugin:
      delete p;


I'm hitting this assert pretty often at shutdown:
    NS_ASSERTION(!unloadLibLater, "Plugin doesn't want to be unloaded");


It seems like the new (but not new in this patch) mXPConnected vars are only 
useful for dealing with 4x plugins.  It looks like that's the reason I'm 
getting the assert at shutdown.

XPCOM plugins are loaded by the componentManager, so it's safe for the plugin 
host to 'unload' xpcom libraries it has 'loaded' (since the loads and unloads 
are refcnted).
>This line (1904) can be removed:
>      p->TryShutdownPlugin();

Right, I noticed that after I posted the patch.

As to unloading asserion, I'll do it so it will do the 'safe' unload only for 
4.x plugins. Thanks for pointing this out.
OK, to reflect Sean's comment one can just quickly do the following:

In nsPluginHostImpl::ReloadPlugins

-  if(IsRunningPlugin(p))
+  if(IsRunningPlugin(p) && (p->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL))

-  p->TryShutdownPlugin();

In nsActivePluginList::remove

-  if(pluginTag->mXPConnected)
+  if(pluginTag->mXPConnected && (pluginTag->mFlags & NS_PLUGIN_FLAG_OLDSCHOOL))
Full patch with those small chages above. Now latering library unload is 
strictly limited to the 4.x style plugins.

Sean, if you have a minute would you please do the following with your plugin 
and see if everything goes fine:
0. have npnull32.dll -- the default plugin
1. have more than one plugin running on a page (with xpconnect in use)
2. go to any other page
3. come back
4. type javascript:navigator.plugins.refresh(1)
5. remove the actual plugin dll 
6. type javascript:navigator.plugins.refresh(1)
7. get the dll back
8. type javascript:navigator.plugins.refresh(1)
The latest patch is looking good.  I tried your steps, but it is impossible to 
remove the plugin dll since it is a component.  The component Manager owns 
references to its nsIModule and nsIFactory.

javascript:navigator.plugins.refresh(1) does stop and destroy all plugin 
instances.  The library and nsIPlugin references are released by the plugin 
host but since the component manager still has a hold of the module and 
factory, the dll is not actually unloaded.
One more note about javascript:navigator.plugins.refresh(1): although this 
causes the plugin host to stop and release plugin instances, the instances 
themselves are not destroyed because the docshell sometimes continues to hold 
references to xpconnected plugin instances.  They get garbage collected - 
sometimes on page transitions and sometimes at shutdown.
OK, so looks like everything works as expected. When you feel comfortable with 
this patch, would you give me your r= ?
Takes care of the issue and makes plugin management cleaner.  Just noticed that 
in nsActivePluginList::removeAllStopped(), these lines can be removed since 
prev isn't used anymore:
  nsActivePlugin * prev = nsnull;
    prev = p;

r=sean@beatnik.com.  Might want to get Patrick to take a look too.
Blocks: 65661
Is this problem causing the plugin to continuep playing even when I leave the 
page on *mac* ? Or would this be a seperate problem ? Pls let me know.
>Is this problem causing the plugin to continuep playing even when I leave 
>the page on *mac* ? Or would this be a seperate problem ? Pls let me know.

No - not related.  Browser support of full-page plugins on mac is very new.  
Sounds like the plugin is not getting a nsIPluginInstance::Stop call from the 
plugin host.
sr=waterson

Maybe rename ``unloaded library list'' to ``unused library list'',
``TryShutdownPlugin()'' to ``TryUnloadPlugin()''.
Checked in.
Status: ASSIGNED → RESOLVED
Closed: 23 years ago
Resolution: --- → FIXED
vrfy
Status: RESOLVED → VERIFIED
Product: Core → Core Graveyard
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: