Bug 1154802 - Assert against potential deadlocks between synchronous MediaTaskQueue operations and tail dispatchers. r=jww

This commit is contained in:
Bobby Holley 2015-04-16 09:20:22 -07:00
parent 3747fb0d73
commit cbcc64429c
2 changed files with 44 additions and 6 deletions

View File

@ -106,8 +106,16 @@ private:
void
MediaTaskQueue::SyncDispatch(TemporaryRef<nsIRunnable> aRunnable) {
NS_WARNING("MediaTaskQueue::SyncDispatch is dangerous and deprecated. Stop using this!");
RefPtr<MediaTaskQueueSyncRunnable> task(new MediaTaskQueueSyncRunnable(aRunnable));
Dispatch(task);
nsRefPtr<MediaTaskQueueSyncRunnable> task(new MediaTaskQueueSyncRunnable(aRunnable));
// Tail dispatchers don't interact nicely with sync dispatch. We require that
// nothing is already in the tail dispatcher, and then sidestep it for this
// task.
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
nsRefPtr<MediaTaskQueueSyncRunnable> taskRef = task;
Dispatch(taskRef.forget(), AssertDispatchSuccess, TailDispatch);
task->WaitUntilDone();
}
@ -121,6 +129,11 @@ MediaTaskQueue::AwaitIdle()
void
MediaTaskQueue::AwaitIdleLocked()
{
// Make the there are no tasks for this queue waiting in the caller's tail
// dispatcher.
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
mQueueMonitor.AssertCurrentThreadOwns();
MOZ_ASSERT(mIsRunning || mTasks.empty());
while (mIsRunning) {
@ -131,6 +144,11 @@ MediaTaskQueue::AwaitIdleLocked()
void
MediaTaskQueue::AwaitShutdownAndIdle()
{
// Make the there are no tasks for this queue waiting in the caller's tail
// dispatcher.
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
MonitorAutoLock mon(mQueueMonitor);
while (!mIsShutdown) {
mQueueMonitor.Wait();
@ -176,6 +194,11 @@ FlushableMediaTaskQueue::FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable)
void
FlushableMediaTaskQueue::FlushLocked()
{
// Make the there are no tasks for this queue waiting in the caller's tail
// dispatcher.
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
mQueueMonitor.AssertCurrentThreadOwns();
MOZ_ASSERT(mIsFlushing);

View File

@ -44,6 +44,8 @@ public:
virtual void AddTask(AbstractThread* aThread,
already_AddRefed<nsIRunnable> aRunnable,
AbstractThread::DispatchFailureHandling aFailureHandling = AbstractThread::AssertDispatchSuccess) = 0;
virtual bool HasTasksFor(AbstractThread* aThread) = 0;
};
/*
@ -88,6 +90,8 @@ public:
}
}
bool HasTasksFor(AbstractThread* aThread) override { return !!GetTaskGroup(aThread); }
private:
struct PerThreadTaskGroup
@ -131,16 +135,27 @@ private:
PerThreadTaskGroup& EnsureTaskGroup(AbstractThread* aThread)
{
for (size_t i = 0; i < mTaskGroups.Length(); ++i) {
if (mTaskGroups[i]->mThread == aThread) {
return *mTaskGroups[i];
}
PerThreadTaskGroup* existing = GetTaskGroup(aThread);
if (existing) {
return *existing;
}
mTaskGroups.AppendElement(new PerThreadTaskGroup(aThread));
return *mTaskGroups.LastElement();
}
PerThreadTaskGroup* GetTaskGroup(AbstractThread* aThread)
{
for (size_t i = 0; i < mTaskGroups.Length(); ++i) {
if (mTaskGroups[i]->mThread == aThread) {
return mTaskGroups[i].get();
}
}
// Not found.
return nullptr;
}
// Task groups, organized by thread.
nsTArray<UniquePtr<PerThreadTaskGroup>> mTaskGroups;