forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			199 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
	
		
			5.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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
 | 
