Skip to content

A stop-all breakpoint on another thread stalls an in-flight logpoint/condition evaluation #43

Closed

Description

@novoj

Problem

Event processing evaluates logpoint expressions, breakpoint conditions and fast-logpoint arming hits by invoking methods in the target. It uses INVOKE_SINGLE_THREADED on the hit's thread T. Since #41 this runs on the jdi-event-dispatcher thread, while the listener thread keeps draining the queue.

If another thread U hits a breakpoint with suspend policy all (the default of jdwp_set_breakpoint) during that invocation, the VM-wide suspension also stops T in the middle of the invocation. U is not inside an MCP evaluation, so its event set is queued behind the stalled evaluation:

  • the evaluation cannot finish until T is resumed;
  • U's stop is neither recorded (BREAKPOINT, jdwp_resume_until_event latch) nor resumed, because its set waits behind the evaluation.

The only way out is jdwp_resume. After it, U's set is processed late and records a stop for a thread that is already running.

This is not a regression from #41. Before it, the listener thread itself was blocked in the invocation, with the same stall. The window is the duration of one evaluation: about 1 ms with a warm cache, up to ~1 s for the first compile, ~300 ms for arming.

Proposed direction

Do not queue a set that suspends the evaluating thread behind that evaluation:

  • When an unguarded SUSPEND_ALL set arrives while the dispatcher is inside a target invocation, process it on a side thread at once. A plain stop is recorded and stays suspended (the evaluation then waits for the user's resume, which is correct for a stop-all breakpoint). A conditional one is evaluated on its own thread, which is suspended by its own event.
  • Keep event-set resume ownership with whoever processes the set. Account for the handler concurrency between the side thread and the stalled dispatcher.
  • Add a live two-thread regression test with a real stop-all breakpoint hit during a logpoint evaluation.

Out of scope

The same stall for an MCP-tool evaluation (jdwp_evaluate_expression) blocked by another thread's stop-all breakpoint. That needs the tool call to give up on, or interrupt, the invocation.

Context: PR #41, review finding 1 of the deadlock fix (commit 1c32d18).

Activity

  1. novoj commented on Oct 29, 2026

    @novoj
    ContributorAuthor

    Folded into #45. The stall can only be fixed safely together with suspension ownership, because the current escape is a blind jdwp_resume, which the ownership model removes. #45 covers the fix: a temporary exemption of the evaluating thread from another thread's stop-all set, suspended again at evaluation exit if that set is still active. Closing in favour of #45.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions