Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions NativeScript/inspector/JsV8InspectorClient.mm
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,18 @@
dispatch_semaphore_signal(messageArrived_);
});

// Debugger.pause needs to interrupt V8 even if the main thread is busy
// executing JS. RequestInterrupt fires at the next safe bytecode boundary.
auto parsed = json::parse(message, nullptr, false);
if (!parsed.is_discarded() && parsed.contains("method") && parsed["method"] == "Debugger.pause") {
isolate_->RequestInterrupt(
[](Isolate* isolate, void* data) {
auto client = static_cast<JsV8InspectorClient*>(data);
client->session_->schedulePauseOnNextStatement({}, {});
},
this);
}
Comment on lines +131 to +141
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Skip the interrupt path when the inspector is already paused.

runMessageLoopOnPause() already pumps frontend messages with runningNestedLoops_ = true. In that state no JS is executing, so this RequestInterrupt stays pending until after resume and can cause an unexpected immediate re-pause on the next statement. Gate the new branch on !runningNestedLoops_ and let the paused message loop handle Debugger.pause normally.

Suggested guard
   auto parsed = json::parse(message, nullptr, false);
-  if (!parsed.is_discarded() && parsed.contains("method") && parsed["method"] == "Debugger.pause") {
+  bool shouldInterrupt = false;
+  dispatch_sync(this->messageLoopQueue_, ^{
+    shouldInterrupt = !runningNestedLoops_;
+  });
+  if (shouldInterrupt && !parsed.is_discarded() && parsed.contains("method") &&
+      parsed["method"] == "Debugger.pause") {
     isolate_->RequestInterrupt(
         [](Isolate* isolate, void* data) {
           auto client = static_cast<JsV8InspectorClient*>(data);
           client->session_->schedulePauseOnNextStatement({}, {});
         },
         this);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@NativeScript/inspector/JsV8InspectorClient.mm` around lines 131 - 141, The
RequestInterrupt path for "Debugger.pause" should be skipped when the inspector
is already in a paused nested loop; wrap the existing parsed-check and
isolate_->RequestInterrupt call in a guard that only runs when
runningNestedLoops_ is false (i.e., if (!runningNestedLoops_) { ... }), so that
runMessageLoopOnPause() (which sets runningNestedLoops_ = true) continues to
handle pause messages via session_->schedulePauseOnNextStatement rather than
queuing an interrupt that re-pauses immediately; update the branch in
JsV8InspectorClient around the RequestInterrupt lambda to check
runningNestedLoops_ before calling isolate_->RequestInterrupt.


tns::ExecuteOnMainThread([this, message]() {
dispatch_sync(this->messageLoopQueue_, ^{
// prevent execution if we're already pumping messages
Expand Down
Loading