summaryrefslogtreecommitdiffstats
path: root/devtools/shared/commands/resource/legacy-listeners/thread-states.js
diff options
context:
space:
mode:
Diffstat (limited to 'devtools/shared/commands/resource/legacy-listeners/thread-states.js')
-rw-r--r--devtools/shared/commands/resource/legacy-listeners/thread-states.js81
1 files changed, 81 insertions, 0 deletions
diff --git a/devtools/shared/commands/resource/legacy-listeners/thread-states.js b/devtools/shared/commands/resource/legacy-listeners/thread-states.js
new file mode 100644
index 0000000000..42c922072a
--- /dev/null
+++ b/devtools/shared/commands/resource/legacy-listeners/thread-states.js
@@ -0,0 +1,81 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const ResourceCommand = require("resource://devtools/shared/commands/resource/resource-command.js");
+
+module.exports = async function ({ targetCommand, targetFront, onAvailable }) {
+ const isBrowserToolbox =
+ targetCommand.descriptorFront.isBrowserProcessDescriptor;
+ const isNonTopLevelFrameTarget =
+ !targetFront.isTopLevel &&
+ targetFront.targetType === targetCommand.TYPES.FRAME;
+
+ if (isBrowserToolbox && isNonTopLevelFrameTarget) {
+ // In the BrowserToolbox, non-top-level frame targets are already
+ // debugged via content-process targets.
+ return;
+ }
+
+ // Wait for the thread actor to be attached, otherwise getFront(thread) will throw for worker targets
+ // This is because worker target are still kind of descriptors and are only resolved into real target
+ // after being attached. And the thread actor ID is only retrieved and available after being attached.
+ await targetFront.onThreadAttached;
+
+ if (targetFront.isDestroyed()) {
+ return;
+ }
+ const threadFront = await targetFront.getFront("thread");
+
+ let isInterrupted = false;
+ const onPausedPacket = packet => {
+ // If paused by an explicit interrupt, which are generated by the
+ // slow script dialog and internal events such as setting
+ // breakpoints, ignore the event.
+ const { why } = packet;
+ if (why.type === "interrupted" && !why.onNext) {
+ isInterrupted = true;
+ return;
+ }
+
+ // Ignore attached events because they are not useful to the user.
+ if (why.type == "alreadyPaused" || why.type == "attached") {
+ return;
+ }
+
+ onAvailable([
+ {
+ resourceType: ResourceCommand.TYPES.THREAD_STATE,
+ state: "paused",
+ why,
+ frame: packet.frame,
+ },
+ ]);
+ };
+ threadFront.on("paused", onPausedPacket);
+
+ threadFront.on("resumed", packet => {
+ // NOTE: the client suppresses resumed events while interrupted
+ // to prevent unintentional behavior.
+ // see [client docs](devtools/client/debugger/src/client/README.md#interrupted) for more information.
+ if (isInterrupted) {
+ isInterrupted = false;
+ return;
+ }
+
+ onAvailable([
+ {
+ resourceType: ResourceCommand.TYPES.THREAD_STATE,
+ state: "resumed",
+ },
+ ]);
+ });
+
+ // Notify about already paused thread
+ const pausedPacket = threadFront.getLastPausePacket();
+ if (pausedPacket) {
+ onPausedPacket(pausedPacket);
+ }
+};