Bug 1160064 - Give WatchManager an owner thread and make sure everything happens there. r=jww

This commit is contained in:
Bobby Holley 2015-04-30 16:21:14 -07:00
parent a6a1df6eb5
commit 75cd0709f1
4 changed files with 36 additions and 9 deletions

View File

@ -2042,7 +2042,7 @@ HTMLMediaElement::LookupMediaElementURITable(nsIURI* aURI)
HTMLMediaElement::HTMLMediaElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
: nsGenericHTMLElement(aNodeInfo),
mWatchManager(this),
mWatchManager(this, AbstractThread::MainThread()),
mCurrentLoadID(0),
mNetworkState(nsIDOMHTMLMediaElement::NETWORK_EMPTY),
mReadyState(nsIDOMHTMLMediaElement::HAVE_NOTHING, "HTMLMediaElement::mReadyState"),

View File

@ -595,7 +595,7 @@ bool MediaDecoder::IsInfinite()
}
MediaDecoder::MediaDecoder() :
mWatchManager(this),
mWatchManager(this, AbstractThread::MainThread()),
mNextFrameStatus(AbstractThread::MainThread(),
MediaDecoderOwner::NEXT_FRAME_UNINITIALIZED,
"MediaDecoder::mNextFrameStatus (Mirror)"),

View File

@ -203,7 +203,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
bool aRealTime) :
mDecoder(aDecoder),
mTaskQueue(new MediaTaskQueue(GetMediaThreadPool(), /* aAssertTailDispatch = */ true)),
mWatchManager(this),
mWatchManager(this, mTaskQueue),
mRealTime(aRealTime),
mDispatchedStateMachine(false),
mDelayedScheduler(this),
@ -2529,6 +2529,9 @@ MediaDecoderStateMachine::FinishShutdown()
mNextPlayState.DisconnectIfConnected();
mNextFrameStatus.DisconnectAll();
// Shut down the watch manager before shutting down our task queue.
mWatchManager.Shutdown();
MOZ_ASSERT(mState == DECODER_STATE_SHUTDOWN,
"How did we escape from the shutdown state?");
// We must daisy-chain these events to destroy the decoder. We must

View File

@ -183,23 +183,39 @@ class WatchManager
{
public:
typedef void(OwnerType::*CallbackMethod)();
explicit WatchManager(OwnerType* aOwner)
: mOwner(aOwner) {}
explicit WatchManager(OwnerType* aOwner, AbstractThread* aOwnerThread)
: mOwner(aOwner), mOwnerThread(aOwnerThread) {}
~WatchManager()
{
if (!IsShutdown()) {
Shutdown();
}
}
bool IsShutdown() const { return !mOwner; }
// Shutdown needs to happen on mOwnerThread. If the WatchManager will be
// destroyed on a different thread, Shutdown() must be called manually.
void Shutdown()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
for (size_t i = 0; i < mWatchers.Length(); ++i) {
mWatchers[i]->Destroy();
}
mWatchers.Clear();
mOwner = nullptr;
}
void Watch(WatchTarget& aTarget, CallbackMethod aMethod)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
aTarget.AddWatcher(&EnsureWatcher(aMethod));
}
void Unwatch(WatchTarget& aTarget, CallbackMethod aMethod)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
PerCallbackWatcher* watcher = GetWatcher(aMethod);
MOZ_ASSERT(watcher);
aTarget.RemoveWatcher(watcher);
@ -207,6 +223,7 @@ public:
void ManualNotify(CallbackMethod aMethod)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
PerCallbackWatcher* watcher = GetWatcher(aMethod);
MOZ_ASSERT(watcher);
watcher->Notify();
@ -216,17 +233,19 @@ private:
class PerCallbackWatcher : public AbstractWatcher
{
public:
PerCallbackWatcher(OwnerType* aOwner, CallbackMethod aMethod)
: mOwner(aOwner), mCallbackMethod(aMethod) {}
PerCallbackWatcher(OwnerType* aOwner, AbstractThread* aOwnerThread, CallbackMethod aMethod)
: mOwner(aOwner), mOwnerThread(aOwnerThread), mCallbackMethod(aMethod) {}
void Destroy()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
mDestroyed = true;
mOwner = nullptr;
}
void Notify() override
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MOZ_DIAGNOSTIC_ASSERT(mOwner, "mOwner is only null after destruction, "
"at which point we shouldn't be notified");
if (mStrongRef) {
@ -237,7 +256,7 @@ private:
// Queue up our notification jobs to run in a stable state.
nsCOMPtr<nsIRunnable> r = NS_NewRunnableMethod(this, &PerCallbackWatcher::DoNotify);
AbstractThread::GetCurrent()->TailDispatcher().AddDirectTask(r.forget());
mOwnerThread->TailDispatcher().AddDirectTask(r.forget());
}
bool CallbackMethodIs(CallbackMethod aMethod) const
@ -250,6 +269,7 @@ private:
void DoNotify()
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
MOZ_ASSERT(mStrongRef);
nsRefPtr<OwnerType> ref = mStrongRef.forget();
((*ref).*mCallbackMethod)();
@ -257,11 +277,13 @@ private:
OwnerType* mOwner; // Never null.
nsRefPtr<OwnerType> mStrongRef; // Only non-null when notifying.
nsRefPtr<AbstractThread> mOwnerThread;
CallbackMethod mCallbackMethod;
};
PerCallbackWatcher* GetWatcher(CallbackMethod aMethod)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
for (size_t i = 0; i < mWatchers.Length(); ++i) {
if (mWatchers[i]->CallbackMethodIs(aMethod)) {
return mWatchers[i];
@ -272,16 +294,18 @@ private:
PerCallbackWatcher& EnsureWatcher(CallbackMethod aMethod)
{
MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn());
PerCallbackWatcher* watcher = GetWatcher(aMethod);
if (watcher) {
return *watcher;
}
watcher = mWatchers.AppendElement(new PerCallbackWatcher(mOwner, aMethod))->get();
watcher = mWatchers.AppendElement(new PerCallbackWatcher(mOwner, mOwnerThread, aMethod))->get();
return *watcher;
}
nsTArray<nsRefPtr<PerCallbackWatcher>> mWatchers;
OwnerType* mOwner;
nsRefPtr<AbstractThread> mOwnerThread;
};
#undef WATCH_LOG