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/DebugOnly.h"
17 #include "mozilla/ErrorResult.h"
18 #include "mozilla/Logging.h"
19 #include "mozilla/Maybe.h"
20 #include "mozilla/Telemetry.h"
21 #include "mozilla/TelemetryHistogramEnums.h"
22 #include "mozilla/TimeStamp.h"
23 #include "mozilla/Unused.h"
24 #include "mozilla/dom/ScriptSettings.h"
25 #include "mozilla/dom/Worker.h"
26 #include "mozilla/dom/WorkerCommon.h"
28 #include "nsGlobalWindowInner.h"
30 #include "nsIEventTarget.h"
31 #include "nsIGlobalObject.h"
32 #include "nsIRunnable.h"
33 #include "nsThreadUtils.h"
34 #include "nsWrapperCacheInlines.h"
36 namespace mozilla::dom
{
38 static mozilla::LazyLogModule
sWorkerRunnableLog("WorkerRunnable");
43 #define LOG(args) MOZ_LOG(sWorkerRunnableLog, LogLevel::Verbose, args);
47 const nsIID kWorkerRunnableIID
= {
51 {0x88, 0x6e, 0xca, 0x6a, 0x81, 0xe4, 0x1d, 0x68}};
56 WorkerRunnable::WorkerRunnable(WorkerPrivate
* aWorkerPrivate
,
57 TargetAndBusyBehavior aBehavior
)
58 : mWorkerPrivate(aWorkerPrivate
),
60 mCallingCancelWithinRun(false) {
61 LOG(("WorkerRunnable::WorkerRunnable [%p]", this));
62 MOZ_ASSERT(aWorkerPrivate
);
66 bool WorkerRunnable::IsDebuggerRunnable() const { return false; }
68 nsIGlobalObject
* WorkerRunnable::DefaultGlobalObject() const {
69 if (IsDebuggerRunnable()) {
70 return mWorkerPrivate
->DebuggerGlobalScope();
72 return mWorkerPrivate
->GlobalScope();
76 bool WorkerRunnable::PreDispatch(WorkerPrivate
* aWorkerPrivate
) {
78 MOZ_ASSERT(aWorkerPrivate
);
81 case ParentThreadUnchangedBusyCount
:
82 aWorkerPrivate
->AssertIsOnWorkerThread();
85 case WorkerThreadModifyBusyCount
:
86 case WorkerThreadUnchangedBusyCount
:
87 aWorkerPrivate
->AssertIsOnParentThread();
91 MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
95 if (mBehavior
== WorkerThreadModifyBusyCount
) {
96 return aWorkerPrivate
->ModifyBusyCount(true);
102 bool WorkerRunnable::Dispatch() {
103 bool ok
= PreDispatch(mWorkerPrivate
);
105 ok
= DispatchInternal();
107 PostDispatch(mWorkerPrivate
, ok
);
111 bool WorkerRunnable::DispatchInternal() {
112 LOG(("WorkerRunnable::DispatchInternal [%p]", this));
113 RefPtr
<WorkerRunnable
> runnable(this);
115 if (mBehavior
== WorkerThreadModifyBusyCount
||
116 mBehavior
== WorkerThreadUnchangedBusyCount
) {
117 if (IsDebuggerRunnable()) {
119 mWorkerPrivate
->DispatchDebuggerRunnable(runnable
.forget()));
121 return NS_SUCCEEDED(mWorkerPrivate
->Dispatch(runnable
.forget()));
125 MOZ_ASSERT(mBehavior
== ParentThreadUnchangedBusyCount
);
127 if (WorkerPrivate
* parent
= mWorkerPrivate
->GetParent()) {
128 return NS_SUCCEEDED(parent
->Dispatch(runnable
.forget()));
131 if (IsDebuggeeRunnable()) {
132 RefPtr
<WorkerDebuggeeRunnable
> debuggeeRunnable
=
133 runnable
.forget().downcast
<WorkerDebuggeeRunnable
>();
134 return NS_SUCCEEDED(mWorkerPrivate
->DispatchDebuggeeToMainThread(
135 debuggeeRunnable
.forget(), NS_DISPATCH_NORMAL
));
138 return NS_SUCCEEDED(mWorkerPrivate
->DispatchToMainThread(runnable
.forget()));
141 void WorkerRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
142 bool aDispatchResult
) {
143 MOZ_ASSERT(aWorkerPrivate
);
147 case ParentThreadUnchangedBusyCount
:
148 aWorkerPrivate
->AssertIsOnWorkerThread();
151 case WorkerThreadModifyBusyCount
:
152 aWorkerPrivate
->AssertIsOnParentThread();
155 case WorkerThreadUnchangedBusyCount
:
156 aWorkerPrivate
->AssertIsOnParentThread();
160 MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
164 if (!aDispatchResult
) {
165 if (mBehavior
== WorkerThreadModifyBusyCount
) {
166 aWorkerPrivate
->ModifyBusyCount(false);
171 bool WorkerRunnable::PreRun(WorkerPrivate
* aWorkerPrivate
) { return true; }
173 void WorkerRunnable::PostRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
,
176 MOZ_ASSERT(aWorkerPrivate
);
180 case ParentThreadUnchangedBusyCount
:
181 aWorkerPrivate
->AssertIsOnParentThread();
184 case WorkerThreadModifyBusyCount
:
185 aWorkerPrivate
->AssertIsOnWorkerThread();
188 case WorkerThreadUnchangedBusyCount
:
189 aWorkerPrivate
->AssertIsOnWorkerThread();
193 MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
197 if (mBehavior
== WorkerThreadModifyBusyCount
) {
198 aWorkerPrivate
->ModifyBusyCountFromWorker(false);
203 WorkerRunnable
* WorkerRunnable::FromRunnable(nsIRunnable
* aRunnable
) {
204 MOZ_ASSERT(aRunnable
);
206 WorkerRunnable
* runnable
;
207 nsresult rv
= aRunnable
->QueryInterface(kWorkerRunnableIID
,
208 reinterpret_cast<void**>(&runnable
));
213 MOZ_ASSERT(runnable
);
217 NS_IMPL_ADDREF(WorkerRunnable
)
218 NS_IMPL_RELEASE(WorkerRunnable
)
220 NS_INTERFACE_MAP_BEGIN(WorkerRunnable
)
221 NS_INTERFACE_MAP_ENTRY(nsIRunnable
)
222 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRunnable
)
223 // kWorkerRunnableIID is special in that it does not AddRef its result.
224 if (aIID
.Equals(kWorkerRunnableIID
)) {
225 *aInstancePtr
= this;
231 WorkerRunnable::Run() {
232 LOG(("WorkerRunnable::Run [%p]", this));
233 bool targetIsWorkerThread
= mBehavior
== WorkerThreadModifyBusyCount
||
234 mBehavior
== WorkerThreadUnchangedBusyCount
;
237 if (targetIsWorkerThread
) {
238 mWorkerPrivate
->AssertIsOnWorkerThread();
240 MOZ_ASSERT(mBehavior
== ParentThreadUnchangedBusyCount
);
241 mWorkerPrivate
->AssertIsOnParentThread();
245 if (targetIsWorkerThread
&& !mCallingCancelWithinRun
&&
246 mWorkerPrivate
->CancelBeforeWorkerScopeConstructed()) {
247 mCallingCancelWithinRun
= true;
249 mCallingCancelWithinRun
= false;
250 if (mBehavior
== WorkerThreadModifyBusyCount
) {
251 mWorkerPrivate
->ModifyBusyCountFromWorker(false);
256 bool result
= PreRun(mWorkerPrivate
);
258 MOZ_ASSERT(targetIsWorkerThread
,
259 "The only PreRun implementation that can fail is "
260 "ScriptExecutorRunnable");
261 mWorkerPrivate
->AssertIsOnWorkerThread();
262 MOZ_ASSERT(!JS_IsExceptionPending(mWorkerPrivate
->GetJSContext()));
263 // We can't enter a useful realm on the JSContext here; just pass it
265 PostRun(mWorkerPrivate
->GetJSContext(), mWorkerPrivate
, false);
266 return NS_ERROR_FAILURE
;
269 // Track down the appropriate global, if any, to use for the AutoEntryScript.
270 nsCOMPtr
<nsIGlobalObject
> globalObject
;
271 bool isMainThread
= !targetIsWorkerThread
&& !mWorkerPrivate
->GetParent();
272 MOZ_ASSERT(isMainThread
== NS_IsMainThread());
273 RefPtr
<WorkerPrivate
> kungFuDeathGrip
;
274 if (targetIsWorkerThread
) {
275 globalObject
= mWorkerPrivate
->GetCurrentEventLoopGlobal();
277 globalObject
= DefaultGlobalObject();
278 // Our worker thread may not be in a good state here if there is no
279 // JSContext avaliable. The way this manifests itself is that
280 // globalObject ends up null (though it's not clear to me how we can be
281 // running runnables at all when DefaultGlobalObject() is returning
282 // false!) and then when we try to init the AutoJSAPI either
283 // CycleCollectedJSContext::Get() returns null or it has a null JSContext.
284 // In any case, we used to have a check for
285 // GetCurrentWorkerThreadJSContext() being non-null here and that seems to
286 // avoid the problem, so let's keep doing that check even if we don't need
287 // the JSContext here at all.
288 if (NS_WARN_IF(!globalObject
&& !GetCurrentWorkerThreadJSContext())) {
289 return NS_ERROR_FAILURE
;
293 // We may still not have a globalObject here: in the case of
294 // CompileScriptRunnable, we don't actually create the global object until
295 // we have the script data, which happens in a syncloop under
296 // CompileScriptRunnable::WorkerRun, so we can't assert that it got created
297 // in the PreRun call above.
299 kungFuDeathGrip
= mWorkerPrivate
;
301 globalObject
= nsGlobalWindowInner::Cast(mWorkerPrivate
->GetWindow());
303 globalObject
= mWorkerPrivate
->GetParent()->GlobalScope();
307 // We might run script as part of WorkerRun, so we need an AutoEntryScript.
308 // This is part of the HTML spec for workers at:
309 // http://www.whatwg.org/specs/web-apps/current-work/#run-a-worker
310 // If we don't have a globalObject we have to use an AutoJSAPI instead, but
311 // this is OK as we won't be running script in these circumstances.
312 Maybe
<mozilla::dom::AutoJSAPI
> maybeJSAPI
;
313 Maybe
<mozilla::dom::AutoEntryScript
> aes
;
317 aes
.emplace(globalObject
, "Worker runnable", isMainThread
);
321 maybeJSAPI
.emplace();
323 jsapi
= maybeJSAPI
.ptr();
327 // Note that we can't assert anything about
328 // mWorkerPrivate->ParentEventTargetRef()->GetWrapper()
329 // existing, since it may in fact have been GCed (and we may be one of the
330 // runnables cleaning up the worker as a result).
332 // If we are on the parent thread and that thread is not the main thread,
333 // then we must be a dedicated worker (because there are no
334 // Shared/ServiceWorkers whose parent is itself a worker) and then we
335 // definitely have a globalObject. If it _is_ the main thread, globalObject
336 // can be null for workers started from JSMs or other non-window contexts,
338 MOZ_ASSERT_IF(!targetIsWorkerThread
&& !isMainThread
,
339 mWorkerPrivate
->IsDedicatedWorker() && globalObject
);
341 // If we're on the parent thread we might be in a null realm in the
342 // situation described above when globalObject is null. Make sure to enter
343 // the realm of the worker's reflector if there is one. There might
344 // not be one if we're just starting to compile the script for this worker.
345 Maybe
<JSAutoRealm
> ar
;
346 if (!targetIsWorkerThread
&& mWorkerPrivate
->IsDedicatedWorker() &&
347 mWorkerPrivate
->ParentEventTargetRef()->GetWrapper()) {
348 JSObject
* wrapper
= mWorkerPrivate
->ParentEventTargetRef()->GetWrapper();
350 // If we're on the parent thread and have a reflector and a globalObject,
351 // then the realms of cx, globalObject, and the worker's reflector
353 MOZ_ASSERT_IF(globalObject
,
354 js::GetNonCCWObjectRealm(wrapper
) == js::GetContextRealm(cx
));
355 MOZ_ASSERT_IF(globalObject
,
356 js::GetNonCCWObjectRealm(wrapper
) ==
357 js::GetNonCCWObjectRealm(
358 globalObject
->GetGlobalJSObjectPreserveColor()));
360 // If we're on the parent thread and have a reflector, then our
361 // JSContext had better be either in the null realm (and hence
362 // have no globalObject) or in the realm of our reflector.
363 MOZ_ASSERT(!js::GetContextRealm(cx
) ||
364 js::GetNonCCWObjectRealm(wrapper
) == js::GetContextRealm(cx
),
365 "Must either be in the null compartment or in our reflector "
368 ar
.emplace(cx
, wrapper
);
371 MOZ_ASSERT(!jsapi
->HasException());
372 result
= WorkerRun(cx
, mWorkerPrivate
);
373 jsapi
->ReportException();
375 // We can't even assert that this didn't create our global, since in the case
376 // of CompileScriptRunnable it _does_.
378 // It would be nice to avoid passing a JSContext to PostRun, but in the case
379 // of ScriptExecutorRunnable we need to know the current compartment on the
380 // JSContext (the one we set up based on the global returned from PreRun) so
381 // that we can sanely do exception reporting. In particular, we want to make
382 // sure that we do our JS_SetPendingException while still in that compartment,
383 // because otherwise we might end up trying to create a cross-compartment
384 // wrapper when we try to move the JS exception from our runnable's
385 // ErrorResult to the JSContext, and that's not desirable in this case.
387 // We _could_ skip passing a JSContext here and then in
388 // ScriptExecutorRunnable::PostRun end up grabbing it from the WorkerPrivate
389 // and looking at its current compartment. But that seems like slightly weird
390 // action-at-a-distance...
392 // In any case, we do NOT try to change the compartment on the JSContext at
393 // this point; in the one case in which we could do that
394 // (CompileScriptRunnable) it actually doesn't matter which compartment we're
396 PostRun(cx
, mWorkerPrivate
, result
);
397 MOZ_ASSERT(!jsapi
->HasException());
399 return result
? NS_OK
: NS_ERROR_FAILURE
;
402 nsresult
WorkerRunnable::Cancel() {
403 LOG(("WorkerRunnable::Cancel [%p]", this));
407 void WorkerDebuggerRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
408 bool aDispatchResult
) {}
410 WorkerSyncRunnable::WorkerSyncRunnable(WorkerPrivate
* aWorkerPrivate
,
411 nsIEventTarget
* aSyncLoopTarget
)
412 : WorkerRunnable(aWorkerPrivate
, WorkerThreadUnchangedBusyCount
),
413 mSyncLoopTarget(aSyncLoopTarget
) {
415 if (mSyncLoopTarget
) {
416 mWorkerPrivate
->AssertValidSyncLoop(mSyncLoopTarget
);
421 WorkerSyncRunnable::WorkerSyncRunnable(
422 WorkerPrivate
* aWorkerPrivate
, nsCOMPtr
<nsIEventTarget
>&& aSyncLoopTarget
)
423 : WorkerRunnable(aWorkerPrivate
, WorkerThreadUnchangedBusyCount
),
424 mSyncLoopTarget(std::move(aSyncLoopTarget
)) {
426 if (mSyncLoopTarget
) {
427 mWorkerPrivate
->AssertValidSyncLoop(mSyncLoopTarget
);
432 WorkerSyncRunnable::~WorkerSyncRunnable() = default;
434 bool WorkerSyncRunnable::DispatchInternal() {
435 if (mSyncLoopTarget
) {
436 RefPtr
<WorkerSyncRunnable
> runnable(this);
438 mSyncLoopTarget
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
));
441 return WorkerRunnable::DispatchInternal();
444 void MainThreadWorkerSyncRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
445 bool aDispatchResult
) {}
447 MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable(
448 WorkerPrivate
* aWorkerPrivate
, nsCOMPtr
<nsIEventTarget
>&& aSyncLoopTarget
,
450 : WorkerSyncRunnable(aWorkerPrivate
, std::move(aSyncLoopTarget
)),
452 LOG(("MainThreadStopSyncLoopRunnable::MainThreadStopSyncLoopRunnable [%p]",
455 AssertIsOnMainThread();
457 mWorkerPrivate
->AssertValidSyncLoop(mSyncLoopTarget
);
461 nsresult
MainThreadStopSyncLoopRunnable::Cancel() {
462 LOG(("MainThreadStopSyncLoopRunnable::Cancel [%p]", this));
464 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv
), "Run() failed");
469 bool MainThreadStopSyncLoopRunnable::WorkerRun(JSContext
* aCx
,
470 WorkerPrivate
* aWorkerPrivate
) {
471 aWorkerPrivate
->AssertIsOnWorkerThread();
472 MOZ_ASSERT(mSyncLoopTarget
);
474 nsCOMPtr
<nsIEventTarget
> syncLoopTarget
;
475 mSyncLoopTarget
.swap(syncLoopTarget
);
477 aWorkerPrivate
->StopSyncLoop(syncLoopTarget
, mResult
);
481 bool MainThreadStopSyncLoopRunnable::DispatchInternal() {
482 MOZ_ASSERT(mSyncLoopTarget
);
484 RefPtr
<MainThreadStopSyncLoopRunnable
> runnable(this);
486 mSyncLoopTarget
->Dispatch(runnable
.forget(), NS_DISPATCH_NORMAL
));
489 void MainThreadStopSyncLoopRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
490 bool aDispatchResult
) {}
493 WorkerControlRunnable::WorkerControlRunnable(WorkerPrivate
* aWorkerPrivate
,
494 TargetAndBusyBehavior aBehavior
)
495 : WorkerRunnable(aWorkerPrivate
, aBehavior
) {
496 MOZ_ASSERT(aWorkerPrivate
);
497 MOZ_ASSERT(aBehavior
== ParentThreadUnchangedBusyCount
||
498 aBehavior
== WorkerThreadUnchangedBusyCount
,
499 "WorkerControlRunnables should not modify the busy count");
503 nsresult
WorkerControlRunnable::Cancel() {
504 LOG(("WorkerControlRunnable::Cancel [%p]", this));
505 if (NS_FAILED(Run())) {
506 NS_WARNING("WorkerControlRunnable::Run() failed.");
512 bool WorkerControlRunnable::DispatchInternal() {
513 RefPtr
<WorkerControlRunnable
> runnable(this);
515 if (mBehavior
== WorkerThreadUnchangedBusyCount
) {
517 mWorkerPrivate
->DispatchControlRunnable(runnable
.forget()));
520 if (WorkerPrivate
* parent
= mWorkerPrivate
->GetParent()) {
521 return NS_SUCCEEDED(parent
->DispatchControlRunnable(runnable
.forget()));
524 return NS_SUCCEEDED(mWorkerPrivate
->DispatchToMainThread(runnable
.forget()));
527 WorkerMainThreadRunnable::WorkerMainThreadRunnable(
528 WorkerPrivate
* aWorkerPrivate
, const nsACString
& aTelemetryKey
)
529 : mozilla::Runnable("dom::WorkerMainThreadRunnable"),
530 mWorkerPrivate(aWorkerPrivate
),
531 mTelemetryKey(aTelemetryKey
) {
532 mWorkerPrivate
->AssertIsOnWorkerThread();
535 WorkerMainThreadRunnable::~WorkerMainThreadRunnable() = default;
537 void WorkerMainThreadRunnable::Dispatch(WorkerStatus aFailStatus
,
538 mozilla::ErrorResult
& aRv
) {
539 mWorkerPrivate
->AssertIsOnWorkerThread();
541 TimeStamp startTime
= TimeStamp::NowLoRes();
543 AutoSyncLoopHolder
syncLoop(mWorkerPrivate
, aFailStatus
);
545 mSyncLoopTarget
= syncLoop
.GetSerialEventTarget();
546 if (!mSyncLoopTarget
) {
547 // SyncLoop creation can fail if the worker is shutting down.
548 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
552 DebugOnly
<nsresult
> rv
= mWorkerPrivate
->DispatchToMainThread(this);
555 "Should only fail after xpcom-shutdown-threads and we're gone by then");
557 bool success
= NS_SUCCEEDED(syncLoop
.Run());
559 Telemetry::Accumulate(
560 Telemetry::SYNC_WORKER_OPERATION
, mTelemetryKey
,
561 static_cast<uint32_t>(
562 (TimeStamp::NowLoRes() - startTime
).ToMilliseconds()));
564 Unused
<< startTime
; // Shut the compiler up.
567 aRv
.ThrowUncatchableException();
572 WorkerMainThreadRunnable::Run() {
573 AssertIsOnMainThread();
575 // This shouldn't be necessary once we're better about making sure no workers
576 // are created during shutdown in earlier phases.
577 if (AppShutdown::IsInOrBeyond(ShutdownPhase::XPCOMShutdownThreads
)) {
578 return NS_ERROR_ILLEGAL_DURING_SHUTDOWN
;
581 bool runResult
= MainThreadRun();
583 RefPtr
<MainThreadStopSyncLoopRunnable
> response
=
584 new MainThreadStopSyncLoopRunnable(mWorkerPrivate
,
585 std::move(mSyncLoopTarget
),
586 runResult
? NS_OK
: NS_ERROR_FAILURE
);
588 MOZ_ALWAYS_TRUE(response
->Dispatch());
593 bool WorkerSameThreadRunnable::PreDispatch(WorkerPrivate
* aWorkerPrivate
) {
594 // We don't call WorkerRunnable::PreDispatch, because we're using
595 // WorkerThreadModifyBusyCount for mBehavior, and WorkerRunnable will assert
596 // that PreDispatch is on the parent thread in that case.
597 aWorkerPrivate
->AssertIsOnWorkerThread();
601 void WorkerSameThreadRunnable::PostDispatch(WorkerPrivate
* aWorkerPrivate
,
602 bool aDispatchResult
) {
603 // We don't call WorkerRunnable::PostDispatch, because we're using
604 // WorkerThreadModifyBusyCount for mBehavior, and WorkerRunnable will assert
605 // that PostDispatch is on the parent thread in that case.
606 aWorkerPrivate
->AssertIsOnWorkerThread();
607 if (aDispatchResult
) {
608 DebugOnly
<bool> willIncrement
=
609 aWorkerPrivate
->ModifyBusyCountFromWorker(true);
610 // Should never fail since if this thread is still running, so should the
611 // parent and it should be able to process a control runnable.
612 MOZ_ASSERT(willIncrement
);
616 WorkerProxyToMainThreadRunnable::WorkerProxyToMainThreadRunnable()
617 : mozilla::Runnable("dom::WorkerProxyToMainThreadRunnable") {}
619 WorkerProxyToMainThreadRunnable::~WorkerProxyToMainThreadRunnable() = default;
621 bool WorkerProxyToMainThreadRunnable::Dispatch(WorkerPrivate
* aWorkerPrivate
) {
622 MOZ_ASSERT(aWorkerPrivate
);
623 aWorkerPrivate
->AssertIsOnWorkerThread();
625 RefPtr
<StrongWorkerRef
> workerRef
= StrongWorkerRef::Create(
626 aWorkerPrivate
, "WorkerProxyToMainThreadRunnable");
627 if (NS_WARN_IF(!workerRef
)) {
628 RunBackOnWorkerThreadForCleanup(aWorkerPrivate
);
632 MOZ_ASSERT(!mWorkerRef
);
633 mWorkerRef
= new ThreadSafeWorkerRef(workerRef
);
636 ? NS_WARN_IF(NS_FAILED(
637 aWorkerPrivate
->DispatchToMainThreadForMessaging(this)))
638 : NS_WARN_IF(NS_FAILED(aWorkerPrivate
->DispatchToMainThread(this)))) {
640 RunBackOnWorkerThreadForCleanup(aWorkerPrivate
);
648 WorkerProxyToMainThreadRunnable::Run() {
649 AssertIsOnMainThread();
650 RunOnMainThread(mWorkerRef
->Private());
651 PostDispatchOnMainThread();
655 void WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread() {
656 class ReleaseRunnable final
: public MainThreadWorkerControlRunnable
{
657 RefPtr
<WorkerProxyToMainThreadRunnable
> mRunnable
;
660 ReleaseRunnable(WorkerPrivate
* aWorkerPrivate
,
661 WorkerProxyToMainThreadRunnable
* aRunnable
)
662 : MainThreadWorkerControlRunnable(aWorkerPrivate
),
663 mRunnable(aRunnable
) {
664 MOZ_ASSERT(aRunnable
);
667 virtual nsresult
Cancel() override
{
668 Unused
<< WorkerRun(nullptr, mWorkerPrivate
);
672 virtual bool WorkerRun(JSContext
* aCx
,
673 WorkerPrivate
* aWorkerPrivate
) override
{
674 MOZ_ASSERT(aWorkerPrivate
);
675 aWorkerPrivate
->AssertIsOnWorkerThread();
678 mRunnable
->RunBackOnWorkerThreadForCleanup(aWorkerPrivate
);
680 // Let's release the worker thread.
681 mRunnable
->ReleaseWorker();
689 ~ReleaseRunnable() = default;
692 RefPtr
<WorkerControlRunnable
> runnable
=
693 new ReleaseRunnable(mWorkerRef
->Private(), this);
694 Unused
<< NS_WARN_IF(!runnable
->Dispatch());
697 void WorkerProxyToMainThreadRunnable::ReleaseWorker() { mWorkerRef
= nullptr; }
699 bool WorkerDebuggeeRunnable::PreDispatch(WorkerPrivate
* aWorkerPrivate
) {
700 if (mBehavior
== ParentThreadUnchangedBusyCount
) {
701 RefPtr
<StrongWorkerRef
> strongRef
= StrongWorkerRef::Create(
702 aWorkerPrivate
, "WorkerDebuggeeRunnable::mSender");
707 mSender
= new ThreadSafeWorkerRef(strongRef
);
710 return WorkerRunnable::PreDispatch(aWorkerPrivate
);
713 } // namespace mozilla::dom