1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "WorkerRunnable.h"
9 #include "WorkerScope.h"
10 #include "js/RootingAPI.h"
12 #include "jsfriendapi.h"
13 #include "mozilla/AlreadyAddRefed.h"
14 #include "mozilla/AppShutdown.h"
15 #include "mozilla/Assertions.h"
16 #include "mozilla/CycleCollectedJSContext.h"
17 #include "mozilla/DebugOnly.h"
18 #include "mozilla/ErrorResult.h"
19 #include "mozilla/Logging.h"
20 #include "mozilla/Maybe.h"
21 #include "mozilla/glean/DomWorkersMetrics.h"
22 #include "mozilla/TelemetryHistogramEnums.h"
23 #include "mozilla/TimeStamp.h"
24 #include "mozilla/Unused.h"
25 #include "mozilla/dom/ScriptSettings.h"
26 #include "mozilla/dom/Worker.h"
27 #include "mozilla/dom/WorkerCommon.h"
29 #include "nsGlobalWindowInner.h"
31 #include "nsIEventTarget.h"
32 #include "nsIGlobalObject.h"
33 #include "nsIRunnable.h"
34 #include "nsThreadUtils.h"
35 #include "nsWrapperCacheInlines.h"
37 namespace mozilla::dom
{
39 static mozilla::LazyLogModule
sWorkerRunnableLog("WorkerRunnable");
44 #define LOG(args) MOZ_LOG(sWorkerRunnableLog, LogLevel::Verbose, args);
48 const nsIID kWorkerRunnableIID
= {
52 {0x88, 0x6e, 0xca, 0x6a, 0x81, 0xe4, 0x1d, 0x68}};
57 WorkerRunnable::WorkerRunnable(const char* aName
)
58 # ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
60 LOG(("WorkerRunnable::WorkerRunnable [%p] (%s)", this, mName
));
64 LOG(("WorkerRunnable::WorkerRunnable [%p]", this));
70 WorkerRunnable
* WorkerRunnable::FromRunnable(nsIRunnable
* aRunnable
) {
71 MOZ_ASSERT(aRunnable
);
73 WorkerRunnable
* runnable
;
74 nsresult rv
= aRunnable
->QueryInterface(kWorkerRunnableIID
,
75 reinterpret_cast<void**>(&runnable
));
84 bool WorkerRunnable::Dispatch(WorkerPrivate
* aWorkerPrivate
) {
85 LOG(("WorkerRunnable::Dispatch [%p] aWorkerPrivate: %p", this,
87 MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate
);
88 bool ok
= PreDispatch(aWorkerPrivate
);
90 ok
= DispatchInternal(aWorkerPrivate
);
92 PostDispatch(aWorkerPrivate
, ok
);
96 NS_IMETHODIMP
WorkerRunnable::Run() { return NS_OK
; }
98 NS_IMPL_ADDREF(WorkerRunnable
)
99 NS_IMPL_RELEASE(WorkerRunnable
)
101 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
103 WorkerRunnable::GetName(nsACString
& aName
) {
105 aName
.AssignASCII(mName
);
113 NS_INTERFACE_MAP_BEGIN(WorkerRunnable
)
114 NS_INTERFACE_MAP_ENTRY(nsIRunnable
)
115 #ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
116 NS_INTERFACE_MAP_ENTRY(nsINamed
)
118 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRunnable
)
119 // kWorkerRunnableIID is special in that it does not AddRef its result.
120 if (aIID
.Equals(kWorkerRunnableIID
)) {
121 *aInstancePtr
= this;
126 WorkerParentThreadRunnable::WorkerParentThreadRunnable(const char* aName
)
127 : WorkerRunnable(aName
) {
128 LOG(("WorkerParentThreadRunnable::WorkerParentThreadRunnable [%p]", this));
131 WorkerParentThreadRunnable::~WorkerParentThreadRunnable() = default;
133 bool WorkerParentThreadRunnable::PreDispatch(WorkerPrivate
* aWorkerPrivate
) {
135 MOZ_ASSERT(aWorkerPrivate
);
136 aWorkerPrivate
->AssertIsOnWorkerThread();
141 bool WorkerParentThreadRunnable::DispatchInternal(
142 WorkerPrivate
* aWorkerPrivate
) {
143 LOG(("WorkerParentThreadRunnable::DispatchInternal [%p]", this));
144 mWorkerParentRef
= aWorkerPrivate
->GetWorkerParentRef();
145 RefPtr
<WorkerParentThreadRunnable
> runnable(this);
146 return NS_SUCCEEDED(aWorkerPrivate
->DispatchToParent(runnable
.forget()));
149 void WorkerParentThreadRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
150 bool aDispatchResult
) {
152 MOZ_ASSERT(aWorkerPrivate
);
153 aWorkerPrivate
->AssertIsOnWorkerThread();
157 bool WorkerParentThreadRunnable::PreRun(WorkerPrivate
* aWorkerPrivate
) {
161 void WorkerParentThreadRunnable::PostRun(JSContext
* aCx
,
162 WorkerPrivate
* aWorkerPrivate
,
166 MOZ_ASSERT(aWorkerPrivate
);
167 aWorkerPrivate
->AssertIsOnParentThread();
172 WorkerParentThreadRunnable::Run() {
173 LOG(("WorkerParentThreadRunnable::Run [%p]", this));
174 RefPtr
<WorkerPrivate
> workerPrivate
;
175 MOZ_ASSERT(mWorkerParentRef
);
176 workerPrivate
= mWorkerParentRef
->Private();
177 if (!workerPrivate
) {
178 NS_WARNING("Worker has already shut down!!!");
182 workerPrivate
->AssertIsOnParentThread();
185 WorkerPrivate
* parent
= workerPrivate
->GetParent();
186 bool isOnMainThread
= !parent
;
187 bool result
= PreRun(workerPrivate
);
190 LOG(("WorkerParentThreadRunnable::Run [%p] WorkerPrivate: %p, parent: %p",
191 this, workerPrivate
.get(), parent
));
193 // Track down the appropriate global, if any, to use for the AutoEntryScript.
194 nsCOMPtr
<nsIGlobalObject
> globalObject
;
195 if (isOnMainThread
) {
196 MOZ_ASSERT(isOnMainThread
== NS_IsMainThread());
197 globalObject
= nsGlobalWindowInner::Cast(workerPrivate
->GetWindow());
199 MOZ_ASSERT(parent
== GetCurrentThreadWorkerPrivate());
200 globalObject
= parent
->GlobalScope();
201 MOZ_DIAGNOSTIC_ASSERT(globalObject
);
203 // We might run script as part of WorkerRun, so we need an AutoEntryScript.
204 // This is part of the HTML spec for workers at:
205 // http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker
206 // If we don't have a globalObject we have to use an AutoJSAPI instead, but
207 // this is OK as we won't be running script in these circumstances.
208 Maybe
<mozilla::dom::AutoJSAPI
> maybeJSAPI
;
209 Maybe
<mozilla::dom::AutoEntryScript
> aes
;
214 aes
.emplace(globalObject
, "Worker parent thread runnable", isOnMainThread
);
218 maybeJSAPI
.emplace();
220 jsapi
= maybeJSAPI
.ptr();
224 // Note that we can't assert anything about
225 // workerPrivate->ParentEventTargetRef()->GetWrapper()
226 // existing, since it may in fact have been GCed (and we may be one of the
227 // runnables cleaning up the worker as a result).
229 // If we are on the parent thread and that thread is not the main thread,
230 // then we must be a dedicated worker (because there are no
231 // Shared/ServiceWorkers whose parent is itself a worker) and then we
232 // definitely have a globalObject. If it _is_ the main thread, globalObject
233 // can be null for workers started from JSMs or other non-window contexts,
235 MOZ_ASSERT_IF(!isOnMainThread
,
236 workerPrivate
->IsDedicatedWorker() && globalObject
);
238 // If we're on the parent thread we might be in a null realm in the
239 // situation described above when globalObject is null. Make sure to enter
240 // the realm of the worker's reflector if there is one. There might
241 // not be one if we're just starting to compile the script for this worker.
242 Maybe
<JSAutoRealm
> ar
;
243 if (workerPrivate
->IsDedicatedWorker() &&
244 workerPrivate
->ParentEventTargetRef() &&
245 workerPrivate
->ParentEventTargetRef()->GetWrapper()) {
246 JSObject
* wrapper
= workerPrivate
->ParentEventTargetRef()->GetWrapper();
248 // If we're on the parent thread and have a reflector and a globalObject,
249 // then the realms of cx, globalObject, and the worker's reflector
251 MOZ_ASSERT_IF(globalObject
,
252 js::GetNonCCWObjectRealm(wrapper
) == js::GetContextRealm(cx
));
253 MOZ_ASSERT_IF(globalObject
,
254 js::GetNonCCWObjectRealm(wrapper
) ==
255 js::GetNonCCWObjectRealm(
256 globalObject
->GetGlobalJSObjectPreserveColor()));
258 // If we're on the parent thread and have a reflector, then our
259 // JSContext had better be either in the null realm (and hence
260 // have no globalObject) or in the realm of our reflector.
261 MOZ_ASSERT(!js::GetContextRealm(cx
) ||
262 js::GetNonCCWObjectRealm(wrapper
) == js::GetContextRealm(cx
),
263 "Must either be in the null compartment or in our reflector "
266 ar
.emplace(cx
, wrapper
);
269 MOZ_ASSERT(!jsapi
->HasException());
270 result
= WorkerRun(cx
, workerPrivate
);
271 jsapi
->ReportException();
273 // It would be nice to avoid passing a JSContext to PostRun, but in the case
274 // of ScriptExecutorRunnable we need to know the current compartment on the
275 // JSContext (the one we set up based on the global returned from PreRun) so
276 // that we can sanely do exception reporting. In particular, we want to make
277 // sure that we do our JS_SetPendingException while still in that compartment,
278 // because otherwise we might end up trying to create a cross-compartment
279 // wrapper when we try to move the JS exception from our runnable's
280 // ErrorResult to the JSContext, and that's not desirable in this case.
282 // We _could_ skip passing a JSContext here and then in
283 // ScriptExecutorRunnable::PostRun end up grabbing it from the WorkerPrivate
284 // and looking at its current compartment. But that seems like slightly weird
285 // action-at-a-distance...
287 // In any case, we do NOT try to change the compartment on the JSContext at
288 // this point; in the one case in which we could do that
289 // (CompileScriptRunnable) it actually doesn't matter which compartment we're
291 PostRun(cx
, workerPrivate
, result
);
292 MOZ_ASSERT(!jsapi
->HasException());
294 return result
? NS_OK
: NS_ERROR_FAILURE
;
297 nsresult
WorkerParentThreadRunnable::Cancel() {
298 LOG(("WorkerParentThreadRunnable::Cancel [%p]", this));
302 WorkerParentControlRunnable::WorkerParentControlRunnable(const char* aName
)
303 : WorkerParentThreadRunnable(aName
) {}
305 WorkerParentControlRunnable::~WorkerParentControlRunnable() = default;
307 nsresult
WorkerParentControlRunnable::Cancel() {
308 LOG(("WorkerParentControlRunnable::Cancel [%p]", this));
309 if (NS_FAILED(Run())) {
310 NS_WARNING("WorkerParentControlRunnable::Run() failed.");
315 WorkerThreadRunnable::WorkerThreadRunnable(const char* aName
)
316 : WorkerRunnable(aName
), mCallingCancelWithinRun(false) {
317 LOG(("WorkerThreadRunnable::WorkerThreadRunnable [%p]", this));
320 nsIGlobalObject
* WorkerThreadRunnable::DefaultGlobalObject(
321 WorkerPrivate
* aWorkerPrivate
) const {
322 MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate
);
323 if (IsDebuggerRunnable()) {
324 return aWorkerPrivate
->DebuggerGlobalScope();
326 return aWorkerPrivate
->GlobalScope();
329 bool WorkerThreadRunnable::PreDispatch(WorkerPrivate
* aWorkerPrivate
) {
330 MOZ_ASSERT(aWorkerPrivate
);
332 aWorkerPrivate
->AssertIsOnParentThread();
337 bool WorkerThreadRunnable::DispatchInternal(WorkerPrivate
* aWorkerPrivate
) {
338 LOG(("WorkerThreadRunnable::DispatchInternal [%p]", this));
339 RefPtr
<WorkerThreadRunnable
> runnable(this);
340 return NS_SUCCEEDED(aWorkerPrivate
->Dispatch(runnable
.forget()));
343 void WorkerThreadRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
344 bool aDispatchResult
) {
345 MOZ_ASSERT(aWorkerPrivate
);
347 aWorkerPrivate
->AssertIsOnParentThread();
351 bool WorkerThreadRunnable::PreRun(WorkerPrivate
* aWorkerPrivate
) {
355 void WorkerThreadRunnable::PostRun(JSContext
* aCx
,
356 WorkerPrivate
* aWorkerPrivate
,
359 MOZ_ASSERT(aWorkerPrivate
);
362 aWorkerPrivate
->AssertIsOnWorkerThread();
367 WorkerThreadRunnable::Run() {
368 LOG(("WorkerThreadRunnable::Run [%p]", this));
370 // The Worker initialization fails, there is no valid WorkerPrivate and
371 // WorkerJSContext to run this WorkerThreadRunnable.
372 if (mCleanPreStartDispatching
) {
373 LOG(("Clean the pre-start dispatched WorkerThreadRunnable [%p]", this));
377 WorkerPrivate
* workerPrivate
= GetCurrentThreadWorkerPrivate();
378 MOZ_ASSERT_DEBUG_OR_FUZZING(workerPrivate
);
380 workerPrivate
->AssertIsOnWorkerThread();
383 if (!mCallingCancelWithinRun
&&
384 workerPrivate
->CancelBeforeWorkerScopeConstructed()) {
385 mCallingCancelWithinRun
= true;
387 mCallingCancelWithinRun
= false;
391 bool result
= PreRun(workerPrivate
);
393 workerPrivate
->AssertIsOnWorkerThread();
394 MOZ_ASSERT(!JS_IsExceptionPending(workerPrivate
->GetJSContext()));
395 // We can't enter a useful realm on the JSContext here; just pass it
397 PostRun(workerPrivate
->GetJSContext(), workerPrivate
, false);
398 return NS_ERROR_FAILURE
;
401 // Track down the appropriate global, if any, to use for the AutoEntryScript.
402 nsCOMPtr
<nsIGlobalObject
> globalObject
=
403 workerPrivate
->GetCurrentEventLoopGlobal();
405 globalObject
= DefaultGlobalObject(workerPrivate
);
406 // Our worker thread may not be in a good state here if there is no
407 // JSContext avaliable. The way this manifests itself is that
408 // globalObject ends up null (though it's not clear to me how we can be
409 // running runnables at all when default globalObject(DebuggerGlobalScope
410 // for debugger runnable, and GlobalScope for normal runnables) is returning
411 // false!) and then when we try to init the AutoJSAPI either
412 // CycleCollectedJSContext::Get() returns null or it has a null JSContext.
413 // In any case, we used to have a check for
414 // GetCurrentWorkerThreadJSContext() being non-null here and that seems to
415 // avoid the problem, so let's keep doing that check even if we don't need
416 // the JSContext here at all.
417 if (NS_WARN_IF(!globalObject
&& !GetCurrentWorkerThreadJSContext())) {
418 return NS_ERROR_FAILURE
;
422 // We might run script as part of WorkerRun, so we need an AutoEntryScript.
423 // This is part of the HTML spec for workers at:
424 // http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker
425 // If we don't have a globalObject we have to use an AutoJSAPI instead, but
426 // this is OK as we won't be running script in these circumstances.
427 Maybe
<mozilla::dom::AutoJSAPI
> maybeJSAPI
;
428 Maybe
<mozilla::dom::AutoEntryScript
> aes
;
432 aes
.emplace(globalObject
, "Worker runnable", false);
436 maybeJSAPI
.emplace();
438 jsapi
= maybeJSAPI
.ptr();
442 MOZ_ASSERT(!jsapi
->HasException());
443 result
= WorkerRun(cx
, workerPrivate
);
444 jsapi
->ReportException();
446 // We can't even assert that this didn't create our global, since in the case
447 // of CompileScriptRunnable it _does_.
449 // It would be nice to avoid passing a JSContext to PostRun, but in the case
450 // of ScriptExecutorRunnable we need to know the current compartment on the
451 // JSContext (the one we set up based on the global returned from PreRun) so
452 // that we can sanely do exception reporting. In particular, we want to make
453 // sure that we do our JS_SetPendingException while still in that compartment,
454 // because otherwise we might end up trying to create a cross-compartment
455 // wrapper when we try to move the JS exception from our runnable's
456 // ErrorResult to the JSContext, and that's not desirable in this case.
458 // We _could_ skip passing a JSContext here and then in
459 // ScriptExecutorRunnable::PostRun end up grabbing it from the WorkerPrivate
460 // and looking at its current compartment. But that seems like slightly weird
461 // action-at-a-distance...
463 // In any case, we do NOT try to change the compartment on the JSContext at
464 // this point; in the one case in which we could do that
465 // (CompileScriptRunnable) it actually doesn't matter which compartment we're
467 PostRun(cx
, workerPrivate
, result
);
468 MOZ_ASSERT(!jsapi
->HasException());
470 return result
? NS_OK
: NS_ERROR_FAILURE
;
473 nsresult
WorkerThreadRunnable::Cancel() {
474 LOG(("WorkerThreadRunnable::Cancel [%p]", this));
478 void WorkerDebuggerRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
479 bool aDispatchResult
) {}
481 WorkerSyncRunnable::WorkerSyncRunnable(nsIEventTarget
* aSyncLoopTarget
,
483 : WorkerThreadRunnable(aName
), mSyncLoopTarget(aSyncLoopTarget
) {}
485 WorkerSyncRunnable::WorkerSyncRunnable(
486 nsCOMPtr
<nsIEventTarget
>&& aSyncLoopTarget
, const char* aName
)
487 : WorkerThreadRunnable(aName
),
488 mSyncLoopTarget(std::move(aSyncLoopTarget
)) {}
490 WorkerSyncRunnable::~WorkerSyncRunnable() = default;
492 bool WorkerSyncRunnable::DispatchInternal(WorkerPrivate
* aWorkerPrivate
) {
493 if (mSyncLoopTarget
) {
495 aWorkerPrivate
->AssertValidSyncLoop(mSyncLoopTarget
);
497 RefPtr
<WorkerSyncRunnable
> runnable(this);
499 mSyncLoopTarget
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
));
502 return WorkerThreadRunnable::DispatchInternal(aWorkerPrivate
);
505 void MainThreadWorkerSyncRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
506 bool aDispatchResult
) {}
508 MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable(
509 nsCOMPtr
<nsIEventTarget
>&& aSyncLoopTarget
, nsresult aResult
)
510 : WorkerSyncRunnable(std::move(aSyncLoopTarget
)), mResult(aResult
) {
511 LOG(("MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable [%p]",
514 AssertIsOnMainThread();
517 nsresult
MainThreadStopSyncLoopRunnable::Cancel() {
518 LOG(("MainThreadStopSyncLoopRunnable::Cancel [%p]", this));
520 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
), "Run() failed");
525 bool MainThreadStopSyncLoopRunnable::WorkerRun(JSContext
* aCx
,
526 WorkerPrivate
* aWorkerPrivate
) {
527 aWorkerPrivate
->AssertIsOnWorkerThread();
528 MOZ_ASSERT(mSyncLoopTarget
);
530 nsCOMPtr
<nsIEventTarget
> syncLoopTarget
;
531 mSyncLoopTarget
.swap(syncLoopTarget
);
533 aWorkerPrivate
->StopSyncLoop(syncLoopTarget
, mResult
);
537 bool MainThreadStopSyncLoopRunnable::DispatchInternal(
538 WorkerPrivate
* aWorkerPrivate
) {
539 MOZ_ASSERT(mSyncLoopTarget
);
541 aWorkerPrivate
->AssertValidSyncLoop(mSyncLoopTarget
);
543 RefPtr
<MainThreadStopSyncLoopRunnable
> runnable(this);
545 mSyncLoopTarget
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
));
548 void MainThreadStopSyncLoopRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
549 bool aDispatchResult
) {}
551 WorkerControlRunnable::WorkerControlRunnable(const char* aName
)
552 : WorkerThreadRunnable(aName
) {}
554 nsresult
WorkerControlRunnable::Cancel() {
555 LOG(("WorkerControlRunnable::Cancel [%p]", this));
556 if (NS_FAILED(Run())) {
557 NS_WARNING("WorkerControlRunnable::Run() failed.");
563 WorkerMainThreadRunnable::WorkerMainThreadRunnable(
564 WorkerPrivate
* aWorkerPrivate
, const nsACString
& aTelemetryKey
,
565 const char* const aName
)
566 : mozilla::Runnable("dom::WorkerMainThreadRunnable"),
567 mTelemetryKey(aTelemetryKey
),
569 aWorkerPrivate
->AssertIsOnWorkerThread();
572 WorkerMainThreadRunnable::~WorkerMainThreadRunnable() = default;
574 void WorkerMainThreadRunnable::Dispatch(WorkerPrivate
* aWorkerPrivate
,
575 WorkerStatus aFailStatus
,
576 mozilla::ErrorResult
& aRv
) {
577 aWorkerPrivate
->AssertIsOnWorkerThread();
579 TimeStamp startTime
= TimeStamp::NowLoRes();
581 RefPtr
<StrongWorkerRef
> workerRef
;
582 if (aFailStatus
< Canceling
) {
583 // Nothing but logging debugging messages in the WorkerRef's
584 // shutdown callback.
585 // Stopping syncLoop in the shutdown callback could cause memory leaks or
586 // UAF when the main thread job completes.
588 StrongWorkerRef::Create(aWorkerPrivate
, mName
, [self
= RefPtr
{this}]() {
590 ("WorkerMainThreadRunnable::Dispatch [%p](%s) Worker starts to "
591 "shutdown while underlying SyncLoop is still running",
592 self
.get(), self
->mName
));
596 ("WorkerMainThreadRunnable::Dispatch [%p](%s) Creating a SyncLoop when"
597 "the Worker is shutting down",
599 workerRef
= StrongWorkerRef::CreateForcibly(aWorkerPrivate
, mName
);
602 // WorkerRef creation can fail if the worker is not in a valid status.
603 aRv
.ThrowInvalidStateError("The worker has already shut down");
606 mWorkerRef
= MakeRefPtr
<ThreadSafeWorkerRef
>(workerRef
);
608 AutoSyncLoopHolder
syncLoop(aWorkerPrivate
, aFailStatus
);
610 mSyncLoopTarget
= syncLoop
.GetSerialEventTarget();
611 if (!mSyncLoopTarget
) {
612 // SyncLoop creation can fail if the worker is shutting down.
613 aRv
.ThrowInvalidStateError("The worker is shutting down");
617 DebugOnly
<nsresult
> rv
= aWorkerPrivate
->DispatchToMainThread(this);
620 "Should only fail after xpcom-shutdown-threads and we're gone by then");
622 bool success
= NS_SUCCEEDED(syncLoop
.Run());
624 // syncLoop is done, release WorkerRef to unblock shutdown.
625 mWorkerRef
= nullptr;
627 glean::workers::sync_worker_operation
.Get(mTelemetryKey
)
628 .AccumulateRawDuration(TimeStamp::NowLoRes() - startTime
);
630 Unused
<< startTime
; // Shut the compiler up.
633 aRv
.ThrowUncatchableException();
638 WorkerMainThreadRunnable::Run() {
639 AssertIsOnMainThread();
641 // This shouldn't be necessary once we're better about making sure no workers
642 // are created during shutdown in earlier phases.
643 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads
)) {
644 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN
;
647 bool runResult
= MainThreadRun();
649 RefPtr
<MainThreadStopSyncLoopRunnable
> response
=
650 new MainThreadStopSyncLoopRunnable(std::move(mSyncLoopTarget
),
651 runResult
? NS_OK
: NS_ERROR_FAILURE
);
653 MOZ_ASSERT(mWorkerRef
);
654 MOZ_ALWAYS_TRUE(response
->Dispatch(mWorkerRef
->Private()));
659 bool WorkerSameThreadRunnable::PreDispatch(WorkerPrivate
* aWorkerPrivate
) {
660 aWorkerPrivate
->AssertIsOnWorkerThread();
664 void WorkerSameThreadRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
665 bool aDispatchResult
) {
666 aWorkerPrivate
->AssertIsOnWorkerThread();
669 WorkerProxyToMainThreadRunnable::WorkerProxyToMainThreadRunnable()
670 : mozilla::Runnable("dom::WorkerProxyToMainThreadRunnable") {}
672 WorkerProxyToMainThreadRunnable::~WorkerProxyToMainThreadRunnable() = default;
674 bool WorkerProxyToMainThreadRunnable::Dispatch(WorkerPrivate
* aWorkerPrivate
) {
675 MOZ_ASSERT(aWorkerPrivate
);
676 aWorkerPrivate
->AssertIsOnWorkerThread();
678 RefPtr
<StrongWorkerRef
> workerRef
= StrongWorkerRef::Create(
679 aWorkerPrivate
, "WorkerProxyToMainThreadRunnable");
680 if (NS_WARN_IF(!workerRef
)) {
681 RunBackOnWorkerThreadForCleanup(aWorkerPrivate
);
685 MOZ_ASSERT(!mWorkerRef
);
686 mWorkerRef
= new ThreadSafeWorkerRef(workerRef
);
689 ? NS_WARN_IF(NS_FAILED(
690 aWorkerPrivate
->DispatchToMainThreadForMessaging(this)))
691 : NS_WARN_IF(NS_FAILED(aWorkerPrivate
->DispatchToMainThread(this)))) {
693 RunBackOnWorkerThreadForCleanup(aWorkerPrivate
);
701 WorkerProxyToMainThreadRunnable::Run() {
702 AssertIsOnMainThread();
703 RunOnMainThread(mWorkerRef
->Private());
704 PostDispatchOnMainThread();
708 void WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread() {
709 class ReleaseRunnable final
: public MainThreadWorkerControlRunnable
{
710 RefPtr
<WorkerProxyToMainThreadRunnable
> mRunnable
;
713 explicit ReleaseRunnable(WorkerProxyToMainThreadRunnable
* aRunnable
)
714 : MainThreadWorkerControlRunnable("ReleaseRunnable"),
715 mRunnable(aRunnable
) {
716 MOZ_ASSERT(aRunnable
);
719 virtual nsresult
Cancel() override
{
720 MOZ_ASSERT(GetCurrentThreadWorkerPrivate());
721 Unused
<< WorkerRun(nullptr, GetCurrentThreadWorkerPrivate());
725 virtual bool WorkerRun(JSContext
* aCx
,
726 WorkerPrivate
* aWorkerPrivate
) override
{
727 MOZ_ASSERT(aWorkerPrivate
);
728 aWorkerPrivate
->AssertIsOnWorkerThread();
731 mRunnable
->RunBackOnWorkerThreadForCleanup(aWorkerPrivate
);
733 // Let's release the worker thread.
734 mRunnable
->ReleaseWorker();
742 ~ReleaseRunnable() = default;
745 RefPtr
<WorkerControlRunnable
> runnable
= new ReleaseRunnable(this);
746 Unused
<< NS_WARN_IF(!runnable
->Dispatch(mWorkerRef
->Private()));
749 void WorkerProxyToMainThreadRunnable::ReleaseWorker() { mWorkerRef
= nullptr; }
751 } // namespace mozilla::dom