diff options
Diffstat (limited to 'dom/workers/WorkerEventTarget.cpp')
-rw-r--r-- | dom/workers/WorkerEventTarget.cpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/dom/workers/WorkerEventTarget.cpp b/dom/workers/WorkerEventTarget.cpp new file mode 100644 index 0000000000..79a1cdcf8c --- /dev/null +++ b/dom/workers/WorkerEventTarget.cpp @@ -0,0 +1,169 @@ +/* -*- 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 "WorkerEventTarget.h" +#include "WorkerPrivate.h" +#include "WorkerRunnable.h" + +#include "mozilla/dom/ReferrerInfo.h" + +namespace mozilla::dom { + +namespace { + +class WrappedControlRunnable final : public WorkerControlRunnable { + nsCOMPtr<nsIRunnable> mInner; + + ~WrappedControlRunnable() = default; + + public: + WrappedControlRunnable(WorkerPrivate* aWorkerPrivate, + nsCOMPtr<nsIRunnable>&& aInner) + : WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount), + mInner(std::move(aInner)) {} + + virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override { + // Silence bad assertions, this can be dispatched from any thread. + return true; + } + + virtual void PostDispatch(WorkerPrivate* aWorkerPrivate, + bool aDispatchResult) override { + // Silence bad assertions, this can be dispatched from any thread. + } + + bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override { + mInner->Run(); + return true; + } + + nsresult Cancel() override { + nsCOMPtr<nsICancelableRunnable> cr = do_QueryInterface(mInner); + + // If the inner runnable is not cancellable, then just do the normal + // WorkerControlRunnable thing. This will end up calling Run(). + if (!cr) { + WorkerControlRunnable::Cancel(); + return NS_OK; + } + + // Otherwise call the inner runnable's Cancel() and treat this like + // a WorkerRunnable cancel. We can't call WorkerControlRunnable::Cancel() + // in this case since that would result in both Run() and the inner + // Cancel() being called. + Unused << cr->Cancel(); + return WorkerRunnable::Cancel(); + } +}; + +} // anonymous namespace + +NS_IMPL_ISUPPORTS(WorkerEventTarget, nsIEventTarget, nsISerialEventTarget) + +WorkerEventTarget::WorkerEventTarget(WorkerPrivate* aWorkerPrivate, + Behavior aBehavior) + : mMutex("WorkerEventTarget"), + mWorkerPrivate(aWorkerPrivate), + mBehavior(aBehavior) { + MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate); +} + +void WorkerEventTarget::ForgetWorkerPrivate(WorkerPrivate* aWorkerPrivate) { + MutexAutoLock lock(mMutex); + MOZ_DIAGNOSTIC_ASSERT(!mWorkerPrivate || mWorkerPrivate == aWorkerPrivate); + mWorkerPrivate = nullptr; +} + +NS_IMETHODIMP +WorkerEventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) { + nsCOMPtr<nsIRunnable> runnable(aRunnable); + return Dispatch(runnable.forget(), aFlags); +} + +NS_IMETHODIMP +WorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable, + uint32_t aFlags) { + nsCOMPtr<nsIRunnable> runnable(aRunnable); + + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + return NS_ERROR_FAILURE; + } + + if (mBehavior == Behavior::Hybrid) { + RefPtr<WorkerRunnable> r = + mWorkerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget()); + if (r->Dispatch()) { + return NS_OK; + } + + runnable = std::move(r); + } + + RefPtr<WorkerControlRunnable> r = + new WrappedControlRunnable(mWorkerPrivate, std::move(runnable)); + if (!r->Dispatch()) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +WorkerEventTarget::DelayedDispatch(already_AddRefed<nsIRunnable>, uint32_t) { + return NS_ERROR_NOT_IMPLEMENTED; +} + +NS_IMETHODIMP +WorkerEventTarget::RegisterShutdownTask(nsITargetShutdownTask* aTask) { + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + return NS_ERROR_FAILURE; + } + + if (!mWorkerPrivate->RegisterShutdownTask(aTask)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +WorkerEventTarget::UnregisterShutdownTask(nsITargetShutdownTask* aTask) { + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + return NS_ERROR_FAILURE; + } + + if (!mWorkerPrivate->UnregisterShutdownTask(aTask)) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP_(bool) +WorkerEventTarget::IsOnCurrentThreadInfallible() { + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + return false; + } + + return mWorkerPrivate->IsOnCurrentThread(); +} + +NS_IMETHODIMP +WorkerEventTarget::IsOnCurrentThread(bool* aIsOnCurrentThread) { + MOZ_ASSERT(aIsOnCurrentThread); + *aIsOnCurrentThread = IsOnCurrentThreadInfallible(); + return NS_OK; +} + +} // namespace mozilla::dom |