Closed Bug 966002 Opened 9 years ago Closed 9 years ago

Main thread shutdown assertions on xpcom shutdown while playing video


(Core :: Audio/Video, defect)

29 Branch
Not set





(Reporter: cpearce, Assigned: cpearce)



(1 file)

If I exit Firefox while playing one video, I get the following assertions:

[6736] WARNING: '!mMainThread', file c:\Users\cpearce\src\mozilla\purple\xpcom\threads\nsThreadManager.cpp, line 265
[6736] WARNING: 'NS_FAILED(rv)', file c:/Users/cpearce/src/mozilla/purple/xpcom/glue/nsThreadUtils.cpp, line 180
0[6bd740]: 149911d0 Queuing event pause
[6736] WARNING: '!mMainThread', file c:\Users\cpearce\src\mozilla\purple\xpcom\threads\nsThreadManager.cpp, line 265
[6736] WARNING: 'NS_FAILED(rv)', file c:/Users/cpearce/src/mozilla/purple/xpcom/glue/nsThreadUtils.cpp, line 180

The number of assertions scaled lineraly with the number of elements playing at shutdown.

The call stack is:

xul.dll!nsThreadManager::GetMainThread(nsIThread * * result=0x005cb5d4) Line 266	C++
xul.dll!NS_GetMainThread(nsIThread * * result=0x005cb5d4) Line 120	C++
xul.dll!NS_DispatchToMainThread(nsIRunnable * event=0x0e802c38, unsigned int dispatchFlags=0) Line 179	C++
xul.dll!mozilla::dom::HTMLMediaElement::DispatchAsyncEvent(const nsAString_internal & aName={...}) Line 3299	C++
xul.dll!mozilla::dom::HTMLMediaElement::FireTimeUpdate(bool aPeriodic=false) Line 3669	C++
xul.dll!mozilla::dom::HTMLMediaElement::Pause(mozilla::ErrorResult & aRv={...}) Line 1494	C++
xul.dll!mozilla::dom::HTMLMediaElement::Pause() Line 1502	C++
xul.dll!mozilla::dom::HTMLVideoElement::Pause() Line 34	C++
xul.dll!mozilla::dom::HTMLMediaElement::UnbindFromTree(bool aDeep=true, bool aNullParent=false) Line 2458	C++
xul.dll!mozilla::dom::Element::UnbindFromTree(bool aDeep=true, bool aNullParent=false) Line 1352	C++
xul.dll!nsGenericHTMLElement::UnbindFromTree(bool aDeep=true, bool aNullParent=false) Line 646	C++
xul.dll!mozilla::dom::HTMLBodyElement::UnbindFromTree(bool aDeep=true, bool aNullParent=false) Line 344	C++
xul.dll!mozilla::dom::Element::UnbindFromTree(bool aDeep=true, bool aNullParent=true) Line 1352	C++
xul.dll!nsGenericHTMLElement::UnbindFromTree(bool aDeep=true, bool aNullParent=true) Line 646	C++
xul.dll!mozilla::dom::HTMLSharedElement::UnbindFromTree(bool aDeep=true, bool aNullParent=true) Line 294	C++
xul.dll!nsDocument::cycleCollection::Unlink(void * p=0x0dbed0a0) Line 1906	C++
xul.dll!nsHTMLDocument::cycleCollection::Unlink(void * p=0x0dbed0a0) Line 213	C++
xul.dll!nsCycleCollector::CollectWhite() Line 2882	C++
xul.dll!nsCycleCollector::Collect(ccType aCCType=ShutdownCC, js::SliceBudget & aBudget={...}, nsICycleCollectorListener * aManualListener=0x00000000) Line 3184	C++
xul.dll!nsCycleCollector::ShutdownCollect() Line 3127	C++
xul.dll!nsCycleCollector::Shutdown() Line 3362	C++
xul.dll!nsCycleCollector_shutdown() Line 3768	C++
xul.dll!mozilla::ShutdownXPCOM(nsIServiceManager * servMgr=0x00000000) Line 796	C++
xul.dll!NS_ShutdownXPCOM(nsIServiceManager * servMgr=0x007eeff4) Line 656	C++
xul.dll!ScopedXPCOMStartup::~ScopedXPCOMStartup() Line 1163	C++
xul.dll!ScopedXPCOMStartup::`scalar deleting destructor'(unsigned int)	C++
xul.dll!XREMain::XRE_main(int argc=4, char * * argv=0x00c88b38, const nsXREAppData * aAppData=0x005cfa70) Line 4116	C++

What's happening is XPCOM is running a CC as part of its shutdown process.

The main thread is shutdown by this stage.

The media element is being unbound from its tree as part of the CC, and it's pausing playback. The media decoder is already paused, but the state isn't reflected in the media element's mPaused field, so we're running Pause() and that tries to dispatch an async event to the main thread to send a "pause" event to JS. The assertion is firing because the reference to the global "main" nsIThread has been cleared by this stage.
When we shutdown, the media element receives NotifyOwnerDocumentActivityChanged() call, which figures out that we need to pause playback, but still remain in the logical "not paused" state. That calls SuspendOrResumeElement() which pauses the decoder and sets mPausedForInactiveDocumentOrChannel and mEventDeliveryPaused to true.

We check mEventDeliveryPaused in HTMLMediaElement::DispatchEvent() and buffer events if it's true, but we're not doing that in HTMLMediaElement::DispatchAsyncEvent(). If we do the same thing in DispatchAsyncEvent, we don't try to dispatch a runnable to dispatch an event after we've shutdown, and the assertions don't fail.
Attachment #8368180 - Flags: review?(roc)
Closed: 9 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla29
You need to log in before you can comment on or make changes to this bug.