mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-07 01:44:42 +00:00
Bug 1836700 - Remove BusyCount of WorkerPrivate. r=asuth,ipc-reviewers,mccr8
Differential Revision: https://phabricator.services.mozilla.com/D182718
This commit is contained in:
parent
ce4599d3d4
commit
76d6e6b69c
@ -1825,7 +1825,7 @@ class WorkerRunnableDispatcher final : public WorkerRunnable {
|
||||
WorkerRunnableDispatcher(RefPtr<EventSourceImpl>&& aImpl,
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
already_AddRefed<nsIRunnable> aEvent)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread),
|
||||
mEventSourceImpl(std::move(aImpl)),
|
||||
mEvent(std::move(aEvent)) {}
|
||||
|
||||
|
@ -96,7 +96,7 @@ class TeardownRunnableOnWorker final : public WorkerControlRunnable,
|
||||
public:
|
||||
TeardownRunnableOnWorker(WorkerPrivate* aWorkerPrivate,
|
||||
BroadcastChannelChild* aActor)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
TeardownRunnable(aActor) {}
|
||||
|
||||
bool WorkerRun(JSContext*, WorkerPrivate*) override {
|
||||
|
9
dom/cache/CacheWorkerRef.cpp
vendored
9
dom/cache/CacheWorkerRef.cpp
vendored
@ -69,6 +69,10 @@ void CacheWorkerRef::AddActor(ActorChild& aActor) {
|
||||
MOZ_ASSERT(!mActorList.Contains(&aActor));
|
||||
|
||||
mActorList.AppendElement(WrapNotNullUnchecked(&aActor));
|
||||
if (mBehavior == eIPCWorkerRef) {
|
||||
MOZ_ASSERT(mIPCWorkerRef);
|
||||
mIPCWorkerRef->SetActorCount(mActorList.Length());
|
||||
}
|
||||
|
||||
// Allow an actor to be added after we've entered the Notifying case. We
|
||||
// can't stop the actor creation from racing with out destruction of the
|
||||
@ -90,6 +94,11 @@ void CacheWorkerRef::RemoveActor(ActorChild& aActor) {
|
||||
|
||||
MOZ_ASSERT(!mActorList.Contains(&aActor));
|
||||
|
||||
if (mBehavior == eIPCWorkerRef) {
|
||||
MOZ_ASSERT(mIPCWorkerRef);
|
||||
mIPCWorkerRef->SetActorCount(mActorList.Length());
|
||||
}
|
||||
|
||||
if (mActorList.IsEmpty()) {
|
||||
mStrongWorkerRef = nullptr;
|
||||
mIPCWorkerRef = nullptr;
|
||||
|
@ -312,7 +312,6 @@ class NotificationWorkerRunnable : public MainThreadWorkerRunnable {
|
||||
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(true);
|
||||
// WorkerScope might start dying at the moment. And WorkerRunInternal()
|
||||
// should not be executed once WorkerScope is dying, since
|
||||
// WorkerRunInternal() might access resources which already been freed
|
||||
@ -324,11 +323,6 @@ class NotificationWorkerRunnable : public MainThreadWorkerRunnable {
|
||||
return true;
|
||||
}
|
||||
|
||||
void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
bool aRunResult) override {
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(false);
|
||||
}
|
||||
|
||||
virtual void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) = 0;
|
||||
};
|
||||
|
||||
@ -361,7 +355,6 @@ class ReleaseNotificationRunnable final : public NotificationWorkerRunnable {
|
||||
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(true);
|
||||
// ReleaseNotificationRunnable is only used in StrongWorkerRef's shutdown
|
||||
// callback. At the moment, it is supposed to executing
|
||||
// mNotification->ReleaseObject() safely even though the corresponding
|
||||
|
@ -39,7 +39,7 @@ class PerformanceEntryAdder final : public WorkerControlRunnable {
|
||||
PerformanceEntryAdder(WorkerPrivate* aWorkerPrivate,
|
||||
PerformanceStorageWorker* aStorage,
|
||||
UniquePtr<PerformanceProxyData>&& aData)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mStorage(aStorage),
|
||||
mData(std::move(aData)) {}
|
||||
|
||||
|
@ -776,8 +776,7 @@ class PromiseWorkerProxyRunnable : public WorkerRunnable {
|
||||
public:
|
||||
PromiseWorkerProxyRunnable(PromiseWorkerProxy* aPromiseWorkerProxy,
|
||||
PromiseWorkerProxy::RunCallbackFunc aFunc)
|
||||
: WorkerRunnable(aPromiseWorkerProxy->GetWorkerPrivate(),
|
||||
WorkerThreadUnchangedBusyCount),
|
||||
: WorkerRunnable(aPromiseWorkerProxy->GetWorkerPrivate(), WorkerThread),
|
||||
mPromiseWorkerProxy(aPromiseWorkerProxy),
|
||||
mFunc(aFunc) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
@ -277,7 +277,7 @@ class ServiceWorkerOp::ServiceWorkerOpRunnable : public WorkerDebuggeeRunnable {
|
||||
|
||||
ServiceWorkerOpRunnable(RefPtr<ServiceWorkerOp> aOwner,
|
||||
WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate, WorkerThread),
|
||||
mOwner(std::move(aOwner)) {
|
||||
AssertIsOnMainThread();
|
||||
MOZ_ASSERT(mOwner);
|
||||
@ -856,10 +856,7 @@ class NotificationEventOp : public ExtendableEventOp,
|
||||
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 modyfing 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.
|
||||
// fails, we still clean the interaction count correctly.
|
||||
uint32_t delay = mArgs.get_ServiceWorkerNotificationEventOpArgs()
|
||||
.disableOpenClickDelay();
|
||||
rv = mTimer->InitWithCallback(this, delay, nsITimer::TYPE_ONE_SHOT);
|
||||
|
@ -2740,7 +2740,7 @@ class WorkerRunnableDispatcher final : public WorkerRunnable {
|
||||
WorkerRunnableDispatcher(WebSocketImpl* aImpl,
|
||||
ThreadSafeWorkerRef* aWorkerRef,
|
||||
already_AddRefed<nsIRunnable> aEvent)
|
||||
: WorkerRunnable(aWorkerRef->Private(), WorkerThreadUnchangedBusyCount),
|
||||
: WorkerRunnable(aWorkerRef->Private(), WorkerThread),
|
||||
mWebSocketImpl(aImpl),
|
||||
mEvent(std::move(aEvent)) {}
|
||||
|
||||
|
@ -33,7 +33,7 @@
|
||||
namespace mozilla::dom {
|
||||
EventWithOptionsRunnable::EventWithOptionsRunnable(Worker& aWorker)
|
||||
: WorkerDebuggeeRunnable(aWorker.mWorkerPrivate,
|
||||
WorkerRunnable::WorkerThreadModifyBusyCount),
|
||||
WorkerRunnable::WorkerThread),
|
||||
StructuredCloneHolder(CloningSupported, TransferringSupported,
|
||||
StructuredCloneScope::SameProcess) {}
|
||||
|
||||
@ -131,7 +131,7 @@ bool EventWithOptionsRunnable::BuildAndFireEvent(
|
||||
|
||||
bool EventWithOptionsRunnable::WorkerRun(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate) {
|
||||
if (mBehavior == ParentThreadUnchangedBusyCount) {
|
||||
if (mTarget == ParentThread) {
|
||||
// Don't fire this event if the JS object has been disconnected from the
|
||||
// private object.
|
||||
if (!aWorkerPrivate->IsAcceptingEvents()) {
|
||||
|
@ -15,8 +15,8 @@
|
||||
namespace mozilla::dom {
|
||||
|
||||
MessageEventRunnable::MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior)
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate, aBehavior),
|
||||
Target aTarget)
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate, aTarget),
|
||||
StructuredCloneHolder(CloningSupported, TransferringSupported,
|
||||
StructuredCloneScope::SameProcess) {}
|
||||
|
||||
@ -84,7 +84,7 @@ bool MessageEventRunnable::DispatchDOMEvent(JSContext* aCx,
|
||||
|
||||
bool MessageEventRunnable::WorkerRun(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate) {
|
||||
if (mBehavior == ParentThreadUnchangedBusyCount) {
|
||||
if (mTarget == ParentThread) {
|
||||
// Don't fire this event if the JS object has been disconnected from the
|
||||
// private object.
|
||||
if (!aWorkerPrivate->IsAcceptingEvents()) {
|
||||
|
@ -20,8 +20,7 @@ namespace dom {
|
||||
class MessageEventRunnable final : public WorkerDebuggeeRunnable,
|
||||
public StructuredCloneHolder {
|
||||
public:
|
||||
MessageEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior);
|
||||
MessageEventRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget);
|
||||
|
||||
bool DispatchDOMEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
DOMEventTargetHelper* aTarget, bool aIsMainThread);
|
||||
|
@ -602,8 +602,7 @@ class JSDispatchableRunnable final : public WorkerRunnable {
|
||||
public:
|
||||
JSDispatchableRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
JS::Dispatchable* aDispatchable)
|
||||
: WorkerRunnable(aWorkerPrivate,
|
||||
WorkerRunnable::WorkerThreadUnchangedBusyCount),
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerRunnable::WorkerThread),
|
||||
mDispatchable(aDispatchable) {
|
||||
MOZ_ASSERT(mDispatchable);
|
||||
}
|
||||
@ -1461,7 +1460,7 @@ namespace {
|
||||
class DumpCrashInfoRunnable : public WorkerControlRunnable {
|
||||
public:
|
||||
explicit DumpCrashInfoRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mMonitor("DumpCrashInfoRunnable::mMonitor") {}
|
||||
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||
@ -1525,12 +1524,7 @@ struct ActiveWorkerStats {
|
||||
new DumpCrashInfoRunnable(worker);
|
||||
if (runnable->DispatchAndWait()) {
|
||||
++(this->*Category);
|
||||
|
||||
// BC: Busy Count
|
||||
mMessage.AppendPrintf("-BC:%d", worker->BusyCount());
|
||||
mMessage.Append(runnable->MsgData());
|
||||
} else {
|
||||
mMessage.AppendPrintf("-BC:%d DispatchFailed", worker->BusyCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1985,8 +1979,6 @@ void LogWorker(WorkerPrivate* worker, const char* category) {
|
||||
worker->GetLoadingPrincipal()->GetOrigin(loadingOrigin);
|
||||
SHUTDOWN_LOG(("LoadingPrincipal: %s", loadingOrigin.get()));
|
||||
|
||||
SHUTDOWN_LOG(("BusyCount: %d", worker->BusyCount()));
|
||||
|
||||
RefPtr<DumpCrashInfoRunnable> runnable = new DumpCrashInfoRunnable(worker);
|
||||
if (runnable->DispatchAndWait()) {
|
||||
SHUTDOWN_LOG(("CrashInfo: %s", runnable->MsgData().get()));
|
||||
|
@ -119,8 +119,8 @@ void Worker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
"Worker.postMessage", nameOrScriptURL.get(),
|
||||
JS::ProfilingCategoryPair::DOM, flags);
|
||||
|
||||
RefPtr<MessageEventRunnable> runnable = new MessageEventRunnable(
|
||||
mWorkerPrivate, WorkerRunnable::WorkerThreadModifyBusyCount);
|
||||
RefPtr<MessageEventRunnable> runnable =
|
||||
new MessageEventRunnable(mWorkerPrivate, WorkerRunnable::WorkerThread);
|
||||
|
||||
JS::CloneDataPolicy clonePolicy;
|
||||
// DedicatedWorkers are always part of the same agent cluster.
|
||||
|
@ -34,7 +34,7 @@ class WrappedControlRunnable final : public WorkerControlRunnable {
|
||||
public:
|
||||
WrappedControlRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
nsCOMPtr<nsIRunnable>&& aInner)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mInner(std::move(aInner)) {}
|
||||
|
||||
virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
|
||||
|
@ -61,6 +61,8 @@
|
||||
#include "mozilla/dom/WindowContext.h"
|
||||
#include "mozilla/extensions/ExtensionBrowser.h" // extensions::Create{AndDispatchInitWorkerContext,WorkerLoaded,WorkerDestroyed}Runnable
|
||||
#include "mozilla/extensions/WebExtensionPolicy.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/StorageAccess.h"
|
||||
#include "mozilla/StoragePrincipalHelper.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
@ -182,7 +184,7 @@ class ExternalRunnableWrapper final : public WorkerRunnable {
|
||||
public:
|
||||
ExternalRunnableWrapper(WorkerPrivate* aWorkerPrivate,
|
||||
nsIRunnable* aWrappedRunnable)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread),
|
||||
mWrappedRunnable(aWrappedRunnable) {
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
MOZ_ASSERT(aWrappedRunnable);
|
||||
@ -245,7 +247,7 @@ class WorkerFinishedRunnable final : public WorkerControlRunnable {
|
||||
public:
|
||||
WorkerFinishedRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
WorkerPrivate* aFinishedWorker)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mFinishedWorker(aFinishedWorker) {
|
||||
aFinishedWorker->IncreaseWorkerFinishedRunnableCount();
|
||||
}
|
||||
@ -322,31 +324,6 @@ class TopLevelWorkerFinishedRunnable final : public Runnable {
|
||||
}
|
||||
};
|
||||
|
||||
class ModifyBusyCountRunnable final : public WorkerControlRunnable {
|
||||
bool mIncrease;
|
||||
|
||||
public:
|
||||
ModifyBusyCountRunnable(WorkerPrivate* aWorkerPrivate, bool aIncrease)
|
||||
: WorkerControlRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
|
||||
mIncrease(aIncrease) {}
|
||||
|
||||
private:
|
||||
virtual bool WorkerRun(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate) override {
|
||||
return aWorkerPrivate->ModifyBusyCount(mIncrease);
|
||||
}
|
||||
|
||||
virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
bool aRunResult) override {
|
||||
if (mIncrease) {
|
||||
WorkerControlRunnable::PostRun(aCx, aWorkerPrivate, aRunResult);
|
||||
return;
|
||||
}
|
||||
// Don't do anything here as it's possible that aWorkerPrivate has been
|
||||
// deleted.
|
||||
}
|
||||
};
|
||||
|
||||
class CompileScriptRunnable final : public WorkerDebuggeeRunnable {
|
||||
nsString mScriptURL;
|
||||
const mozilla::Encoding* mDocumentEncoding;
|
||||
@ -357,7 +334,7 @@ class CompileScriptRunnable final : public WorkerDebuggeeRunnable {
|
||||
UniquePtr<SerializedStackHolder> aOriginStack,
|
||||
const nsAString& aScriptURL,
|
||||
const mozilla::Encoding* aDocumentEncoding)
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate, WorkerThread),
|
||||
mScriptURL(aScriptURL),
|
||||
mDocumentEncoding(aDocumentEncoding),
|
||||
mOriginStack(aOriginStack.release()) {}
|
||||
@ -464,8 +441,7 @@ class NotifyRunnable final : public WorkerControlRunnable {
|
||||
|
||||
public:
|
||||
NotifyRunnable(WorkerPrivate* aWorkerPrivate, WorkerStatus aStatus)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
mStatus(aStatus) {
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread), mStatus(aStatus) {
|
||||
MOZ_ASSERT(aStatus == Closing || aStatus == Canceling ||
|
||||
aStatus == Killing);
|
||||
}
|
||||
@ -473,34 +449,27 @@ class NotifyRunnable final : public WorkerControlRunnable {
|
||||
private:
|
||||
virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate) override {
|
||||
aWorkerPrivate->AssertIsOnParentThread();
|
||||
return aWorkerPrivate->ModifyBusyCount(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult) override {
|
||||
aWorkerPrivate->AssertIsOnParentThread();
|
||||
if (!aDispatchResult) {
|
||||
// We couldn't dispatch to the worker, which means it's already dead.
|
||||
// Undo the busy count modification.
|
||||
aWorkerPrivate->ModifyBusyCount(false);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
bool aRunResult) override {
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(false);
|
||||
}
|
||||
|
||||
virtual bool WorkerRun(JSContext* aCx,
|
||||
WorkerPrivate* aWorkerPrivate) override {
|
||||
return aWorkerPrivate->NotifyInternal(mStatus);
|
||||
}
|
||||
|
||||
virtual void PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
bool aRunResult) override {}
|
||||
};
|
||||
|
||||
class FreezeRunnable final : public WorkerControlRunnable {
|
||||
public:
|
||||
explicit FreezeRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread) {}
|
||||
|
||||
private:
|
||||
virtual bool WorkerRun(JSContext* aCx,
|
||||
@ -512,7 +481,7 @@ class FreezeRunnable final : public WorkerControlRunnable {
|
||||
class ThawRunnable final : public WorkerControlRunnable {
|
||||
public:
|
||||
explicit ThawRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread) {}
|
||||
|
||||
private:
|
||||
virtual bool WorkerRun(JSContext* aCx,
|
||||
@ -526,7 +495,7 @@ class PropagateStorageAccessPermissionGrantedRunnable final
|
||||
public:
|
||||
explicit PropagateStorageAccessPermissionGrantedRunnable(
|
||||
WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread) {}
|
||||
|
||||
private:
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||
@ -567,7 +536,7 @@ class ReportErrorToConsoleRunnable final : public WorkerRunnable {
|
||||
ReportErrorToConsoleRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
const char* aMessage,
|
||||
const nsTArray<nsString>& aParams)
|
||||
: WorkerRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount),
|
||||
: WorkerRunnable(aWorkerPrivate, ParentThread),
|
||||
mMessage(aMessage),
|
||||
mParams(aParams.Clone()) {}
|
||||
|
||||
@ -595,7 +564,7 @@ class TimerRunnable final : public WorkerRunnable,
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
explicit TimerRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread) {}
|
||||
|
||||
private:
|
||||
~TimerRunnable() = default;
|
||||
@ -637,8 +606,7 @@ class DebuggerImmediateRunnable : public WorkerRunnable {
|
||||
public:
|
||||
explicit DebuggerImmediateRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
dom::Function& aHandler)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
mHandler(&aHandler) {}
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread), mHandler(&aHandler) {}
|
||||
|
||||
private:
|
||||
virtual bool IsDebuggerRunnable() const override { return true; }
|
||||
@ -698,7 +666,7 @@ class UpdateContextOptionsRunnable final : public WorkerControlRunnable {
|
||||
public:
|
||||
UpdateContextOptionsRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
const JS::ContextOptions& aContextOptions)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mContextOptions(aContextOptions) {}
|
||||
|
||||
private:
|
||||
@ -733,7 +701,7 @@ class UpdateJSWorkerMemoryParameterRunnable final
|
||||
UpdateJSWorkerMemoryParameterRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
JSGCParamKey aKey,
|
||||
Maybe<uint32_t> aValue)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mValue(aValue),
|
||||
mKey(aKey) {}
|
||||
|
||||
@ -753,7 +721,7 @@ class UpdateGCZealRunnable final : public WorkerControlRunnable {
|
||||
public:
|
||||
UpdateGCZealRunnable(WorkerPrivate* aWorkerPrivate, uint8_t aGCZeal,
|
||||
uint32_t aFrequency)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mGCZeal(aGCZeal),
|
||||
mFrequency(aFrequency) {}
|
||||
|
||||
@ -771,8 +739,7 @@ class SetLowMemoryStateRunnable final : public WorkerControlRunnable {
|
||||
|
||||
public:
|
||||
SetLowMemoryStateRunnable(WorkerPrivate* aWorkerPrivate, bool aState)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
mState(aState) {}
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread), mState(aState) {}
|
||||
|
||||
private:
|
||||
virtual bool WorkerRun(JSContext* aCx,
|
||||
@ -789,7 +756,7 @@ class GarbageCollectRunnable final : public WorkerControlRunnable {
|
||||
public:
|
||||
GarbageCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aShrinking,
|
||||
bool aCollectChildren)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mShrinking(aShrinking),
|
||||
mCollectChildren(aCollectChildren) {}
|
||||
|
||||
@ -823,7 +790,7 @@ class CycleCollectRunnable : public WorkerControlRunnable {
|
||||
|
||||
public:
|
||||
CycleCollectRunnable(WorkerPrivate* aWorkerPrivate, bool aCollectChildren)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mCollectChildren(aCollectChildren) {}
|
||||
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||
@ -849,7 +816,7 @@ class OfflineStatusChangeRunnable : public WorkerRunnable {
|
||||
class MemoryPressureRunnable : public WorkerControlRunnable {
|
||||
public:
|
||||
explicit MemoryPressureRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread) {}
|
||||
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||
aWorkerPrivate->MemoryPressureInternal();
|
||||
@ -880,8 +847,7 @@ PRThread* PRThreadFromThread(nsIThread* aThread) {
|
||||
class CancelingOnParentRunnable final : public WorkerDebuggeeRunnable {
|
||||
public:
|
||||
explicit CancelingOnParentRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount) {
|
||||
}
|
||||
: WorkerDebuggeeRunnable(aWorkerPrivate, ParentThread) {}
|
||||
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||
aWorkerPrivate->Cancel();
|
||||
@ -894,7 +860,7 @@ class CancelingWithTimeoutOnParentRunnable final
|
||||
: public WorkerControlRunnable {
|
||||
public:
|
||||
explicit CancelingWithTimeoutOnParentRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerControlRunnable(aWorkerPrivate, ParentThreadUnchangedBusyCount) {}
|
||||
: WorkerControlRunnable(aWorkerPrivate, ParentThread) {}
|
||||
|
||||
bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
|
||||
aWorkerPrivate->AssertIsOnParentThread();
|
||||
@ -1558,12 +1524,14 @@ void WorkerPrivate::Traverse(nsCycleCollectionTraversalCallback& aCb) {
|
||||
|
||||
// The WorkerPrivate::mParentEventTargetRef has a reference to the exposed
|
||||
// Worker object, which is really held by the worker thread. We traverse this
|
||||
// reference if and only if our busy count is zero and we have not released
|
||||
// the main thread reference. We do not unlink it. This allows the CC to
|
||||
// break cycles involving the Worker and begin shutting it down (which does
|
||||
// happen in unlink) but ensures that the WorkerPrivate won't be deleted
|
||||
// before we're done shutting down the thread.
|
||||
if (!mBusyCount && !mMainThreadObjectsForgotten) {
|
||||
// reference if and only if all main thread event queues are empty, no
|
||||
// shutdown tasks, no StrongWorkerRefs, no child workers, no timeouts, no
|
||||
// blocking background actors, and we have not released the main thread
|
||||
// reference. We do not unlink it. This allows the CC to break cycles
|
||||
// involving the Worker and begin shutting it down (which does happen in
|
||||
// unlink) but ensures that the WorkerPrivate won't be deleted before we're
|
||||
// done shutting down the thread.
|
||||
if (IsEligibleForCC() && !mMainThreadObjectsForgotten) {
|
||||
nsCycleCollectionTraversalCallback& cb = aCb;
|
||||
WorkerPrivate* tmp = this;
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentEventTargetRef);
|
||||
@ -1944,31 +1912,6 @@ bool WorkerPrivate::Close() {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorkerPrivate::ModifyBusyCount(bool aIncrease) {
|
||||
AssertIsOnParentThread();
|
||||
|
||||
MOZ_ASSERT(aIncrease || mBusyCount, "Mismatched busy count mods!");
|
||||
|
||||
if (aIncrease) {
|
||||
mBusyCount++;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (--mBusyCount == 0) {
|
||||
bool shouldCancel;
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
shouldCancel = mParentStatus == Canceling;
|
||||
}
|
||||
|
||||
if (shouldCancel && !Cancel()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WorkerPrivate::ProxyReleaseMainThreadObjects() {
|
||||
AssertIsOnParentThread();
|
||||
MOZ_ASSERT(!mMainThreadObjectsForgotten);
|
||||
@ -2289,6 +2232,7 @@ WorkerPrivate::WorkerThreadAccessible::WorkerThreadAccessible(
|
||||
WorkerPrivate* const aParent)
|
||||
: mNumWorkerRefsPreventingShutdownStart(0),
|
||||
mDebuggerEventLoopLevel(0),
|
||||
mNonblockingCCBackgroundActorCount(0),
|
||||
mErrorHandlerRecursionCount(0),
|
||||
mNextTimeoutId(1),
|
||||
mCurrentTimerNestingLevel(0),
|
||||
@ -2362,7 +2306,6 @@ WorkerPrivate::WorkerPrivate(
|
||||
new WorkerEventTarget(this, WorkerEventTarget::Behavior::Hybrid)),
|
||||
mParentStatus(Pending),
|
||||
mStatus(Pending),
|
||||
mBusyCount(0),
|
||||
mCreationTimeStamp(TimeStamp::Now()),
|
||||
mCreationTimeHighRes((double)PR_Now() / PR_USEC_PER_MSEC),
|
||||
mReportedUseCounters(false),
|
||||
@ -3393,6 +3336,13 @@ void WorkerPrivate::DoRunLoop(JSContext* aCx) {
|
||||
}
|
||||
}
|
||||
|
||||
// Checking the background actors if needed, any runnable execution could
|
||||
// release background actors which blocks GC/CC on
|
||||
// WorkerPrivate::mParentEventTargetRef.
|
||||
if (currentStatus < Canceling) {
|
||||
UpdateCCFlag(CCFlag::CheckBackgroundActors);
|
||||
}
|
||||
|
||||
if (!debuggerRunnablesPending && !normalRunnablesPending) {
|
||||
// Both the debugger event queue and the normal event queue has been
|
||||
// exhausted, cancel the periodic GC timer and schedule the idle GC timer.
|
||||
@ -4120,24 +4070,6 @@ void WorkerPrivate::UnlinkTimeouts() {
|
||||
data->mTimeouts.Clear();
|
||||
}
|
||||
|
||||
bool WorkerPrivate::ModifyBusyCountFromWorker(bool aIncrease) {
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
|
||||
// If we're in shutdown then the busy count is no longer being considered so
|
||||
// just return now.
|
||||
if (mStatus >= Killing) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
RefPtr<ModifyBusyCountRunnable> runnable =
|
||||
new ModifyBusyCountRunnable(this, aIncrease);
|
||||
return runnable->Dispatch();
|
||||
}
|
||||
|
||||
bool WorkerPrivate::AddChildWorker(WorkerPrivate& aChildWorker) {
|
||||
auto data = mWorkerThreadAccessible.Access();
|
||||
|
||||
@ -4157,8 +4089,11 @@ bool WorkerPrivate::AddChildWorker(WorkerPrivate& aChildWorker) {
|
||||
"Already know about this one!");
|
||||
data->mChildWorkers.AppendElement(&aChildWorker);
|
||||
|
||||
return data->mChildWorkers.Length() == 1 ? ModifyBusyCountFromWorker(true)
|
||||
: true;
|
||||
if (data->mChildWorkers.Length() == 1) {
|
||||
UpdateCCFlag(CCFlag::IneligibleForChildWorker);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorkerPrivate::RemoveChildWorker(WorkerPrivate& aChildWorker) {
|
||||
@ -4168,8 +4103,8 @@ void WorkerPrivate::RemoveChildWorker(WorkerPrivate& aChildWorker) {
|
||||
"Didn't know about this one!");
|
||||
data->mChildWorkers.RemoveElement(&aChildWorker);
|
||||
|
||||
if (data->mChildWorkers.IsEmpty() && !ModifyBusyCountFromWorker(false)) {
|
||||
NS_WARNING("Failed to modify busy count!");
|
||||
if (data->mChildWorkers.IsEmpty()) {
|
||||
UpdateCCFlag(CCFlag::EligibleForChildWorker);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4204,11 +4139,10 @@ bool WorkerPrivate::AddWorkerRef(WorkerRef* aWorkerRef,
|
||||
"Already know about this one!");
|
||||
|
||||
if (aWorkerRef->IsPreventingShutdown()) {
|
||||
if (!data->mNumWorkerRefsPreventingShutdownStart &&
|
||||
!ModifyBusyCountFromWorker(true)) {
|
||||
return false;
|
||||
}
|
||||
data->mNumWorkerRefsPreventingShutdownStart += 1;
|
||||
if (data->mNumWorkerRefsPreventingShutdownStart == 1) {
|
||||
UpdateCCFlag(CCFlag::IneligibleForWorkerRef);
|
||||
}
|
||||
}
|
||||
|
||||
data->mWorkerRefs.AppendElement(aWorkerRef);
|
||||
@ -4227,9 +4161,8 @@ void WorkerPrivate::RemoveWorkerRef(WorkerRef* aWorkerRef) {
|
||||
|
||||
if (aWorkerRef->IsPreventingShutdown()) {
|
||||
data->mNumWorkerRefsPreventingShutdownStart -= 1;
|
||||
if (!data->mNumWorkerRefsPreventingShutdownStart &&
|
||||
!ModifyBusyCountFromWorker(false)) {
|
||||
NS_WARNING("Failed to modify busy count!");
|
||||
if (!data->mNumWorkerRefsPreventingShutdownStart) {
|
||||
UpdateCCFlag(CCFlag::EligibleForWorkerRef);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -4304,6 +4237,120 @@ void WorkerPrivate::RunShutdownTasks() {
|
||||
mWorkerHybridEventTarget->ForgetWorkerPrivate(this);
|
||||
}
|
||||
|
||||
void WorkerPrivate::AdjustNonblockingCCBackgroundActorCount(int32_t aCount) {
|
||||
AssertIsOnWorkerThread();
|
||||
auto data = mWorkerThreadAccessible.Access();
|
||||
LOGV(("WorkerPrivate::AdjustNonblockingCCBackgroundActors [%p] (%d/%u)", this,
|
||||
aCount, data->mNonblockingCCBackgroundActorCount));
|
||||
|
||||
#ifdef DEBUG
|
||||
if (aCount < 0) {
|
||||
MOZ_ASSERT(data->mNonblockingCCBackgroundActorCount >=
|
||||
(uint32_t)abs(aCount));
|
||||
}
|
||||
#endif
|
||||
|
||||
data->mNonblockingCCBackgroundActorCount += aCount;
|
||||
}
|
||||
|
||||
void WorkerPrivate::UpdateCCFlag(const CCFlag aFlag) {
|
||||
LOGV(("WorkerPrivate::UpdateCCFlag [%p]", this));
|
||||
AssertIsOnWorkerThread();
|
||||
|
||||
auto data = mWorkerThreadAccessible.Access();
|
||||
|
||||
#ifdef DEBUG
|
||||
switch (aFlag) {
|
||||
case CCFlag::EligibleForWorkerRef: {
|
||||
MOZ_ASSERT(!data->mNumWorkerRefsPreventingShutdownStart);
|
||||
break;
|
||||
}
|
||||
case CCFlag::IneligibleForWorkerRef: {
|
||||
MOZ_ASSERT(data->mNumWorkerRefsPreventingShutdownStart);
|
||||
break;
|
||||
}
|
||||
case CCFlag::EligibleForChildWorker: {
|
||||
MOZ_ASSERT(data->mChildWorkers.IsEmpty());
|
||||
break;
|
||||
}
|
||||
case CCFlag::IneligibleForChildWorker: {
|
||||
MOZ_ASSERT(!data->mChildWorkers.IsEmpty());
|
||||
break;
|
||||
}
|
||||
case CCFlag::EligibleForTimeout: {
|
||||
MOZ_ASSERT(data->mTimeouts.IsEmpty());
|
||||
break;
|
||||
}
|
||||
case CCFlag::IneligibleForTimeout: {
|
||||
MOZ_ASSERT(!data->mTimeouts.IsEmpty());
|
||||
break;
|
||||
}
|
||||
case CCFlag::CheckBackgroundActors: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mStatus > Canceling) {
|
||||
mCCFlagSaysEligible = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
auto HasBackgroundActors = [nonblockingActorCount =
|
||||
data->mNonblockingCCBackgroundActorCount]() {
|
||||
RefPtr<PBackgroundChild> backgroundChild =
|
||||
BackgroundChild::GetForCurrentThread();
|
||||
MOZ_ASSERT(backgroundChild);
|
||||
auto totalCount = backgroundChild->AllManagedActorsCount();
|
||||
LOGV(("WorkerPrivate::UpdateCCFlag HasBackgroundActors: %s(%u/%u)",
|
||||
totalCount > nonblockingActorCount ? "true" : "false", totalCount,
|
||||
nonblockingActorCount));
|
||||
|
||||
return totalCount > nonblockingActorCount;
|
||||
};
|
||||
|
||||
bool eligibleForCC = data->mChildWorkers.IsEmpty() &&
|
||||
data->mTimeouts.IsEmpty() &&
|
||||
!data->mNumWorkerRefsPreventingShutdownStart;
|
||||
|
||||
// Only checking BackgroundActors when no strong WorkerRef, ChildWorker, and
|
||||
// Timeout since the checking is expensive.
|
||||
if (eligibleForCC) {
|
||||
eligibleForCC = !HasBackgroundActors();
|
||||
}
|
||||
|
||||
{
|
||||
MutexAutoLock lock(mMutex);
|
||||
mCCFlagSaysEligible = eligibleForCC;
|
||||
}
|
||||
}
|
||||
|
||||
bool WorkerPrivate::IsEligibleForCC() {
|
||||
LOGV(("WorkerPrivate::IsEligibleForCC [%p]", this));
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mStatus > Canceling) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool HasShutdownTasks = !mShutdownTasks.IsEmpty();
|
||||
|
||||
LOGV(("mMainThreadEventTarget: %s",
|
||||
mMainThreadEventTarget->IsEmpty() ? "empty" : "non-empty"));
|
||||
LOGV(("mMainThreadEventTargetForMessaging: %s",
|
||||
mMainThreadEventTargetForMessaging->IsEmpty() ? "empty" : "non-empty"));
|
||||
LOGV(("mMainThreadDebuggerEventTarget: %s",
|
||||
mMainThreadDebuggeeEventTarget->IsEmpty() ? "empty" : "non-empty"));
|
||||
LOGV(("mCCFlagSaysEligible: %s", mCCFlagSaysEligible ? "true" : "false"));
|
||||
LOGV(("HasShutdownTasks: %s", HasShutdownTasks ? "true" : "false"));
|
||||
|
||||
return mMainThreadEventTarget->IsEmpty() &&
|
||||
mMainThreadEventTargetForMessaging->IsEmpty() &&
|
||||
mMainThreadDebuggeeEventTarget->IsEmpty() && mCCFlagSaysEligible &&
|
||||
!HasShutdownTasks;
|
||||
}
|
||||
|
||||
void WorkerPrivate::CancelAllTimeouts() {
|
||||
auto data = mWorkerThreadAccessible.Access();
|
||||
|
||||
@ -4326,7 +4373,7 @@ void WorkerPrivate::CancelAllTimeouts() {
|
||||
// them. Otherwise, we need to clean them up ourselves.
|
||||
if (!data->mRunningExpiredTimeouts) {
|
||||
data->mTimeouts.Clear();
|
||||
ModifyBusyCountFromWorker(false);
|
||||
UpdateCCFlag(CCFlag::EligibleForTimeout);
|
||||
}
|
||||
|
||||
// Set mTimerRunning false even if mRunningExpiredTimeouts is true, so that
|
||||
@ -4711,8 +4758,8 @@ void WorkerPrivate::PostMessageToParent(
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<MessageEventRunnable> runnable = new MessageEventRunnable(
|
||||
this, WorkerRunnable::ParentThreadUnchangedBusyCount);
|
||||
RefPtr<MessageEventRunnable> runnable =
|
||||
new MessageEventRunnable(this, WorkerRunnable::ParentThread);
|
||||
|
||||
JS::CloneDataPolicy clonePolicy;
|
||||
|
||||
@ -5095,10 +5142,7 @@ int32_t WorkerPrivate::SetTimeout(JSContext* aCx, TimeoutHandler* aHandler,
|
||||
}
|
||||
|
||||
if (!data->mTimerRunning) {
|
||||
if (!ModifyBusyCountFromWorker(true)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return 0;
|
||||
}
|
||||
UpdateCCFlag(CCFlag::IneligibleForTimeout);
|
||||
data->mTimerRunning = true;
|
||||
}
|
||||
|
||||
@ -5279,9 +5323,7 @@ bool WorkerPrivate::RunExpiredTimeouts(JSContext* aCx) {
|
||||
// Either signal the parent that we're no longer using timeouts or reschedule
|
||||
// the timer.
|
||||
if (data->mTimeouts.IsEmpty()) {
|
||||
if (!ModifyBusyCountFromWorker(false)) {
|
||||
retval = false;
|
||||
}
|
||||
UpdateCCFlag(CCFlag::EligibleForTimeout);
|
||||
data->mTimerRunning = false;
|
||||
} else if (retval && !RescheduleTimeoutTimer(aCx)) {
|
||||
retval = false;
|
||||
@ -5327,9 +5369,12 @@ bool WorkerPrivate::RescheduleTimeoutTimer(JSContext* aCx) {
|
||||
void WorkerPrivate::StartCancelingTimer() {
|
||||
AssertIsOnParentThread();
|
||||
|
||||
auto errorCleanup = MakeScopeExit([&] { mCancelingTimer = nullptr; });
|
||||
// return if mCancelingTimer has already existed.
|
||||
if (mCancelingTimer) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mCancelingTimer);
|
||||
auto errorCleanup = MakeScopeExit([&] { mCancelingTimer = nullptr; });
|
||||
|
||||
if (WorkerPrivate* parent = GetParent()) {
|
||||
mCancelingTimer = NS_NewTimer(parent->ControlEventTarget());
|
||||
|
@ -365,8 +365,6 @@ class WorkerPrivate final
|
||||
|
||||
void UnlinkTimeouts();
|
||||
|
||||
bool ModifyBusyCountFromWorker(bool aIncrease);
|
||||
|
||||
bool AddChildWorker(WorkerPrivate& aChildWorker);
|
||||
|
||||
void RemoveChildWorker(WorkerPrivate& aChildWorker);
|
||||
@ -647,12 +645,6 @@ class WorkerPrivate final
|
||||
mParentEventTargetRef = aParentEventTargetRef;
|
||||
}
|
||||
|
||||
bool ModifyBusyCount(bool aIncrease);
|
||||
|
||||
// This method is used by RuntimeService to know what is going wrong the
|
||||
// shutting down.
|
||||
uint32_t BusyCount() { return mBusyCount; }
|
||||
|
||||
// Check whether this worker is a secure context. For use from the parent
|
||||
// thread only; the canonical "is secure context" boolean is stored on the
|
||||
// compartment of the worker global. The only reason we don't
|
||||
@ -1141,6 +1133,35 @@ class WorkerPrivate final
|
||||
return data->mCancelBeforeWorkerScopeConstructed;
|
||||
}
|
||||
|
||||
enum class CCFlag : uint8_t {
|
||||
EligibleForWorkerRef,
|
||||
IneligibleForWorkerRef,
|
||||
EligibleForChildWorker,
|
||||
IneligibleForChildWorker,
|
||||
EligibleForTimeout,
|
||||
IneligibleForTimeout,
|
||||
CheckBackgroundActors,
|
||||
};
|
||||
|
||||
// When create/release a StrongWorkerRef, child worker, and timeout, this
|
||||
// method is used to setup if mParentEventTargetRef can get into
|
||||
// cycle-collection.
|
||||
// When this method is called, it will also checks if any background actor
|
||||
// should block the mParentEventTargetRef cycle-collection when there is no
|
||||
// StrongWorkerRef/ChildWorker/Timeout.
|
||||
// Worker thread only.
|
||||
void UpdateCCFlag(const CCFlag);
|
||||
|
||||
// This is used in WorkerPrivate::Traverse() to checking if
|
||||
// mParentEventTargetRef should get into cycle-collection.
|
||||
// Parent thread only method.
|
||||
bool IsEligibleForCC();
|
||||
|
||||
// A method which adjusts the count of background actors which should not
|
||||
// block WorkerPrivate::mParentEventTargetRef cycle-collection.
|
||||
// Worker thread only.
|
||||
void AdjustNonblockingCCBackgroundActorCount(int32_t aCount);
|
||||
|
||||
private:
|
||||
WorkerPrivate(
|
||||
WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
@ -1308,7 +1329,7 @@ class WorkerPrivate final
|
||||
|
||||
// The worker is owned by its thread, which is represented here. This is set
|
||||
// in Constructor() and emptied by WorkerFinishedRunnable, and conditionally
|
||||
// traversed by the cycle collector if the busy count is zero.
|
||||
// traversed by the cycle collector if no other things preventing shutdown.
|
||||
//
|
||||
// There are 4 ways a worker can be terminated:
|
||||
// 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to
|
||||
@ -1400,10 +1421,6 @@ class WorkerPrivate final
|
||||
WorkerStatus mParentStatus MOZ_GUARDED_BY(mMutex);
|
||||
WorkerStatus mStatus MOZ_GUARDED_BY(mMutex);
|
||||
|
||||
// This is touched on parent thread only, but it can be read on a different
|
||||
// thread before crashing because hanging.
|
||||
Atomic<uint64_t> mBusyCount;
|
||||
|
||||
TimeStamp mCreationTimeStamp;
|
||||
DOMHighResTimeStamp mCreationTimeHighRes;
|
||||
|
||||
@ -1464,6 +1481,11 @@ class WorkerPrivate final
|
||||
uint32_t mNumWorkerRefsPreventingShutdownStart;
|
||||
uint32_t mDebuggerEventLoopLevel;
|
||||
|
||||
// This is the count of background actors that binding with IPCWorkerRefs.
|
||||
// This count would be used in WorkerPrivate::UpdateCCFlag for checking if
|
||||
// CC should be blocked by background actors.
|
||||
uint32_t mNonblockingCCBackgroundActorCount;
|
||||
|
||||
uint32_t mErrorHandlerRecursionCount;
|
||||
int32_t mNextTimeoutId;
|
||||
|
||||
@ -1584,6 +1606,8 @@ class WorkerPrivate final
|
||||
nsTArray<nsCOMPtr<nsITargetShutdownTask>> mShutdownTasks
|
||||
MOZ_GUARDED_BY(mMutex);
|
||||
bool mShutdownTasksRun MOZ_GUARDED_BY(mMutex) = false;
|
||||
|
||||
bool mCCFlagSaysEligible MOZ_GUARDED_BY(mMutex){true};
|
||||
};
|
||||
|
||||
class AutoSyncLoopHolder {
|
||||
|
@ -20,7 +20,7 @@ class ReleaseRefControlRunnable final : public WorkerControlRunnable {
|
||||
public:
|
||||
ReleaseRefControlRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
already_AddRefed<StrongWorkerRef> aRef)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread),
|
||||
mRef(std::move(aRef)) {
|
||||
MOZ_ASSERT(mRef);
|
||||
}
|
||||
@ -229,20 +229,34 @@ already_AddRefed<IPCWorkerRef> IPCWorkerRef::Create(
|
||||
if (!ref->HoldWorker(Canceling)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ref->mWorkerPrivate->AdjustNonblockingCCBackgroundActorCount(1);
|
||||
ref->mCallback = std::move(aCallback);
|
||||
|
||||
return ref.forget();
|
||||
}
|
||||
|
||||
IPCWorkerRef::IPCWorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName)
|
||||
: WorkerRef(aWorkerPrivate, aName, false) {}
|
||||
: WorkerRef(aWorkerPrivate, aName, false), mActorCount(1) {}
|
||||
|
||||
IPCWorkerRef::~IPCWorkerRef() = default;
|
||||
IPCWorkerRef::~IPCWorkerRef() {
|
||||
NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
|
||||
// explicit type convertion to avoid undefined behavior of uint32_t overflow.
|
||||
mWorkerPrivate->AdjustNonblockingCCBackgroundActorCount(
|
||||
(int32_t)-mActorCount);
|
||||
ReleaseWorker();
|
||||
};
|
||||
|
||||
WorkerPrivate* IPCWorkerRef::Private() const {
|
||||
NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
|
||||
return mWorkerPrivate;
|
||||
}
|
||||
|
||||
void IPCWorkerRef::SetActorCount(uint32_t aCount) {
|
||||
NS_ASSERT_OWNINGTHREAD(IPCWorkerRef);
|
||||
// explicit type convertion to avoid undefined behavior of uint32_t overflow.
|
||||
mWorkerPrivate->AdjustNonblockingCCBackgroundActorCount((int32_t)aCount -
|
||||
(int32_t)mActorCount);
|
||||
mActorCount = aCount;
|
||||
}
|
||||
|
||||
} // namespace mozilla::dom
|
||||
|
@ -209,9 +209,14 @@ class IPCWorkerRef final : public WorkerRef {
|
||||
|
||||
WorkerPrivate* Private() const;
|
||||
|
||||
void SetActorCount(uint32_t aCount);
|
||||
|
||||
private:
|
||||
IPCWorkerRef(WorkerPrivate* aWorkerPrivate, const char* aName);
|
||||
~IPCWorkerRef();
|
||||
|
||||
// The count of background actors which binding with this IPCWorkerRef.
|
||||
uint32_t mActorCount;
|
||||
};
|
||||
|
||||
// Template class to keep an Actor pointer, as a raw pointer, in a ref-counted
|
||||
|
@ -53,10 +53,9 @@ const nsIID kWorkerRunnableIID = {
|
||||
} // namespace
|
||||
|
||||
#ifdef DEBUG
|
||||
WorkerRunnable::WorkerRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior)
|
||||
WorkerRunnable::WorkerRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget)
|
||||
: mWorkerPrivate(aWorkerPrivate),
|
||||
mBehavior(aBehavior),
|
||||
mTarget(aTarget),
|
||||
mCallingCancelWithinRun(false) {
|
||||
LOG(("WorkerRunnable::WorkerRunnable [%p]", this));
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
@ -77,13 +76,12 @@ bool WorkerRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
|
||||
switch (mBehavior) {
|
||||
case ParentThreadUnchangedBusyCount:
|
||||
switch (mTarget) {
|
||||
case ParentThread:
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
break;
|
||||
|
||||
case WorkerThreadModifyBusyCount:
|
||||
case WorkerThreadUnchangedBusyCount:
|
||||
case WorkerThread:
|
||||
aWorkerPrivate->AssertIsOnParentThread();
|
||||
break;
|
||||
|
||||
@ -91,11 +89,6 @@ bool WorkerRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mBehavior == WorkerThreadModifyBusyCount) {
|
||||
return aWorkerPrivate->ModifyBusyCount(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -112,8 +105,7 @@ bool WorkerRunnable::DispatchInternal() {
|
||||
LOG(("WorkerRunnable::DispatchInternal [%p]", this));
|
||||
RefPtr<WorkerRunnable> runnable(this);
|
||||
|
||||
if (mBehavior == WorkerThreadModifyBusyCount ||
|
||||
mBehavior == WorkerThreadUnchangedBusyCount) {
|
||||
if (mTarget == WorkerThread) {
|
||||
if (IsDebuggerRunnable()) {
|
||||
return NS_SUCCEEDED(
|
||||
mWorkerPrivate->DispatchDebuggerRunnable(runnable.forget()));
|
||||
@ -122,7 +114,7 @@ bool WorkerRunnable::DispatchInternal() {
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
|
||||
MOZ_ASSERT(mTarget == ParentThread);
|
||||
|
||||
if (WorkerPrivate* parent = mWorkerPrivate->GetParent()) {
|
||||
return NS_SUCCEEDED(parent->Dispatch(runnable.forget()));
|
||||
@ -143,16 +135,12 @@ void WorkerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
|
||||
#ifdef DEBUG
|
||||
switch (mBehavior) {
|
||||
case ParentThreadUnchangedBusyCount:
|
||||
switch (mTarget) {
|
||||
case ParentThread:
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
break;
|
||||
|
||||
case WorkerThreadModifyBusyCount:
|
||||
aWorkerPrivate->AssertIsOnParentThread();
|
||||
break;
|
||||
|
||||
case WorkerThreadUnchangedBusyCount:
|
||||
case WorkerThread:
|
||||
aWorkerPrivate->AssertIsOnParentThread();
|
||||
break;
|
||||
|
||||
@ -160,12 +148,6 @@ void WorkerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!aDispatchResult) {
|
||||
if (mBehavior == WorkerThreadModifyBusyCount) {
|
||||
aWorkerPrivate->ModifyBusyCount(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool WorkerRunnable::PreRun(WorkerPrivate* aWorkerPrivate) { return true; }
|
||||
@ -176,16 +158,12 @@ void WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
|
||||
#ifdef DEBUG
|
||||
switch (mBehavior) {
|
||||
case ParentThreadUnchangedBusyCount:
|
||||
switch (mTarget) {
|
||||
case ParentThread:
|
||||
aWorkerPrivate->AssertIsOnParentThread();
|
||||
break;
|
||||
|
||||
case WorkerThreadModifyBusyCount:
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
break;
|
||||
|
||||
case WorkerThreadUnchangedBusyCount:
|
||||
case WorkerThread:
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
break;
|
||||
|
||||
@ -193,10 +171,6 @@ void WorkerRunnable::PostRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
MOZ_ASSERT_UNREACHABLE("Unknown behavior!");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mBehavior == WorkerThreadModifyBusyCount) {
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(false);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
@ -230,14 +204,13 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMETHODIMP
|
||||
WorkerRunnable::Run() {
|
||||
LOG(("WorkerRunnable::Run [%p]", this));
|
||||
bool targetIsWorkerThread = mBehavior == WorkerThreadModifyBusyCount ||
|
||||
mBehavior == WorkerThreadUnchangedBusyCount;
|
||||
bool targetIsWorkerThread = mTarget == WorkerThread;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (targetIsWorkerThread) {
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
} else {
|
||||
MOZ_ASSERT(mBehavior == ParentThreadUnchangedBusyCount);
|
||||
MOZ_ASSERT(mTarget == ParentThread);
|
||||
mWorkerPrivate->AssertIsOnParentThread();
|
||||
}
|
||||
#endif
|
||||
@ -247,9 +220,6 @@ WorkerRunnable::Run() {
|
||||
mCallingCancelWithinRun = true;
|
||||
Cancel();
|
||||
mCallingCancelWithinRun = false;
|
||||
if (mBehavior == WorkerThreadModifyBusyCount) {
|
||||
mWorkerPrivate->ModifyBusyCountFromWorker(false);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -409,7 +379,7 @@ void WorkerDebuggerRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||
|
||||
WorkerSyncRunnable::WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
nsIEventTarget* aSyncLoopTarget)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread),
|
||||
mSyncLoopTarget(aSyncLoopTarget) {
|
||||
#ifdef DEBUG
|
||||
if (mSyncLoopTarget) {
|
||||
@ -420,7 +390,7 @@ WorkerSyncRunnable::WorkerSyncRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
|
||||
WorkerSyncRunnable::WorkerSyncRunnable(
|
||||
WorkerPrivate* aWorkerPrivate, nsCOMPtr<nsIEventTarget>&& aSyncLoopTarget)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount),
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread),
|
||||
mSyncLoopTarget(std::move(aSyncLoopTarget)) {
|
||||
#ifdef DEBUG
|
||||
if (mSyncLoopTarget) {
|
||||
@ -491,12 +461,9 @@ void MainThreadStopSyncLoopRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||
|
||||
#ifdef DEBUG
|
||||
WorkerControlRunnable::WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior)
|
||||
: WorkerRunnable(aWorkerPrivate, aBehavior) {
|
||||
Target aTarget)
|
||||
: WorkerRunnable(aWorkerPrivate, aTarget) {
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
MOZ_ASSERT(aBehavior == ParentThreadUnchangedBusyCount ||
|
||||
aBehavior == WorkerThreadUnchangedBusyCount,
|
||||
"WorkerControlRunnables should not modify the busy count");
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -512,7 +479,7 @@ nsresult WorkerControlRunnable::Cancel() {
|
||||
bool WorkerControlRunnable::DispatchInternal() {
|
||||
RefPtr<WorkerControlRunnable> runnable(this);
|
||||
|
||||
if (mBehavior == WorkerThreadUnchangedBusyCount) {
|
||||
if (mTarget == WorkerThread) {
|
||||
return NS_SUCCEEDED(
|
||||
mWorkerPrivate->DispatchControlRunnable(runnable.forget()));
|
||||
}
|
||||
@ -591,26 +558,13 @@ WorkerMainThreadRunnable::Run() {
|
||||
}
|
||||
|
||||
bool WorkerSameThreadRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
|
||||
// We don't call WorkerRunnable::PreDispatch, because we're using
|
||||
// WorkerThreadModifyBusyCount for mBehavior, and WorkerRunnable will assert
|
||||
// that PreDispatch is on the parent thread in that case.
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorkerSameThreadRunnable::PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult) {
|
||||
// We don't call WorkerRunnable::PostDispatch, because we're using
|
||||
// WorkerThreadModifyBusyCount for mBehavior, and WorkerRunnable will assert
|
||||
// that PostDispatch is on the parent thread in that case.
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
if (aDispatchResult) {
|
||||
DebugOnly<bool> willIncrement =
|
||||
aWorkerPrivate->ModifyBusyCountFromWorker(true);
|
||||
// Should never fail since if this thread is still running, so should the
|
||||
// parent and it should be able to process a control runnable.
|
||||
MOZ_ASSERT(willIncrement);
|
||||
}
|
||||
}
|
||||
|
||||
WorkerProxyToMainThreadRunnable::WorkerProxyToMainThreadRunnable()
|
||||
@ -697,7 +651,7 @@ void WorkerProxyToMainThreadRunnable::PostDispatchOnMainThread() {
|
||||
void WorkerProxyToMainThreadRunnable::ReleaseWorker() { mWorkerRef = nullptr; }
|
||||
|
||||
bool WorkerDebuggeeRunnable::PreDispatch(WorkerPrivate* aWorkerPrivate) {
|
||||
if (mBehavior == ParentThreadUnchangedBusyCount) {
|
||||
if (mTarget == ParentThread) {
|
||||
RefPtr<StrongWorkerRef> strongRef = StrongWorkerRef::Create(
|
||||
aWorkerPrivate, "WorkerDebuggeeRunnable::mSender");
|
||||
if (!strongRef) {
|
||||
|
@ -34,24 +34,15 @@ namespace dom {
|
||||
class WorkerPrivate;
|
||||
|
||||
// Use this runnable to communicate from the worker to its parent or vice-versa.
|
||||
// The busy count must be taken into consideration and declared at construction
|
||||
// time.
|
||||
class WorkerRunnable : public nsIRunnable {
|
||||
public:
|
||||
enum TargetAndBusyBehavior {
|
||||
enum Target {
|
||||
// Target the main thread for top-level workers, otherwise target the
|
||||
// WorkerThread of the worker's parent. No change to the busy count.
|
||||
ParentThreadUnchangedBusyCount,
|
||||
// WorkerThread of the worker's parent.
|
||||
ParentThread,
|
||||
|
||||
// Target the thread where the worker event loop runs. The busy count will
|
||||
// be incremented before dispatching and decremented (asynchronously) after
|
||||
// running.
|
||||
WorkerThreadModifyBusyCount,
|
||||
|
||||
// Target the thread where the worker event loop runs. The busy count will
|
||||
// not be modified in any way. Besides worker-internal runnables this is
|
||||
// almost always the wrong choice.
|
||||
WorkerThreadUnchangedBusyCount
|
||||
// Target the thread where the worker event loop runs.
|
||||
WorkerThread,
|
||||
};
|
||||
|
||||
protected:
|
||||
@ -59,7 +50,7 @@ class WorkerRunnable : public nsIRunnable {
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
// See above.
|
||||
TargetAndBusyBehavior mBehavior;
|
||||
Target mTarget;
|
||||
|
||||
private:
|
||||
// Whether or not Cancel() is currently being called from inside the Run()
|
||||
@ -90,13 +81,12 @@ class WorkerRunnable : public nsIRunnable {
|
||||
static WorkerRunnable* FromRunnable(nsIRunnable* aRunnable);
|
||||
|
||||
protected:
|
||||
WorkerRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior = WorkerThreadModifyBusyCount)
|
||||
WorkerRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget = WorkerThread)
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
: mWorkerPrivate(aWorkerPrivate),
|
||||
mBehavior(aBehavior),
|
||||
mTarget(aTarget),
|
||||
mCallingCancelWithinRun(false) {
|
||||
}
|
||||
#endif
|
||||
@ -111,13 +101,11 @@ class WorkerRunnable : public nsIRunnable {
|
||||
nsIGlobalObject* DefaultGlobalObject() const;
|
||||
|
||||
// By default asserts that Dispatch() is being called on the right thread
|
||||
// (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
|
||||
// Also increments the busy count of |mWorkerPrivate| if targeting the
|
||||
// WorkerThread.
|
||||
// (ParentThread if |mTarget| is WorkerThread).
|
||||
virtual bool PreDispatch(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
// By default asserts that Dispatch() is being called on the right thread
|
||||
// (ParentThread if |mTarget| is WorkerThread, or WorkerThread otherwise).
|
||||
// (ParentThread if |mTarget| is WorkerThread).
|
||||
virtual void PostDispatch(WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult);
|
||||
|
||||
@ -133,11 +121,11 @@ class WorkerRunnable : public nsIRunnable {
|
||||
// Must be implemented by subclasses. Called on the target thread. The return
|
||||
// value will be passed to PostRun(). The JSContext passed in here comes from
|
||||
// an AutoJSAPI (or AutoEntryScript) that we set up on the stack. If
|
||||
// mBehavior is ParentThreadUnchangedBusyCount, it is in the compartment of
|
||||
// mTarget is ParentThread, it is in the compartment of
|
||||
// mWorkerPrivate's reflector (i.e. the worker object in the parent thread),
|
||||
// unless that reflector is null, in which case it's in the compartment of the
|
||||
// parent global (which is the compartment reflector would have been in), or
|
||||
// in the null compartment if there is no parent global. For other mBehavior
|
||||
// in the null compartment if there is no parent global. For other mTarget
|
||||
// values, we're running on the worker thread and aCx is in whatever
|
||||
// compartment GetCurrentWorkerThreadJSContext() was in when
|
||||
// nsIRunnable::Run() got called. This is actually important for cases when a
|
||||
@ -154,8 +142,7 @@ class WorkerRunnable : public nsIRunnable {
|
||||
virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) = 0;
|
||||
|
||||
// By default asserts that Run() (and WorkerRun()) were called on the correct
|
||||
// thread. Also sends an asynchronous message to the ParentThread if the
|
||||
// busy count was previously modified in PreDispatch().
|
||||
// thread.
|
||||
//
|
||||
// The aCx passed here is the same one as was passed to WorkerRun and is
|
||||
// still in the same compartment. PostRun implementations must NOT leave an
|
||||
@ -175,7 +162,7 @@ class WorkerRunnable : public nsIRunnable {
|
||||
class WorkerDebuggerRunnable : public WorkerRunnable {
|
||||
protected:
|
||||
explicit WorkerDebuggerRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread) {}
|
||||
|
||||
virtual ~WorkerDebuggerRunnable() = default;
|
||||
|
||||
@ -244,18 +231,16 @@ class MainThreadWorkerSyncRunnable : public WorkerSyncRunnable {
|
||||
// This runnable is processed as soon as it is received by the worker,
|
||||
// potentially running before previously queued runnables and perhaps even with
|
||||
// other JS code executing on the stack. These runnables must not alter the
|
||||
// state of the JS runtime and should only twiddle state values. The busy count
|
||||
// is never modified.
|
||||
// state of the JS runtime and should only twiddle state values.
|
||||
class WorkerControlRunnable : public WorkerRunnable {
|
||||
friend class WorkerPrivate;
|
||||
|
||||
protected:
|
||||
WorkerControlRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior)
|
||||
WorkerControlRunnable(WorkerPrivate* aWorkerPrivate, Target aTarget)
|
||||
#ifdef DEBUG
|
||||
;
|
||||
#else
|
||||
: WorkerRunnable(aWorkerPrivate, aBehavior) {
|
||||
: WorkerRunnable(aWorkerPrivate, aTarget) {
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -278,7 +263,7 @@ class WorkerControlRunnable : public WorkerRunnable {
|
||||
class MainThreadWorkerRunnable : public WorkerRunnable {
|
||||
protected:
|
||||
explicit MainThreadWorkerRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread) {
|
||||
AssertIsOnMainThread();
|
||||
}
|
||||
|
||||
@ -300,7 +285,7 @@ class MainThreadWorkerRunnable : public WorkerRunnable {
|
||||
class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
|
||||
protected:
|
||||
explicit MainThreadWorkerControlRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThreadUnchangedBusyCount) {}
|
||||
: WorkerControlRunnable(aWorkerPrivate, WorkerThread) {}
|
||||
|
||||
virtual ~MainThreadWorkerControlRunnable() = default;
|
||||
|
||||
@ -316,15 +301,14 @@ class MainThreadWorkerControlRunnable : public WorkerControlRunnable {
|
||||
};
|
||||
|
||||
// A WorkerRunnable that should be dispatched from the worker to itself for
|
||||
// async tasks. This will increment the busy count PostDispatch() (only if
|
||||
// dispatch was successful) and decrement it in PostRun().
|
||||
// async tasks.
|
||||
//
|
||||
// Async tasks will almost always want to use this since
|
||||
// a WorkerSameThreadRunnable keeps the Worker from being GCed.
|
||||
class WorkerSameThreadRunnable : public WorkerRunnable {
|
||||
protected:
|
||||
explicit WorkerSameThreadRunnable(WorkerPrivate* aWorkerPrivate)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount) {}
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThread) {}
|
||||
|
||||
virtual ~WorkerSameThreadRunnable() = default;
|
||||
|
||||
@ -404,9 +388,7 @@ class WorkerProxyToMainThreadRunnable : public Runnable {
|
||||
};
|
||||
|
||||
// This runnable is used to stop a sync loop and it's meant to be used on the
|
||||
// main-thread only. As sync loops keep the busy count incremented as long as
|
||||
// they run this runnable does not modify the busy count
|
||||
// in any way.
|
||||
// main-thread only.
|
||||
class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
|
||||
nsresult mResult;
|
||||
|
||||
@ -460,10 +442,9 @@ class MainThreadStopSyncLoopRunnable : public WorkerSyncRunnable {
|
||||
// a top-level worker also pauses mMainThreadDebuggeeEventTarget.
|
||||
class WorkerDebuggeeRunnable : public WorkerRunnable {
|
||||
protected:
|
||||
WorkerDebuggeeRunnable(
|
||||
WorkerPrivate* aWorkerPrivate,
|
||||
TargetAndBusyBehavior aBehavior = ParentThreadUnchangedBusyCount)
|
||||
: WorkerRunnable(aWorkerPrivate, aBehavior) {}
|
||||
WorkerDebuggeeRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
Target aTarget = ParentThread)
|
||||
: WorkerRunnable(aWorkerPrivate, aTarget) {}
|
||||
|
||||
bool PreDispatch(WorkerPrivate* aWorkerPrivate) override;
|
||||
|
||||
@ -480,7 +461,7 @@ class WorkerDebuggeeRunnable : public WorkerRunnable {
|
||||
// WorkerPrivate::GetWindow may only be used on the main thread.
|
||||
//
|
||||
// Runnables sent downwards, from content to a worker or from a worker to a
|
||||
// child, keep the sender alive because they are WorkerThreadModifyBusyCount
|
||||
// child, keep the sender alive because they are WorkerThread
|
||||
// runnables, and so leave this null.
|
||||
RefPtr<ThreadSafeWorkerRef> mSender;
|
||||
};
|
||||
|
@ -290,6 +290,8 @@ class IProtocol : public HasResultCodes {
|
||||
virtual void AllManagedActors(
|
||||
nsTArray<RefPtr<ActorLifecycleProxy>>& aActors) const = 0;
|
||||
|
||||
virtual uint32_t AllManagedActorsCount() const = 0;
|
||||
|
||||
// Internal method called when the actor becomes connected.
|
||||
void ActorConnected();
|
||||
|
||||
|
@ -3973,6 +3973,38 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor):
|
||||
|
||||
self.cls.addstmts([managedmeth, Whitespace.NL])
|
||||
|
||||
# AllManagedActorsCount() const
|
||||
managedmeth = MethodDefn(
|
||||
MethodDecl(
|
||||
"AllManagedActorsCount",
|
||||
ret=Type.UINT32,
|
||||
methodspec=MethodSpec.OVERRIDE,
|
||||
const=True,
|
||||
)
|
||||
)
|
||||
|
||||
# Count the number of managed actors.
|
||||
managedmeth.addcode(
|
||||
"""
|
||||
uint32_t total = 0;
|
||||
"""
|
||||
)
|
||||
for managed in ptype.manages:
|
||||
managedmeth.addcode(
|
||||
"""
|
||||
total += ${container}.Count();
|
||||
""",
|
||||
container=p.managedVar(managed, self.side),
|
||||
)
|
||||
managedmeth.addcode(
|
||||
"""
|
||||
return total;
|
||||
|
||||
"""
|
||||
)
|
||||
|
||||
self.cls.addstmts([managedmeth, Whitespace.NL])
|
||||
|
||||
# OpenPEndpoint(...)/BindPEndpoint(...)
|
||||
for managed in ptype.manages:
|
||||
self.genManagedEndpoint(managed)
|
||||
|
@ -134,7 +134,7 @@ class ExtensionListenerCallWorkerRunnable : public dom::WorkerRunnable {
|
||||
ListenerCallOptions* aCallOptions,
|
||||
RefPtr<dom::Promise> aPromiseRetval = nullptr)
|
||||
: WorkerRunnable(aExtensionEventListener->GetWorkerPrivate(),
|
||||
WorkerThreadUnchangedBusyCount),
|
||||
WorkerThread),
|
||||
mListener(aExtensionEventListener),
|
||||
mArgsHolder(std::move(aArgsHolder)),
|
||||
mPromiseResult(std::move(aPromiseRetval)),
|
||||
|
Loading…
Reference in New Issue
Block a user