author | Ben Kelly <ben@wanderview.com> |
Thu, 26 Jan 2017 08:01:33 -0800 | |
changeset 377896 | 6196560e59678490e7a993d13fc0610d57068f13 |
parent 377895 | e881b33252def613f041a8671e04bcc94ae7f0c9 |
child 377897 | d4f4afc096fd685ecc77e503ba70ec5b5dd52b13 |
push id | 7198 |
push user | jlorenzo@mozilla.com |
push date | Tue, 18 Apr 2017 12:07:49 +0000 |
treeherder | mozilla-beta@d57aa49c3948 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | baku |
bugs | 1319278 |
milestone | 54.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
|
--- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -1033,72 +1033,27 @@ ServiceWorkerPrivate::SendPushSubscripti return NS_ERROR_FAILURE; } return NS_OK; } namespace { -static void -DummyNotificationTimerCallback(nsITimer* aTimer, void* aClosure) -{ - // Nothing. -} - -class AllowWindowInteractionHandler; - -class ClearWindowAllowedRunnable final : public WorkerRunnable +class AllowWindowInteractionHandler final : public ExtendableEventCallback + , public nsITimerCallback + , public WorkerHolder { -public: - ClearWindowAllowedRunnable(WorkerPrivate* aWorkerPrivate, - AllowWindowInteractionHandler* aHandler) - : WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) - , mHandler(aHandler) - { } - -private: - bool - PreDispatch(WorkerPrivate* aWorkerPrivate) override - { - // WorkerRunnable asserts that the dispatch is from parent thread if - // the busy count modification is WorkerThreadUnchangedBusyCount. - // Since this runnable will be dispatched from the timer thread, we override - // PreDispatch and PostDispatch to skip the check. - return true; - } - - void - PostDispatch(WorkerPrivate* aWorkerPrivate, bool aDispatchResult) override - { - // Silence bad assertions. - } - - bool - WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override; - - nsresult - Cancel() override - { - // Always ensure the handler is released on the worker thread, even if we - // are cancelled. - mHandler = nullptr; - return WorkerRunnable::Cancel(); - } - - RefPtr<AllowWindowInteractionHandler> mHandler; -}; - -class AllowWindowInteractionHandler final : public ExtendableEventCallback -{ - friend class ClearWindowAllowedRunnable; nsCOMPtr<nsITimer> mTimer; ~AllowWindowInteractionHandler() { + // We must either fail to initialize or call ClearWindowAllowed. + MOZ_DIAGNOSTIC_ASSERT(!mTimer); + MOZ_DIAGNOSTIC_ASSERT(!mWorkerPrivate); } void ClearWindowAllowed(WorkerPrivate* aWorkerPrivate) { MOZ_ASSERT(aWorkerPrivate); aWorkerPrivate->AssertIsOnWorkerThread(); @@ -1112,87 +1067,96 @@ class AllowWindowInteractionHandler fina WorkerGlobalScope* globalScope = aWorkerPrivate->GlobalScope(); if (!globalScope) { return; } globalScope->ConsumeWindowInteraction(); mTimer->Cancel(); mTimer = nullptr; - MOZ_ALWAYS_TRUE(aWorkerPrivate->ModifyBusyCountFromWorker(false)); + + ReleaseWorker(); } void StartClearWindowTimer(WorkerPrivate* aWorkerPrivate) { MOZ_ASSERT(aWorkerPrivate); aWorkerPrivate->AssertIsOnWorkerThread(); MOZ_ASSERT(!mTimer); nsresult rv; nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID, &rv); if (NS_WARN_IF(NS_FAILED(rv))) { return; } - RefPtr<ClearWindowAllowedRunnable> r = - new ClearWindowAllowedRunnable(aWorkerPrivate, this); - - RefPtr<TimerThreadEventTarget> target = - new TimerThreadEventTarget(aWorkerPrivate, r); - - rv = timer->SetTarget(target); + rv = timer->SetTarget(aWorkerPrivate->ControlEventTarget()); if (NS_WARN_IF(NS_FAILED(rv))) { return; } - // The important stuff that *has* to be reversed. - if (NS_WARN_IF(!aWorkerPrivate->ModifyBusyCountFromWorker(true))) { + if (!HoldWorker(aWorkerPrivate, Closing)) { return; } + aWorkerPrivate->GlobalScope()->AllowWindowInteraction(); timer.swap(mTimer); // We swap first and then initialize the timer so that even if initializing // fails, we still clean the busy count and interaction count correctly. // The timer can't be initialized before modifying the busy count since the // timer thread could run and call the timeout but the worker may // already be terminating and modifying the busy count could fail. - rv = mTimer->InitWithFuncCallback(DummyNotificationTimerCallback, nullptr, - gDOMDisableOpenClickDelay, - nsITimer::TYPE_ONE_SHOT); + rv = mTimer->InitWithCallback(this, + gDOMDisableOpenClickDelay, + nsITimer::TYPE_ONE_SHOT); if (NS_WARN_IF(NS_FAILED(rv))) { ClearWindowAllowed(aWorkerPrivate); return; } } + // nsITimerCallback virtual methods + NS_IMETHOD + Notify(nsITimer* aTimer) override + { + MOZ_DIAGNOSTIC_ASSERT(mTimer == aTimer); + ClearWindowAllowed(mWorkerPrivate); + return NS_OK; + } + + // WorkerHolder virtual methods + bool + Notify(Status aStatus) override + { + // We could try to hold the worker alive until the timer fires, but other + // APIs are not likely to work in this partially shutdown state. We might + // as well let the worker thread exit. + ClearWindowAllowed(mWorkerPrivate); + return true; + } + public: - NS_INLINE_DECL_REFCOUNTING(AllowWindowInteractionHandler, override) + NS_DECL_THREADSAFE_ISUPPORTS explicit AllowWindowInteractionHandler(WorkerPrivate* aWorkerPrivate) { StartClearWindowTimer(aWorkerPrivate); } void FinishedWithResult(ExtendableEventResult /* aResult */) override { WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate(); ClearWindowAllowed(workerPrivate); } }; -bool -ClearWindowAllowedRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) -{ - mHandler->ClearWindowAllowed(aWorkerPrivate); - mHandler = nullptr; - return true; -} +NS_IMPL_ISUPPORTS(AllowWindowInteractionHandler, nsITimerCallback) class SendNotificationEventRunnable final : public ExtendableEventWorkerRunnable { const nsString mEventName; const nsString mID; const nsString mTitle; const nsString mDir; const nsString mLang;
--- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -4899,16 +4899,22 @@ WorkerPrivate::DispatchToMainThread(alre { nsCOMPtr<nsIRunnable> runnable = aRunnable; if (nsCOMPtr<nsINamed> named = do_QueryInterface(runnable)) { named->SetName("WorkerRunnable"); } return mMainThreadEventTarget->Dispatch(runnable.forget(), aFlags); } +nsIEventTarget* +WorkerPrivate::ControlEventTarget() +{ + return mWorkerControlEventTarget; +} + void WorkerPrivate::InitializeGCTimers() { AssertIsOnWorkerThread(); // We need a timer for GC. The basic plan is to run a non-shrinking GC // periodically (PERIODIC_GC_TIMER_DELAY_SEC) while the worker is running. // Once the worker goes idle we set a short (IDLE_GC_TIMER_DELAY_SEC) timer to
--- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1387,16 +1387,22 @@ public: nsresult DispatchToMainThread(nsIRunnable* aRunnable, uint32_t aFlags = NS_DISPATCH_NORMAL); nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable, uint32_t aFlags = NS_DISPATCH_NORMAL); + // Get an event target that will dispatch runnables as control runnables on + // the worker thread. Implement nsICancelableRunnable if you wish to take + // action on cancelation. + nsIEventTarget* + ControlEventTarget(); + private: WorkerPrivate(WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker, WorkerType aWorkerType, const nsACString& aSharedWorkerName, WorkerLoadInfo& aLoadInfo); bool MayContinueRunning()