mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
javac canceling (embedded and external)
checkCanceled convenience method in context waitFor() API for RequestFuture
This commit is contained in:
@@ -284,13 +284,7 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
}
|
||||
try {
|
||||
for (RequestFuture future : futures) {
|
||||
try {
|
||||
future.get();
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
catch (java.util.concurrent.ExecutionException ignored) {
|
||||
}
|
||||
future.waitFor();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
@@ -447,7 +441,7 @@ public class CompileServerManager implements ApplicationComponent{
|
||||
connected = client.connect(NetUtils.getLocalHostString(), port);
|
||||
if (connected) {
|
||||
final RequestFuture setupFuture = sendSetupRequest(client);
|
||||
setupFuture.get();
|
||||
setupFuture.waitFor();
|
||||
myProcessHandler = processHandler;
|
||||
myClient = client;
|
||||
}
|
||||
|
||||
@@ -99,7 +99,7 @@ import org.jetbrains.jps.api.RequestFuture;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class CompileDriver {
|
||||
|
||||
@@ -591,15 +591,10 @@ public class CompileDriver {
|
||||
final Set<Artifact> artifacts = ArtifactCompileScope.getArtifactsToBuild(myProject, compileContext.getCompileScope(), true);
|
||||
final RequestFuture future = compileOnServer(compileContext, modules, artifacts, paths, callback);
|
||||
if (future != null) {
|
||||
try {
|
||||
startCancelWatcher(indicator, future);
|
||||
future.get();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
LOG.error(e); // todo
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
LOG.error(e); // todo
|
||||
while (!future.waitFor(200L , TimeUnit.MILLISECONDS)) {
|
||||
if (indicator.isCanceled()) {
|
||||
future.cancel(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -686,27 +681,6 @@ public class CompileDriver {
|
||||
});
|
||||
}
|
||||
|
||||
private static void startCancelWatcher(final ProgressIndicator indicator, final RequestFuture future) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
|
||||
public void run() {
|
||||
while (true) {
|
||||
try {
|
||||
Thread.sleep(200L);
|
||||
if (future.isDone() || future.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
if (indicator.isCanceled()) {
|
||||
future.cancel(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static List<String> fetchFiles(CompileContextImpl context) {
|
||||
if (context.isRebuild()) {
|
||||
return Collections.emptyList();
|
||||
|
||||
@@ -79,17 +79,34 @@ public class RequestFuture<T> implements Future {
|
||||
return myDone.get();
|
||||
}
|
||||
|
||||
public Object get() throws InterruptedException, ExecutionException {
|
||||
while (!isDone()) {
|
||||
mySemaphore.tryAcquire(100L, TimeUnit.MILLISECONDS);
|
||||
public void waitFor() {
|
||||
try {
|
||||
while (!isDone()) {
|
||||
mySemaphore.tryAcquire(100L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean waitFor(long timeout, TimeUnit unit) {
|
||||
try {
|
||||
if (!isDone()) {
|
||||
mySemaphore.tryAcquire(timeout, unit);
|
||||
}
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
return isDone();
|
||||
}
|
||||
|
||||
public Object get() throws InterruptedException, ExecutionException {
|
||||
waitFor();
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (!isDone()) {
|
||||
mySemaphore.tryAcquire(timeout, unit);
|
||||
}
|
||||
waitFor(timeout, unit);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import java.util.*;
|
||||
* Date: 9/17/11
|
||||
*/
|
||||
public class CompileContext extends UserDataHolderBase implements MessageHandler{
|
||||
private static final String CANCELED_MESSAGE = "The build has been canceled";
|
||||
private final CompileScope myScope;
|
||||
private final boolean myIsMake;
|
||||
private final boolean myIsProjectRebuild;
|
||||
@@ -155,10 +156,20 @@ public class CompileContext extends UserDataHolderBase implements MessageHandler
|
||||
return myCompilingTests;
|
||||
}
|
||||
|
||||
public CanceledStatus getCancelStatus() {
|
||||
public final CanceledStatus getCancelStatus() {
|
||||
return myCancelStatus;
|
||||
}
|
||||
|
||||
public final boolean isCanceled() {
|
||||
return getCancelStatus().isCanceled();
|
||||
}
|
||||
|
||||
public final void checkCanceled() throws ProjectBuildException {
|
||||
if (isCanceled()) {
|
||||
throw new ProjectBuildException(CANCELED_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
void setCompilingTests(boolean compilingTests) {
|
||||
myCompilingTests = compilingTests;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -34,7 +34,6 @@ public class IncProjectBuilder {
|
||||
private static final Logger LOG = Logger.getInstance("#org.jetbrains.jps.incremental.IncProjectBuilder");
|
||||
|
||||
public static final String COMPILE_SERVER_NAME = "COMPILE SERVER";
|
||||
private static final String CANCELED_MESSAGE = "The build has been canceled";
|
||||
|
||||
private final ProjectDescriptor myProjectDescriptor;
|
||||
private final BuilderRegistry myBuilderRegistry;
|
||||
@@ -119,11 +118,7 @@ public class IncProjectBuilder {
|
||||
if (descriptor != null) {
|
||||
try {
|
||||
final RequestFuture future = descriptor.client.sendShutdownRequest();
|
||||
future.get();
|
||||
}
|
||||
catch (InterruptedException ignored) {
|
||||
}
|
||||
catch (ExecutionException ignored) {
|
||||
future.waitFor(500L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
finally {
|
||||
// ensure process is not running
|
||||
@@ -229,9 +224,7 @@ public class IncProjectBuilder {
|
||||
// check that output and source roots are not overlapping
|
||||
final List<File> filesToDelete = new ArrayList<File>();
|
||||
for (File outputRoot : rootsToDelete) {
|
||||
if (myCancelStatus.isCanceled()) {
|
||||
throw new ProjectBuildException(CANCELED_MESSAGE);
|
||||
}
|
||||
context.checkCanceled();
|
||||
boolean okToDelete = true;
|
||||
if (PathUtil.isUnder(allSourceRoots, outputRoot)) {
|
||||
okToDelete = false;
|
||||
@@ -401,9 +394,7 @@ public class IncProjectBuilder {
|
||||
if (buildResult == ModuleLevelBuilder.ExitCode.ABORT) {
|
||||
throw new ProjectBuildException("Builder " + builder.getDescription() + " requested build stop");
|
||||
}
|
||||
if (myCancelStatus.isCanceled()) {
|
||||
throw new ProjectBuildException(CANCELED_MESSAGE);
|
||||
}
|
||||
context.checkCanceled();
|
||||
if (buildResult == ModuleLevelBuilder.ExitCode.ADDITIONAL_PASS_REQUIRED) {
|
||||
if (!nextPassRequired) {
|
||||
// recalculate basis
|
||||
@@ -447,9 +438,7 @@ public class IncProjectBuilder {
|
||||
private void runProjectLevelBuilders(CompileContext context) throws ProjectBuildException {
|
||||
for (ProjectLevelBuilder builder : myBuilderRegistry.getProjectLevelBuilders()) {
|
||||
builder.build(context);
|
||||
if (myCancelStatus.isCanceled()) {
|
||||
throw new ProjectBuildException(CANCELED_MESSAGE);
|
||||
}
|
||||
context.checkCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,8 @@ import java.net.ServerSocket;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -263,8 +263,13 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
final boolean compiledOk = compileJava(chunk, files, classpath, platformCp, sourcePath, outs, context, diagnosticSink, outputSink);
|
||||
|
||||
final Map<File, String> chunkSourcePath = ProjectPaths.getSourceRootsWithDependents(chunk, context.isCompilingTests());
|
||||
|
||||
context.checkCanceled();
|
||||
|
||||
final ClassLoader compiledClassesLoader = createInstrumentationClassLoader(classpath, platformCp, chunkSourcePath, outputSink);
|
||||
|
||||
context.checkCanceled();
|
||||
|
||||
if (!forms.isEmpty()) {
|
||||
try {
|
||||
context.processMessage(new ProgressMessage("Instrumenting forms [" + chunkName + "]"));
|
||||
@@ -275,6 +280,8 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
context.checkCanceled();
|
||||
|
||||
if (addNotNullAssertions) {
|
||||
try {
|
||||
context.processMessage(new ProgressMessage("Adding NotNull assertions [" + chunkName + "]"));
|
||||
@@ -285,6 +292,8 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
context.checkCanceled();
|
||||
|
||||
if (!compiledOk && diagnosticSink.getErrorCount() == 0) {
|
||||
diagnosticSink.report(new PlainMessageDiagnostic(Diagnostic.Kind.ERROR, "Compilation failed: internal java compiler error"));
|
||||
}
|
||||
@@ -356,14 +365,10 @@ public class JavaBuilder extends ModuleLevelBuilder {
|
||||
final RequestFuture<JavacServerResponseHandler> future = client.sendCompileRequest(
|
||||
options, files, classpath, platformCp, sourcePath, outs, diagnosticSink, classesConsumer
|
||||
);
|
||||
try {
|
||||
future.get();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
catch (ExecutionException e) {
|
||||
e.printStackTrace(System.err);
|
||||
while (!future.waitFor(100L, TimeUnit.MILLISECONDS)) {
|
||||
if (context.isCanceled()) {
|
||||
future.cancel(true);
|
||||
}
|
||||
}
|
||||
rc = future.getResponseHandler().isTerminatedSuccessfully();
|
||||
}
|
||||
|
||||
@@ -66,6 +66,18 @@ class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager
|
||||
return super.isSameFile(a, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileObject getFileForInput(Location location, String packageName, String relativeName) throws IOException {
|
||||
checkCanceled();
|
||||
return super.getFileForInput(location, packageName, relativeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaFileObject getJavaFileForInput(Location location, String className, JavaFileObject.Kind kind) throws IOException {
|
||||
checkCanceled();
|
||||
return super.getJavaFileForInput(location, className, kind);
|
||||
}
|
||||
|
||||
public JavaFileObject getJavaFileForOutput(Location location, String className, JavaFileObject.Kind kind, FileObject sibling) throws IOException {
|
||||
if (kind != JavaFileObject.Kind.SOURCE && kind != JavaFileObject.Kind.CLASS) {
|
||||
throw new IllegalArgumentException("Invalid kind " + kind);
|
||||
@@ -86,6 +98,8 @@ class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager
|
||||
}
|
||||
|
||||
private OutputFileObject getFileForOutput(Location location, JavaFileObject.Kind kind, String fileName, @Nullable String className, FileObject sibling) throws IOException {
|
||||
checkCanceled();
|
||||
|
||||
JavaFileObject src = null;
|
||||
if (sibling instanceof JavaFileObject) {
|
||||
final JavaFileObject javaFileObject = (JavaFileObject)sibling;
|
||||
@@ -190,4 +204,18 @@ class JavacFileManager extends ForwardingJavaFileManager<StandardJavaFileManager
|
||||
return name.toString().replace('.', File.separatorChar);
|
||||
}
|
||||
|
||||
private int myChecksCounter = 0;
|
||||
|
||||
private void checkCanceled() {
|
||||
final int counter = (myChecksCounter + 1) % 10;
|
||||
myChecksCounter = counter;
|
||||
if (counter == 0 && myContext.isCanceled()) {
|
||||
throw new RuntimeException("Compilation canceled") {
|
||||
@Override
|
||||
public Throwable fillInStackTrace() {
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@ package org.jetbrains.jps.javac;
|
||||
|
||||
import com.intellij.openapi.util.SystemInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jps.api.CanceledStatus;
|
||||
import org.jetbrains.jps.server.ClasspathBootstrap;
|
||||
|
||||
@@ -29,13 +28,14 @@ public class JavacMain {
|
||||
Collection<File> sourcePath,
|
||||
Map<File, Set<File>> outputDirToRoots,
|
||||
final DiagnosticOutputConsumer outConsumer,
|
||||
final OutputFileConsumer outputSink, @Nullable CanceledStatus canceledStatus) {
|
||||
final OutputFileConsumer outputSink,
|
||||
CanceledStatus canceledStatus) {
|
||||
final JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
|
||||
|
||||
for (File outputDir : outputDirToRoots.keySet()) {
|
||||
outputDir.mkdirs();
|
||||
}
|
||||
final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink));
|
||||
final JavacFileManager fileManager = new JavacFileManager(new ContextImpl(compiler, outConsumer, outputSink, canceledStatus));
|
||||
|
||||
fileManager.handleOption("-bootclasspath", Collections.singleton("").iterator()); // this will clear cached stuff
|
||||
fileManager.handleOption("-extdirs", Collections.singleton("").iterator()); // this will clear cached stuff
|
||||
@@ -111,10 +111,15 @@ public class JavacMain {
|
||||
private final StandardJavaFileManager myStdManager;
|
||||
private final DiagnosticOutputConsumer myOutConsumer;
|
||||
private final OutputFileConsumer myOutputFileSink;
|
||||
private final CanceledStatus myCanceledStatus;
|
||||
|
||||
public ContextImpl(@NotNull JavaCompiler compiler, @NotNull DiagnosticOutputConsumer outConsumer, @NotNull OutputFileConsumer sink) {
|
||||
public ContextImpl(@NotNull JavaCompiler compiler,
|
||||
@NotNull DiagnosticOutputConsumer outConsumer,
|
||||
@NotNull OutputFileConsumer sink,
|
||||
CanceledStatus canceledStatus) {
|
||||
myOutConsumer = outConsumer;
|
||||
myOutputFileSink = sink;
|
||||
myCanceledStatus = canceledStatus;
|
||||
StandardJavaFileManager stdManager = null;
|
||||
final Class<StandardJavaFileManager> optimizedManagerClass = ClasspathBootstrap.getOptimizedFileManagerClass();
|
||||
if (optimizedManagerClass != null) {
|
||||
@@ -136,7 +141,7 @@ public class JavacMain {
|
||||
}
|
||||
|
||||
public boolean isCanceled() {
|
||||
return false; // todo
|
||||
return myCanceledStatus.isCanceled();
|
||||
}
|
||||
|
||||
public StandardJavaFileManager getStandardFileManager() {
|
||||
|
||||
@@ -11,9 +11,9 @@ import org.jboss.netty.handler.codec.protobuf.ProtobufEncoder;
|
||||
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
|
||||
import org.jboss.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.api.CanceledStatus;
|
||||
|
||||
import javax.tools.Diagnostic;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.*;
|
||||
import java.io.File;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.util.*;
|
||||
@@ -32,10 +32,11 @@ public class JavacServer {
|
||||
private final ChannelGroup myAllOpenChannels = new DefaultChannelGroup("javac-server");
|
||||
private final ChannelFactory myChannelFactory;
|
||||
private final ChannelPipelineFactory myPipelineFactory;
|
||||
private ExecutorService myThreadPool;
|
||||
|
||||
public JavacServer() {
|
||||
final ExecutorService threadPool = Executors.newCachedThreadPool();
|
||||
myChannelFactory = new NioServerSocketChannelFactory(threadPool, threadPool, 1);
|
||||
myThreadPool = Executors.newCachedThreadPool();
|
||||
myChannelFactory = new NioServerSocketChannelFactory(myThreadPool, myThreadPool, 1);
|
||||
final ChannelRegistrar channelRegistrar = new ChannelRegistrar();
|
||||
final ChannelHandler compilationRequestsHandler = new CompilationRequestsHandler();
|
||||
myPipelineFactory = new ChannelPipelineFactory() {
|
||||
@@ -103,7 +104,15 @@ public class JavacServer {
|
||||
}
|
||||
|
||||
|
||||
public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx, final UUID sessionId, List<String> options, Collection<File> files, Collection<File> classpath, Collection<File> platformCp, Collection<File> sourcePath, Map<File, Set<File>> outs) {
|
||||
public static JavacRemoteProto.Message compile(final ChannelHandlerContext ctx,
|
||||
final UUID sessionId,
|
||||
List<String> options,
|
||||
Collection<File> files,
|
||||
Collection<File> classpath,
|
||||
Collection<File> platformCp,
|
||||
Collection<File> sourcePath,
|
||||
Map<File, Set<File>> outs,
|
||||
final CanceledStatus canceledStatus) {
|
||||
final DiagnosticOutputConsumer diagnostic = new DiagnosticOutputConsumer() {
|
||||
public void outputLineAvailable(String line) {
|
||||
Channels.write(ctx.getChannel(), JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createStdOutputResponse(line)));
|
||||
@@ -122,7 +131,7 @@ public class JavacServer {
|
||||
};
|
||||
|
||||
try {
|
||||
final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, null/*todo*/);
|
||||
final boolean rc = JavacMain.compile(options, files, classpath, platformCp, sourcePath, outs, diagnostic, outputSink, canceledStatus);
|
||||
return JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createBuildCompletedResponse(rc));
|
||||
}
|
||||
catch (Throwable e) {
|
||||
@@ -131,8 +140,14 @@ public class JavacServer {
|
||||
}
|
||||
}
|
||||
|
||||
public static void cancelBuild() {
|
||||
// todo
|
||||
private final Set<CancelHandler> myCancelHandlers = Collections.synchronizedSet(new HashSet<CancelHandler>());
|
||||
|
||||
public void cancelBuilds() {
|
||||
synchronized (myCancelHandlers) {
|
||||
for (CancelHandler handler : myCancelHandlers) {
|
||||
handler.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<File> toFiles(List<String> paths) {
|
||||
@@ -145,7 +160,7 @@ public class JavacServer {
|
||||
|
||||
private class CompilationRequestsHandler extends SimpleChannelHandler {
|
||||
|
||||
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||
public void messageReceived(final ChannelHandlerContext ctx, MessageEvent e) throws Exception {
|
||||
final JavacRemoteProto.Message msg = (JavacRemoteProto.Message)e.getMessage();
|
||||
final UUID sessionId = JavacProtoUtil.fromProtoUUID(msg.getSessionId());
|
||||
final JavacRemoteProto.Message.Type messageType = msg.getMessageType();
|
||||
@@ -172,14 +187,26 @@ public class JavacServer {
|
||||
outs.put(new File(outputGroup.getOutputRoot()), srcRoots);
|
||||
}
|
||||
|
||||
reply = compile(ctx, sessionId, options, files, cp, platformCp, srcPath, outs);
|
||||
final CancelHandler cancelHandler = new CancelHandler();
|
||||
myCancelHandlers.add(cancelHandler);
|
||||
myThreadPool.submit(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
final JavacRemoteProto.Message exitMsg = compile(ctx, sessionId, options, files, cp, platformCp, srcPath, outs, cancelHandler);
|
||||
Channels.write(ctx.getChannel(), exitMsg);
|
||||
}
|
||||
finally {
|
||||
myCancelHandlers.remove(cancelHandler);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (requestType == JavacRemoteProto.Message.Request.Type.CANCEL){
|
||||
cancelBuild();
|
||||
cancelBuilds();
|
||||
reply = JavacProtoUtil.toMessage(sessionId, JavacProtoUtil.createRequestAckResponse());
|
||||
}
|
||||
else if (requestType == JavacRemoteProto.Message.Request.Type.SHUTDOWN){
|
||||
cancelBuild();
|
||||
cancelBuilds();
|
||||
new Thread("StopThread") {
|
||||
public void run() {
|
||||
JavacServer.this.stop();
|
||||
@@ -213,4 +240,19 @@ public class JavacServer {
|
||||
super.channelOpen(ctx, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static class CancelHandler implements CanceledStatus {
|
||||
private volatile boolean myIsCanceled = false;
|
||||
|
||||
private CancelHandler() {
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
myIsCanceled = true;
|
||||
}
|
||||
|
||||
public boolean isCanceled() {
|
||||
return myIsCanceled;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user