/* -*- 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 mInner; ~WrappedControlRunnable() = default; public: WrappedControlRunnable(WorkerPrivate* aWorkerPrivate, nsCOMPtr&& 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 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 runnable(aRunnable); return Dispatch(runnable.forget(), aFlags); } NS_IMETHODIMP WorkerEventTarget::Dispatch(already_AddRefed aRunnable, uint32_t aFlags) { nsCOMPtr runnable(aRunnable); MutexAutoLock lock(mMutex); if (!mWorkerPrivate) { return NS_ERROR_FAILURE; } if (mBehavior == Behavior::Hybrid) { RefPtr r = mWorkerPrivate->MaybeWrapAsWorkerRunnable(runnable.forget()); if (r->Dispatch()) { return NS_OK; } runnable = std::move(r); } RefPtr r = new WrappedControlRunnable(mWorkerPrivate, std::move(runnable)); if (!r->Dispatch()) { return NS_ERROR_FAILURE; } return NS_OK; } NS_IMETHODIMP WorkerEventTarget::DelayedDispatch(already_AddRefed, 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