[debugger] Implement merging paused suspend-thread contexts into suspend-all context on suspend-all breakpoint

Also adjust Java multithreading tests to the updated behavior

IDEA-381878 IDEA-365578

GitOrigin-RevId: 67688175a42ebc9f7919c8492d1b06e05ffdef40
This commit is contained in:
Alexey.Merkulov
2025-11-08 00:55:18 +00:00
committed by intellij-monorepo-bot
parent 9775e9b839
commit bf157ba353
5 changed files with 34 additions and 2 deletions
@@ -203,7 +203,10 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
public void paused(@NotNull SuspendContext suspendContext) {
boolean isSuspendAll = suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL;
if (isSuspendAll && DebuggerUtils.isNewThreadSuspendStateTracking()) {
mergeSuspendThreadContextToSuspendAllContext();
resumeThreadsUnderEvaluationAndExplicitlyResumedAfterPause((SuspendContextImpl)suspendContext);
// It deletes suspend-thread stepping in another thread and suspend-all breakpoint is reached
getRequestsManager().deleteAllStepRequests();
}
myThreadBlockedMonitor.stopWatching(!isSuspendAll ? suspendContext.getThread() : null);
@@ -1203,6 +1206,21 @@ public abstract class DebugProcessImpl extends UserDataHolderBase implements Deb
myWaitFor.waitFor(timeout);
}
private void mergeSuspendThreadContextToSuspendAllContext() {
boolean wasResumedSuspendThreadPausedContexts = false;
for (SuspendContextImpl anotherPausedContext : getSuspendManager().getPausedContexts()) {
if (anotherPausedContext.getSuspendPolicy() == EventRequest.SUSPEND_EVENT_THREAD) {
getSuspendManager().resume(anotherPausedContext);
wasResumedSuspendThreadPausedContexts = true;
}
}
if (wasResumedSuspendThreadPausedContexts) {
XDebuggerManagerImpl.getNotificationGroup()
.createNotification(JavaDebuggerBundle.message("message.switched.to.suspend.all.context"), MessageType.WARNING)
.notify(getProject());
}
//mySteppingProgressTracker.cancelAllSteppings();
}
private void resumeThreadsUnderEvaluationAndExplicitlyResumedAfterPause(@NotNull SuspendContextImpl suspendAllContext) {
for (SuspendContextImpl suspendContext : mySuspendManager.getEventContexts()) {
@@ -25,7 +25,9 @@ internal class SteppingProgressTracker(private val debuggerProcessImpl: DebugPro
/** returns true iff the [suspendContext] is the end of ongoing stepping */
fun onPaused(suspendContext: SuspendContext): Boolean {
val thread = suspendContext.thread
val completedSteps = trackedStepping.filter { it.threadFilter(thread, suspendContext as SuspendContextImpl) }
val completedSteps = if (suspendContext.suspendPolicy == EventRequest.SUSPEND_ALL) trackedStepping
else trackedStepping.filter { it.threadFilter(thread, suspendContext as SuspendContextImpl) }
for ((stepCompetedStatus, _) in completedSteps) {
stepCompetedStatus.complete(Unit)
}
@@ -26,6 +26,7 @@ import com.sun.jdi.event.ClassPrepareEvent;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.request.*;
import one.util.streamex.StreamEx;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -482,4 +483,14 @@ public class RequestManagerImpl extends DebugProcessAdapterImpl implements Reque
}
return false;
}
@ApiStatus.Internal
public void deleteAllStepRequests() {
List<Requestor> stepRequestors =
ContainerUtil.filter(myRequestorToBelongedRequests.keySet(), request -> request instanceof StepRequestor);
for (Requestor request : stepRequestors) {
deleteRequest(request);
}
}
}
@@ -706,7 +706,7 @@ public final class DebuggerSession implements AbstractDebuggerSession {
}
final ThreadReferenceProxyImpl newThread = suspendContext.getEventThread();
if (newThread == null || suspendContext.getSuspendPolicy() == EventRequest.SUSPEND_ALL || !myDebugProcess.isSteppingInProgress()) {
if (newThread == null || !myDebugProcess.isSteppingInProgress()) {
if (suspendContext.threadFilterWasPassed) {
return true;
}
@@ -82,6 +82,7 @@ message.breakpoint.skipped.learn.more=Troubleshooting guide
message.other.threads.reached.breakpoints={0,choice,1#Another thread also reached a breakpoint|2#{0} other threads also reached breakpoints}
message.resumed.other.threads.while.stepping=Resumed all threads because the "#{0}" thread is not in the "RUNNING" state
message.run.to.cursor.paused.in.another.thread=Suspended in another thread
message.switched.to.suspend.all.context=Context was switched to the suspend-all breakpoint
error.invalid.argument={0,choice, 1#Invalid argument|2#Invalid arguments}
error.vm.disconnected=VM disconnected. Target virtual machine closed connection
error.unknown.host=Cannot connect to remote process. Host is unknown