mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Bug 1097823 - Implement MediaTaskQueue::ForceDispatch. r=cpearce
This is necessary to have strong guarantees that promises will be resolved. While we're flushing the task queue, normal dispatch starts to fail, meaning that we can't dispatch promise resolution. We have 3 options to handle this: (A) Never respond to the promise. (B) Invoke the Resolve/Reject callback synchronously if dispatch fails. (C) Prevent dispatch from failing. (C) seems like the option least likely to violate invariants if we can get away with it. Promise resolution is unlikely to be a heavyweight task in the way that a decode task might be, so this should hopefully be ok. Note that this still doesn't help for bonafide task queue shutdown. It's up to consumers to tear down their MediaPromiseHolders before the task queues are shut down.
This commit is contained in:
parent
8c9d29f7fe
commit
143aa4f9db
@ -34,6 +34,13 @@ MediaTaskQueue::Dispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||
return DispatchLocked(aRunnable, AbortIfFlushing);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTaskQueue::ForceDispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
return DispatchLocked(aRunnable, Forced);
|
||||
}
|
||||
|
||||
nsresult
|
||||
MediaTaskQueue::DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
|
||||
DispatchMode aMode)
|
||||
@ -45,7 +52,7 @@ MediaTaskQueue::DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
|
||||
if (mIsShutdown) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mTasks.push(aRunnable);
|
||||
mTasks.push(TaskQueueEntry(aRunnable, aMode == Forced));
|
||||
if (mIsRunning) {
|
||||
return NS_OK;
|
||||
}
|
||||
@ -140,9 +147,7 @@ MediaTaskQueue::FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
AutoSetFlushing autoFlush(this);
|
||||
while (!mTasks.empty()) {
|
||||
mTasks.pop();
|
||||
}
|
||||
FlushLocked();
|
||||
nsresult rv = DispatchLocked(aRunnable, IgnoreFlushing);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
AwaitIdleLocked();
|
||||
@ -154,10 +159,25 @@ MediaTaskQueue::Flush()
|
||||
{
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
AutoSetFlushing autoFlush(this);
|
||||
while (!mTasks.empty()) {
|
||||
FlushLocked();
|
||||
AwaitIdleLocked();
|
||||
}
|
||||
|
||||
void
|
||||
MediaTaskQueue::FlushLocked()
|
||||
{
|
||||
mQueueMonitor.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mIsFlushing);
|
||||
|
||||
// Clear the tasks, but preserve those with mForceDispatch by re-appending
|
||||
// them to the queue.
|
||||
size_t numTasks = mTasks.size();
|
||||
for (size_t i = 0; i < numTasks; ++i) {
|
||||
if (mTasks.front().mForceDispatch) {
|
||||
mTasks.push(mTasks.front());
|
||||
}
|
||||
mTasks.pop();
|
||||
}
|
||||
AwaitIdleLocked();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -191,7 +211,7 @@ MediaTaskQueue::Runner::Run()
|
||||
mon.NotifyAll();
|
||||
return NS_OK;
|
||||
}
|
||||
event = mQueue->mTasks.front();
|
||||
event = mQueue->mTasks.front().mRunnable;
|
||||
mQueue->mTasks.pop();
|
||||
}
|
||||
MOZ_ASSERT(event);
|
||||
|
@ -34,6 +34,10 @@ public:
|
||||
|
||||
nsresult Dispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||
|
||||
// This should only be used for things that absolutely can't afford to be
|
||||
// flushed. Normal operations should use Dispatch.
|
||||
nsresult ForceDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||
|
||||
nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||
|
||||
nsresult FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable);
|
||||
@ -68,18 +72,27 @@ private:
|
||||
// mQueueMonitor must be held.
|
||||
void AwaitIdleLocked();
|
||||
|
||||
enum DispatchMode { AbortIfFlushing, IgnoreFlushing };
|
||||
enum DispatchMode { AbortIfFlushing, IgnoreFlushing, Forced };
|
||||
|
||||
nsresult DispatchLocked(TemporaryRef<nsIRunnable> aRunnable,
|
||||
DispatchMode aMode);
|
||||
void FlushLocked();
|
||||
|
||||
RefPtr<SharedThreadPool> mPool;
|
||||
|
||||
// Monitor that protects the queue and mIsRunning;
|
||||
Monitor mQueueMonitor;
|
||||
|
||||
struct TaskQueueEntry {
|
||||
RefPtr<nsIRunnable> mRunnable;
|
||||
bool mForceDispatch;
|
||||
|
||||
TaskQueueEntry(TemporaryRef<nsIRunnable> aRunnable, bool aForceDispatch = false)
|
||||
: mRunnable(aRunnable), mForceDispatch(aForceDispatch) {}
|
||||
};
|
||||
|
||||
// Queue of tasks to run.
|
||||
std::queue<RefPtr<nsIRunnable>> mTasks;
|
||||
std::queue<TaskQueueEntry> mTasks;
|
||||
|
||||
// The thread currently running the task queue. We store a reference
|
||||
// to this so that IsCurrentThreadIn() can tell if the current thread
|
||||
|
Loading…
Reference in New Issue
Block a user