зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1257063 - Don't destruct the runnable inside the lock when TaskQueue::Dispatch fails. r=bobbyholley.
MozReview-Commit-ID: I5KvfHnLUIS
This commit is contained in:
Родитель
df9d702622
Коммит
7070827866
|
@ -20,13 +20,19 @@ FlushableTaskQueue::Flush()
|
|||
nsresult
|
||||
FlushableTaskQueue::FlushAndDispatch(already_AddRefed<nsIRunnable> aRunnable)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r = aRunnable;
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
AutoSetFlushing autoFlush(this);
|
||||
FlushLocked();
|
||||
nsCOMPtr<nsIRunnable> r = dont_AddRef(aRunnable.take());
|
||||
nsresult rv = DispatchLocked(r.forget(), IgnoreFlushing, AssertDispatchSuccess);
|
||||
nsresult rv = DispatchLocked(/* passed by ref */r, IgnoreFlushing, AssertDispatchSuccess);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
AwaitIdleLocked();
|
||||
}
|
||||
// If the ownership of |r| is not transferred in DispatchLocked() due to
|
||||
// dispatch failure, it will be deleted here outside the lock. We do so
|
||||
// since the destructor of the runnable might access TaskQueue and result
|
||||
// in deadlocks.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -39,15 +39,16 @@ TaskQueue::TailDispatcher()
|
|||
return *mTailDispatcher;
|
||||
}
|
||||
|
||||
// Note aRunnable is passed by ref to support conditional ownership transfer.
|
||||
// See Dispatch() in TaskQueue.h for more details.
|
||||
nsresult
|
||||
TaskQueue::DispatchLocked(already_AddRefed<nsIRunnable> aRunnable,
|
||||
TaskQueue::DispatchLocked(nsCOMPtr<nsIRunnable>& aRunnable,
|
||||
DispatchMode aMode, DispatchFailureHandling aFailureHandling,
|
||||
DispatchReason aReason)
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r = aRunnable;
|
||||
AbstractThread* currentThread;
|
||||
if (aReason != TailDispatch && (currentThread = GetCurrent()) && RequiresTailDispatch(currentThread)) {
|
||||
currentThread->TailDispatcher().AddTask(this, r.forget(), aFailureHandling);
|
||||
currentThread->TailDispatcher().AddTask(this, aRunnable.forget(), aFailureHandling);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -58,7 +59,7 @@ TaskQueue::DispatchLocked(already_AddRefed<nsIRunnable> aRunnable,
|
|||
if (mIsShutdown) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mTasks.push(r.forget());
|
||||
mTasks.push(aRunnable.forget());
|
||||
if (mIsRunning) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -42,12 +42,19 @@ public:
|
|||
void Dispatch(already_AddRefed<nsIRunnable> aRunnable,
|
||||
DispatchFailureHandling aFailureHandling = AssertDispatchSuccess,
|
||||
DispatchReason aReason = NormalDispatch) override
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> r = aRunnable;
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
nsresult rv = DispatchLocked(Move(aRunnable), AbortIfFlushing, aFailureHandling, aReason);
|
||||
nsresult rv = DispatchLocked(/* passed by ref */r, AbortIfFlushing, aFailureHandling, aReason);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aFailureHandling == DontAssertDispatchSuccess || NS_SUCCEEDED(rv));
|
||||
Unused << rv;
|
||||
}
|
||||
// If the ownership of |r| is not transferred in DispatchLocked() due to
|
||||
// dispatch failure, it will be deleted here outside the lock. We do so
|
||||
// since the destructor of the runnable might access TaskQueue and result
|
||||
// in deadlocks.
|
||||
}
|
||||
|
||||
// Puts the queue in a shutdown state and returns immediately. The queue will
|
||||
// remain alive at least until all the events are drained, because the Runners
|
||||
|
@ -81,7 +88,8 @@ protected:
|
|||
|
||||
enum DispatchMode { AbortIfFlushing, IgnoreFlushing };
|
||||
|
||||
nsresult DispatchLocked(already_AddRefed<nsIRunnable> aRunnable, DispatchMode aMode,
|
||||
nsresult DispatchLocked(nsCOMPtr<nsIRunnable>& aRunnable,
|
||||
DispatchMode aMode,
|
||||
DispatchFailureHandling aFailureHandling,
|
||||
DispatchReason aReason = NormalDispatch);
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче