diff --git a/java/compiler/impl/intellij.java.compiler.impl.iml b/java/compiler/impl/intellij.java.compiler.impl.iml index 67db63ddd429..db349a6e6bde 100644 --- a/java/compiler/impl/intellij.java.compiler.impl.iml +++ b/java/compiler/impl/intellij.java.compiler.impl.iml @@ -8,13 +8,11 @@ - - @@ -25,30 +23,33 @@ - - - - - - - + + + + + + + + + + + + - - diff --git a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java index 55b8a7ba10dd..6d730782d68b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -124,11 +124,9 @@ public final class CompileDriver { buildManager.postponeBackgroundTasks(); buildManager.cancelAutoMakeTasks(myProject); TaskFuture future = compileInExternalProcess(compileContext, true); - if (future != null) { - while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { - if (indicator.isCanceled()) { - future.cancel(false); - } + while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { + if (indicator.isCanceled()) { + future.cancel(false); } } } @@ -221,7 +219,7 @@ public final class CompileDriver { return scopes; } - @Nullable + @NotNull private TaskFuture compileInExternalProcess(@NotNull final CompileContextImpl compileContext, final boolean onlyCheckUpToDate) { final CompileScope scope = compileContext.getCompileScope(); final Collection paths = ReadAction.compute(() -> CompileScopeUtil.fetchFiles(compileContext)); @@ -450,21 +448,19 @@ public final class CompileDriver { } TaskFuture future = compileInExternalProcess(compileContext, false); - if (future != null) { - Tracer.Span compileInExternalProcessSpan = Tracer.start("compile in external process"); - while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { - if (indicator.isCanceled()) { - future.cancel(false); - } - } - compileInExternalProcessSpan.complete(); - if (!executeCompileTasks(compileContext, false)) { - COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED); - } - if (compileContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) { - COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.ERRORS); + Tracer.Span compileInExternalProcessSpan = Tracer.start("compile in external process"); + while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { + if (indicator.isCanceled()) { + future.cancel(false); } } + compileInExternalProcessSpan.complete(); + if (!executeCompileTasks(compileContext, false)) { + COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.CANCELLED); + } + if (compileContext.getMessageCount(CompilerMessageCategory.ERROR) > 0) { + COMPILE_SERVER_BUILD_STATUS.set(compileContext, ExitStatus.ERRORS); + } } catch (ProcessCanceledException ignored) { compileContext.putUserDataIfAbsent(COMPILE_SERVER_BUILD_STATUS, ExitStatus.CANCELLED); diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildCommandLineBuilder.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildCommandLineBuilder.java index 4ddd269acfa9..09cf1f18893f 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildCommandLineBuilder.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildCommandLineBuilder.java @@ -1,4 +1,4 @@ -// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.compiler.server; import com.intellij.compiler.YourKitProfilerService; @@ -6,7 +6,6 @@ import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import org.jetbrains.annotations.NotNull; -import java.net.InetAddress; import java.nio.charset.Charset; import java.nio.file.Path; import java.util.List; @@ -27,11 +26,6 @@ interface BuildCommandLineBuilder { @NotNull Path getHostWorkingDirectory(); - InetAddress getListenAddress(); - - @NotNull - String getHostIp() throws ExecutionException; - String getYjpAgentPath(YourKitProfilerService yourKitProfilerService); void setCharset(Charset charset); diff --git a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java index 3b3be268614b..2fa8d445387b 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -23,6 +23,7 @@ import com.intellij.execution.runners.ExecutionEnvironment; import com.intellij.execution.wsl.WSLDistribution; import com.intellij.execution.wsl.WslDistributionManager; import com.intellij.execution.wsl.WslPath; +import com.intellij.execution.wsl.WslProxy; import com.intellij.ide.IdleTracker; import com.intellij.ide.PowerSaveMode; import com.intellij.ide.actions.RevealFileAction; @@ -287,6 +288,7 @@ public final class BuildManager implements Disposable { } private final List myListeningConnections = new ArrayList<>(); + private final Map myWslProxyCache = new HashMap<>(); private final @NotNull Charset mySystemCharset = CharsetToolkit.getDefaultSystemCharset(); private volatile boolean myBuildProcessDebuggingEnabled; @@ -406,7 +408,10 @@ public final class BuildManager implements Disposable { }); } - ShutDownTracker.getInstance().registerShutdownTask(this::stopListening); + ShutDownTracker.getInstance().registerShutdownTask(() -> { + stopListening(); + clearWslProxyCache(); + }); if (!IS_UNIT_TEST_MODE) { ScheduledFuture future = AppExecutorUtil.getAppScheduledExecutorService().scheduleWithFixedDelay(() -> runCommand(myGCTask), 3, 180, TimeUnit.MINUTES); @@ -716,10 +721,8 @@ public final class BuildManager implements Disposable { final TaskFuture future = scheduleBuild( project, false, true, false, scopes, Collections.emptyList(), Collections.singletonMap(BuildParametersKeys.IS_AUTOMAKE, "true"), handler ); - if (future != null) { - myAutomakeFutures.put(future, project); - futures.add(new Pair<>(future, handler)); - } + myAutomakeFutures.put(future, project); + futures.add(new Pair<>(future, handler)); } boolean needAdditionalBuild = false; for (Pair, AutoMakeMessageHandler> pair : futures) { @@ -862,7 +865,7 @@ public final class BuildManager implements Disposable { return result != null && !result.first.isDone()? result : null; } - public @Nullable TaskFuture scheduleBuild( + public @NotNull TaskFuture scheduleBuild( final Project project, final boolean isRebuild, final boolean isMake, final boolean onlyCheckUpToDate, final List scopes, final Collection paths, @@ -873,15 +876,6 @@ public final class BuildManager implements Disposable { final boolean isAutomake = messageHandler instanceof AutoMakeMessageHandler; final WSLDistribution wslDistribution = findWSLDistribution(project); final BuilderMessageHandler handler = new NotifyingMessageHandler(project, messageHandler, wslDistribution != null ? wslDistribution::getWindowsPath : null, isAutomake); - try { - ensureListening(wslDistribution != null ? wslDistribution.getHostIpAddress() : InetAddress.getLoopbackAddress()); - } - catch (Exception e) { - final UUID sessionId = UUID.randomUUID(); // the actual session did not start; use random UUID - handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), null)); - handler.sessionTerminated(sessionId); - return null; - } Function pathMapper = wslDistribution != null ? wslDistribution::getWslPath : Function.identity(); final DelegateFuture _future = new DelegateFuture(); @@ -1128,9 +1122,30 @@ public final class BuildManager implements Disposable { return startListening(inetAddress); } + private synchronized int getWslPort(WSLDistribution dist, int localPort) { + return myWslProxyCache.computeIfAbsent(dist.getId() + ":" + localPort, key -> new WslProxy(dist, localPort)).getWslIngressPort(); + } + + private synchronized void cleanWslProxies(WSLDistribution dist) { + String idPrefix = dist.getId() + ":"; + List keys = new SmartList<>(); + for (String key : myWslProxyCache.keySet()) { + if (key.startsWith(idPrefix)) { + keys.add(key); + } + } + for (String key : keys) { + WslProxy proxy = myWslProxyCache.remove(key); + if (proxy != null) { + Disposer.dispose(proxy); + } + } + } + @Override public void dispose() { stopListening(); + clearWslProxyCache(); myAutomakeTrigger.cancel(); myRequestsProcessor.cancel(); } @@ -1323,6 +1338,11 @@ public final class BuildManager implements Disposable { final CompilerConfiguration projectConfig = CompilerConfiguration.getInstance(project); final CompilerWorkspaceConfiguration config = CompilerWorkspaceConfiguration.getInstance(project); + InetAddress listenAddress = InetAddress.getLoopbackAddress(); + int listenPort = ensureListening(listenAddress); + String buildProcessConnectHost = listenAddress.getHostAddress(); + int buildProcessConnectPort = listenPort; + BuildCommandLineBuilder cmdLine; WslPath wslPath = WslPath.parseWindowsUncPath(vmExecutablePath); if (wslPath != null) { @@ -1331,6 +1351,8 @@ public final class BuildManager implements Disposable { throw new ExecutionException(JavaCompilerBundle.message("build.process.wsl.distribution.dont.match", sdkName + " (WSL " + sdkDistribution.getPresentableName() + ")", MINIMUM_REQUIRED_JPS_BUILD_JAVA_VERSION)); } cmdLine = new WslBuildCommandLineBuilder(project, sdkDistribution, wslPath.getLinuxPath(), progressIndicator); + buildProcessConnectHost = "127.0.0.1"; // WslProxy listen address on linux side + buildProcessConnectPort = getWslPort(sdkDistribution, listenPort); } else { if (projectWslDistribution != null) { @@ -1338,7 +1360,6 @@ public final class BuildManager implements Disposable { } cmdLine = new LocalBuildCommandLineBuilder(vmExecutablePath); } - int listenPort = ensureListening(cmdLine.getListenAddress()); boolean profileWithYourKit = false; boolean isAgentpathSet = false; @@ -1612,8 +1633,8 @@ public final class BuildManager implements Disposable { } cmdLine.addParameter(BuildMain.class.getName()); - cmdLine.addParameter(cmdLine.getHostIp()); - cmdLine.addParameter(Integer.toString(listenPort)); + cmdLine.addParameter(buildProcessConnectHost); + cmdLine.addParameter(Integer.toString(buildProcessConnectPort)); cmdLine.addParameter(sessionId.toString()); cmdLine.addParameter(cmdLine.getWorkingDirectory()); @@ -1782,13 +1803,24 @@ public final class BuildManager implements Disposable { return null; } - private void stopListening() { + private synchronized void stopListening() { for (ListeningConnection connection : myListeningConnections) { connection.myChannelRegistrar.close(); } myListeningConnections.clear(); } + private synchronized void clearWslProxyCache() { + for (WslProxy proxy : myWslProxyCache.values()) { + try { + Disposer.dispose(proxy); + } + catch (Throwable ignored) { + } + } + myWslProxyCache.clear(); + } + private int startListening(InetAddress address) { ListeningConnection listeningConnection = new ListeningConnection(address); BuiltInServerManager builtInServerManager = BuiltInServerManager.getInstance(); @@ -2193,6 +2225,10 @@ public final class BuildManager implements Disposable { } } }); + WSLDistribution wslDistr = findWSLDistribution(project); + if (wslDistr != null) { + cleanWslProxies(wslDistr); + } } @Override diff --git a/java/compiler/impl/src/com/intellij/compiler/server/LocalBuildCommandLineBuilder.java b/java/compiler/impl/src/com/intellij/compiler/server/LocalBuildCommandLineBuilder.java index 21b493c7f1a8..abc678366aed 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/LocalBuildCommandLineBuilder.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/LocalBuildCommandLineBuilder.java @@ -10,7 +10,6 @@ import com.intellij.openapi.util.io.FileUtilRt; import org.jetbrains.annotations.NotNull; import java.io.File; -import java.net.InetAddress; import java.nio.charset.Charset; import java.nio.file.Path; import java.util.List; @@ -62,16 +61,6 @@ final class LocalBuildCommandLineBuilder implements BuildCommandLineBuilder { return getLocalBuildSystemDirectory(); } - @Override - public InetAddress getListenAddress() { - return InetAddress.getLoopbackAddress(); - } - - @Override - public @NotNull String getHostIp() { - return getListenAddress().getHostAddress(); - } - @Override public String getYjpAgentPath(YourKitProfilerService yourKitProfilerService) { return getLocalBuildSystemDirectory() diff --git a/java/compiler/impl/src/com/intellij/compiler/server/WslBuildCommandLineBuilder.java b/java/compiler/impl/src/com/intellij/compiler/server/WslBuildCommandLineBuilder.java index 5145f376597e..f5aca41f9a96 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/WslBuildCommandLineBuilder.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/WslBuildCommandLineBuilder.java @@ -20,7 +20,6 @@ import org.jetbrains.jps.api.GlobalOptions; import java.io.FileNotFoundException; import java.io.IOException; -import java.net.InetAddress; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.NoSuchFileException; @@ -43,8 +42,7 @@ final class WslBuildCommandLineBuilder implements BuildCommandLineBuilder { private static boolean CURRENT_SNAPSHOT_COPIED = false; private boolean myReportedProgress; - WslBuildCommandLineBuilder(@NotNull Project project, @NotNull WSLDistribution distribution, @NotNull String sdkPath, - @Nullable ProgressIndicator progressIndicator) { + WslBuildCommandLineBuilder(@NotNull Project project, @NotNull WSLDistribution distribution, @NotNull String sdkPath, @Nullable ProgressIndicator progressIndicator) { myProject = project; myDistribution = distribution; myProgressIndicator = progressIndicator; @@ -156,21 +154,6 @@ final class WslBuildCommandLineBuilder implements BuildCommandLineBuilder { return myWorkingDirectory; } - @Override - public InetAddress getListenAddress() { - try { - return myDistribution.getHostIpAddress(); - } - catch (ExecutionException ignored) { - return null; - } - } - - @Override - public @NotNull String getHostIp() throws ExecutionException { - return myDistribution.getHostIpAddress().getHostAddress(); - } - @Override public String getYjpAgentPath(YourKitProfilerService yourKitProfilerService) { return myWorkingDirectory + "/" + yourKitProfilerService.getYKAgentFullNameForWSL();