diff options
Diffstat (limited to 'dom/workers/WorkerEventTarget.cpp')
-rw-r--r-- | dom/workers/WorkerEventTarget.cpp | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/dom/workers/WorkerEventTarget.cpp b/dom/workers/WorkerEventTarget.cpp new file mode 100644 index 0000000000..cb58b4f8ed --- /dev/null +++ b/dom/workers/WorkerEventTarget.cpp @@ -0,0 +1,199 @@ +/* -*- 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/Logging.h" +#include "mozilla/dom/ReferrerInfo.h" + +namespace mozilla::dom { + +static mozilla::LazyLogModule sWorkerEventTargetLog("WorkerEventTarget"); + +#ifdef LOG +# undef LOG +#endif +#ifdef LOGV +# undef LOGV +#endif +#define LOG(args) MOZ_LOG(sWorkerEventTargetLog, LogLevel::Debug, args); +#define LOGV(args) MOZ_LOG(sWorkerEventTargetLog, LogLevel::Verbose, args); + +namespace { + +class WrappedControlRunnable final : public WorkerControlRunnable { + nsCOMPtr<nsIRunnable> mInner; + + ~WrappedControlRunnable() = default; + + public: + WrappedControlRunnable(WorkerPrivate* aWorkerPrivate, + nsCOMPtr<nsIRunnable>&& aInner) + : WorkerControlRunnable(aWorkerPrivate, "WrappedControlRunnable", + WorkerThread), + 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) { + return Run(); + } + + // 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. + return cr->Cancel(); + } +}; + +} // anonymous namespace + +NS_IMPL_ISUPPORTS(WorkerEventTarget, nsIEventTarget, nsISerialEventTarget) + +WorkerEventTarget::WorkerEventTarget(WorkerPrivate* aWorkerPrivate, + Behavior aBehavior) + : mMutex("WorkerEventTarget"), + mWorkerPrivate(aWorkerPrivate), + mBehavior(aBehavior) { + LOG(("WorkerEventTarget::WorkerEventTarget [%p] aBehavior: %u", this, + (uint8_t)aBehavior)); + MOZ_DIAGNOSTIC_ASSERT(mWorkerPrivate); +} + +void WorkerEventTarget::ForgetWorkerPrivate(WorkerPrivate* aWorkerPrivate) { + LOG(("WorkerEventTarget::ForgetWorkerPrivate [%p] aWorkerPrivate: %p", this, + aWorkerPrivate)); + MutexAutoLock lock(mMutex); + MOZ_DIAGNOSTIC_ASSERT(!mWorkerPrivate || mWorkerPrivate == aWorkerPrivate); + mWorkerPrivate = nullptr; +} + +NS_IMETHODIMP +WorkerEventTarget::DispatchFromScript(nsIRunnable* aRunnable, uint32_t aFlags) { + LOGV(("WorkerEventTarget::DispatchFromScript [%p] aRunnable: %p", this, + aRunnable)); + nsCOMPtr<nsIRunnable> runnable(aRunnable); + return Dispatch(runnable.forget(), aFlags); +} + +NS_IMETHODIMP +WorkerEventTarget::Dispatch(already_AddRefed<nsIRunnable> aRunnable, + uint32_t aFlags) { + nsCOMPtr<nsIRunnable> runnable(aRunnable); + LOGV( + ("WorkerEventTarget::Dispatch [%p] aRunnable: %p", this, runnable.get())); + + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + return NS_ERROR_FAILURE; + } + + if (mBehavior == Behavior::Hybrid) { + LOGV(("WorkerEventTarget::Dispatch [%p] Dispatch as normal runnable(%p)", + this, runnable.get())); + + RefPtr<WorkerRunnable> r = + mWorkerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget()); + if (r->Dispatch()) { + return NS_OK; + } + runnable = std::move(r); + LOGV(( + "WorkerEventTarget::Dispatch [%p] Dispatch as normal runnable(%p) fail", + this, runnable.get())); + } + + RefPtr<WorkerControlRunnable> r = + new WrappedControlRunnable(mWorkerPrivate, std::move(runnable)); + LOGV( + ("WorkerEventTarget::Dispatch [%p] Wrapped runnable as control " + "runnable(%p)", + this, r.get())); + if (!r->Dispatch()) { + LOGV( + ("WorkerEventTarget::Dispatch [%p] Dispatch as control runnable(%p) " + "fail", + this, r.get())); + 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) { + NS_ENSURE_ARG(aTask); + + MutexAutoLock lock(mMutex); + + // If mWorkerPrivate is gone, the event target is already late during + // shutdown, return NS_ERROR_UNEXPECTED as documented in `nsIEventTarget.idl`. + if (!mWorkerPrivate) { + return NS_ERROR_UNEXPECTED; + } + + return mWorkerPrivate->RegisterShutdownTask(aTask); +} + +NS_IMETHODIMP +WorkerEventTarget::UnregisterShutdownTask(nsITargetShutdownTask* aTask) { + NS_ENSURE_ARG(aTask); + + MutexAutoLock lock(mMutex); + + if (!mWorkerPrivate) { + return NS_ERROR_UNEXPECTED; + } + + return mWorkerPrivate->UnregisterShutdownTask(aTask); +} + +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 |