From ed7947f51c7cfb333973e29d4283945b110e941b Mon Sep 17 00:00:00 2001 From: Aleksey Pivovarov Date: Mon, 18 Mar 2024 18:51:23 +0100 Subject: [PATCH] IJPL-760 git: do not freeze UI if git process cancellation has failed The observed freeze happened on 'OSProcessUtil - Cannot killProcessTree already terminated process', that has left UI frozen for 2xTERMINATION_TIMEOUT_MS seconds. GitOrigin-RevId: cf92928975ed869091264107849262c03267cfb8 --- .../src/git4idea/commands/GitTextHandler.java | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/plugins/git4idea/src/git4idea/commands/GitTextHandler.java b/plugins/git4idea/src/git4idea/commands/GitTextHandler.java index 789337c99780..aa429831aff8 100644 --- a/plugins/git4idea/src/git4idea/commands/GitTextHandler.java +++ b/plugins/git4idea/src/git4idea/commands/GitTextHandler.java @@ -8,6 +8,7 @@ import com.intellij.execution.process.KillableProcessHandler; import com.intellij.execution.process.OSProcessHandler; import com.intellij.execution.process.ProcessAdapter; import com.intellij.execution.process.ProcessEvent; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.progress.ProcessCanceledException; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; @@ -112,29 +113,48 @@ public abstract class GitTextHandler extends GitHandler { ProgressManager.checkCanceled(); } catch (ProcessCanceledException pce) { - ProgressManager.getInstance().executeNonCancelableSection(() -> { - if (!tryKill()) { - LOG.warn("Could not terminate [" + printableCommandLine() + "]."); - } - }); + tryKillProcess(); throw pce; } } } } - private boolean tryKill() { - myHandler.destroyProcess(); + private void tryKillProcess() { + ProgressManager.getInstance().executeNonCancelableSection(() -> { + myHandler.destroyProcess(); + }); - // signal was sent, but we still need to wait for process to finish its dark deeds + if (ApplicationManager.getApplication().isReadAccessAllowed() || + shouldSuppressReadLocks()) { + // Some Git operations are called while holding the global locks. + // Ex: access to the 'GitIndexVirtualFile' or 'GitDirectoryVirtualFile'. + // In this case, we should not delay the current thread cancellation. + ApplicationManager.getApplication().executeOnPooledThread(() -> { + waitAndHardKillProcess(); + }); + } + else { + ProgressManager.getInstance().executeNonCancelableSection(() -> { + waitAndHardKillProcess(); + }); + } + } + + private void waitAndHardKillProcess() { + // The signal was sent, but we still need to wait for the process to finish its dark deeds if (myHandler.waitFor(myTerminationTimeoutMs)) { - return true; + return; } LOG.warn("Soft-kill failed for [" + printableCommandLine() + "]."); ExecutionManagerImpl.stopProcess(myHandler); - return myHandler.waitFor(myTerminationTimeoutMs); + if (myHandler.waitFor(myTerminationTimeoutMs)) { + return; + } + + LOG.warn("Could not terminate [" + printableCommandLine() + "]."); } protected OSProcessHandler createProcess(@NotNull GeneralCommandLine commandLine) throws ExecutionException {