author | Ben Kelly <ben@wanderview.com> |
Tue, 13 Sep 2016 20:12:15 -0700 | |
changeset 313861 | 4844015b5fb76e47518cda47c7eb36188bd9df37 |
parent 313860 | 90a6f6dc4543bf8a57de97ff0b31f2197e3d4ce5 |
child 313862 | e72b06de40c005266f3fed08331eaf7141051a60 |
push id | 32264 |
push user | cbook@mozilla.com |
push date | Wed, 14 Sep 2016 10:18:20 +0000 |
treeherder | autoland@b9c4a0402a0a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bholley |
bugs | 1300118 |
milestone | 51.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
xpcom/threads/TaskQueue.cpp | file | annotate | diff | comparison | revisions | |
xpcom/threads/TaskQueue.h | file | annotate | diff | comparison | revisions |
--- a/xpcom/threads/TaskQueue.cpp +++ b/xpcom/threads/TaskQueue.cpp @@ -1,20 +1,72 @@ /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/TaskQueue.h" +#include "nsIEventTarget.h" #include "nsThreadUtils.h" namespace mozilla { +class TaskQueue::EventTargetWrapper final : public nsIEventTarget +{ + RefPtr<TaskQueue> mTaskQueue; + + ~EventTargetWrapper() + { + } + +public: + explicit EventTargetWrapper(TaskQueue* aTaskQueue) + : mTaskQueue(aTaskQueue) + { + MOZ_ASSERT(mTaskQueue); + } + + NS_IMETHOD + DispatchFromScript(nsIRunnable* aEvent, uint32_t aFlags) override + { + nsCOMPtr<nsIRunnable> ref = aEvent; + return Dispatch(ref.forget(), aFlags); + } + + NS_IMETHOD + Dispatch(already_AddRefed<nsIRunnable> aEvent, uint32_t aFlags) override + { + nsCOMPtr<nsIRunnable> runnable = aEvent; + MonitorAutoLock mon(mTaskQueue->mQueueMonitor); + return mTaskQueue->DispatchLocked(/* passed by ref */runnable, + AbortIfFlushing, + DontAssertDispatchSuccess, + NormalDispatch); + } + + NS_IMETHOD + DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t aFlags) override + { + return NS_ERROR_NOT_IMPLEMENTED; + } + + NS_IMETHOD + IsOnCurrentThread(bool* aResult) override + { + *aResult = mTaskQueue->IsCurrentThreadIn(); + return NS_OK; + } + + NS_DECL_THREADSAFE_ISUPPORTS +}; + +NS_IMPL_ISUPPORTS(TaskQueue::EventTargetWrapper, nsIEventTarget) + TaskQueue::TaskQueue(already_AddRefed<nsIEventTarget> aTarget, bool aRequireTailDispatch) : AbstractThread(aRequireTailDispatch) , mTarget(aTarget) , mQueueMonitor("TaskQueue::Queue") , mTailDispatcher(nullptr) , mIsRunning(false) , mIsShutdown(false) @@ -138,16 +190,23 @@ TaskQueue::IsEmpty() bool TaskQueue::IsCurrentThreadIn() { bool in = NS_GetCurrentThread() == mRunningThread; MOZ_ASSERT(in == (GetCurrent() == this)); return in; } +already_AddRefed<nsIEventTarget> +TaskQueue::WrapAsEventTarget() +{ + nsCOMPtr<nsIEventTarget> ref = new EventTargetWrapper(this); + return ref.forget(); +} + nsresult TaskQueue::Runner::Run() { RefPtr<nsIRunnable> event; { MonitorAutoLock mon(mQueue->mQueueMonitor); MOZ_ASSERT(mQueue->mIsRunning); if (mQueue->mTasks.size() == 0) {
--- a/xpcom/threads/TaskQueue.h +++ b/xpcom/threads/TaskQueue.h @@ -24,17 +24,36 @@ namespace mozilla { typedef MozPromise<bool, bool, false> ShutdownPromise; // Abstracts executing runnables in order on an arbitrary event target. The // runnables dispatched to the TaskQueue will be executed in the order in which // they're received, and are guaranteed to not be executed concurrently. // They may be executed on different threads, and a memory barrier is used // to make this threadsafe for objects that aren't already threadsafe. -class TaskQueue : public AbstractThread { +// +// Note, since a TaskQueue can also be converted to an nsIEventTarget using +// WrapAsEventTarget() its possible to construct a hierarchy of TaskQueues. +// Consider these three TaskQueues: +// +// TQ1 dispatches to the main thread +// TQ2 dispatches to TQ1 +// TQ3 dispatches to TQ1 +// +// This ensures there is only ever a single runnable from the entire chain on +// the main thread. It also ensures that TQ2 and TQ3 only have a single runnable +// in TQ1 at any time. +// +// This arrangement lets you prioritize work by dispatching runnables directly +// to TQ1. You can issue many runnables for important work. Meanwhile the TQ2 +// and TQ3 work will always execute at most one runnable and then yield. +class TaskQueue : public AbstractThread +{ + class EventTargetWrapper; + public: explicit TaskQueue(already_AddRefed<nsIEventTarget> aTarget, bool aSupportsTailDispatch = false); TaskDispatcher& TailDispatcher() override; TaskQueue* AsTaskQueue() override { return this; } @@ -71,16 +90,20 @@ public: void AwaitShutdownAndIdle(); bool IsEmpty(); // Returns true if the current thread is currently running a Runnable in // the task queue. bool IsCurrentThreadIn() override; + // Create a new nsIEventTarget wrapper object that dispatches to this + // TaskQueue. + already_AddRefed<nsIEventTarget> WrapAsEventTarget(); + protected: virtual ~TaskQueue(); // Blocks until all task finish executing. Called internally by methods // that need to wait until the task queue is idle. // mQueueMonitor must be held. void AwaitIdleLocked();