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 d4a69206c3ba..a5685017d365 100644 --- a/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java +++ b/java/compiler/impl/src/com/intellij/compiler/impl/CompileDriver.java @@ -71,9 +71,9 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.TestOnly; -import org.jetbrains.jps.api.BasicFuture; import org.jetbrains.jps.api.CmdlineProtoUtil; import org.jetbrains.jps.api.CmdlineRemoteProto; +import org.jetbrains.jps.api.TaskFuture; import org.jetbrains.jps.model.java.JavaSourceRootType; import javax.swing.*; @@ -138,7 +138,7 @@ public class CompileDriver { return; } try { - final BasicFuture future = compileInExternalProcess(compileContext, true); + final TaskFuture future = compileInExternalProcess(compileContext, true); if (future != null) { while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { if (indicator.isCanceled()) { @@ -194,7 +194,7 @@ public class CompileDriver { } @Nullable - private BasicFuture compileInExternalProcess(final @NotNull CompileContextImpl compileContext, final boolean onlyCheckUpToDate) + private TaskFuture compileInExternalProcess(final @NotNull CompileContextImpl compileContext, final boolean onlyCheckUpToDate) throws Exception { final CompileScope scope = compileContext.getCompileScope(); final Collection paths = CompileScopeUtil.fetchFiles(compileContext); @@ -400,7 +400,7 @@ public class CompileDriver { return; } - final BasicFuture future = compileInExternalProcess(compileContext, false); + final TaskFuture future = compileInExternalProcess(compileContext, false); if (future != null) { while (!future.waitFor(200L, TimeUnit.MILLISECONDS)) { if (indicator.isCanceled()) { 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 2c5b378d96ea..efaf9e2b4346 100644 --- a/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java +++ b/java/compiler/impl/src/com/intellij/compiler/server/BuildManager.java @@ -100,7 +100,8 @@ import org.jetbrains.jps.cmdline.ClasspathBootstrap; import org.jetbrains.jps.incremental.Utils; import org.jetbrains.jps.model.serialization.JpsGlobalLoader; -import javax.tools.*; +import javax.tools.JavaCompiler; +import javax.tools.ToolProvider; import java.awt.*; import java.io.File; import java.io.IOException; @@ -108,8 +109,7 @@ import java.net.InetSocketAddress; import java.nio.charset.Charset; import java.util.*; import java.util.List; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; import static org.jetbrains.jps.api.CmdlineRemoteProto.Message.ControllerMessage.ParametersMessage.TargetTypeBuildScope; @@ -148,10 +148,10 @@ public class BuildManager implements ApplicationComponent{ private final File mySystemDirectory; private final ProjectManager myProjectManager; - private final Map myAutomakeFutures = Collections.synchronizedMap(new HashMap()); + private final Map myAutomakeFutures = Collections.synchronizedMap(new HashMap()); private final Map myBuildsInProgress = Collections.synchronizedMap(new HashMap()); - private final Map, OSProcessHandler>> myPreloadedBuilds = - Collections.synchronizedMap(new HashMap, OSProcessHandler>>()); + private final Map, OSProcessHandler>>> myPreloadedBuilds = + Collections.synchronizedMap(new HashMap, OSProcessHandler>>>()); private final BuildProcessClasspathManager myClasspathManager = new BuildProcessClasspathManager(); private final SequentialTaskExecutor myRequestsProcessor = new SequentialTaskExecutor(PooledThreadExecutor.INSTANCE); private final Map myProjectDataMap = Collections.synchronizedMap(new HashMap()); @@ -447,7 +447,7 @@ public class BuildManager implements ApplicationComponent{ } final List scopes = CmdlineProtoUtil.createAllModulesScopes(false); final AutoMakeMessageHandler handler = new AutoMakeMessageHandler(project); - final BasicFuture future = scheduleBuild( + final TaskFuture future = scheduleBuild( project, false, true, false, scopes, Collections.emptyList(), Collections.emptyMap(), handler ); if (future != null) { @@ -526,12 +526,12 @@ public class BuildManager implements ApplicationComponent{ return false; } - public Collection cancelAutoMakeTasks(Project project) { - final Collection futures = new SmartList(); + public Collection cancelAutoMakeTasks(Project project) { + final Collection futures = new SmartList(); synchronized (myAutomakeFutures) { - for (Map.Entry entry : myAutomakeFutures.entrySet()) { + for (Map.Entry entry : myAutomakeFutures.entrySet()) { if (entry.getValue().equals(project)) { - final BasicFuture future = entry.getKey(); + final TaskFuture future = entry.getKey(); future.cancel(false); futures.add(future); } @@ -542,15 +542,15 @@ public class BuildManager implements ApplicationComponent{ private void cancelPreloadedBuilds(Project project) { final String projectPath = getProjectPath(project); - final Pair, OSProcessHandler> pair = myPreloadedBuilds.remove(projectPath); - if (pair != null) { - final RequestFuture future = pair.first; - myMessageDispatcher.cancelSession(future.getRequestID()); - runCommand(new Runnable() { - @Override - public void run() { + runCommand(new Runnable() { + @Override + public void run() { + Pair, OSProcessHandler> pair = takePreloadedProcess(projectPath); + if (pair != null) { + final RequestFuture future = pair.first; + myMessageDispatcher.cancelSession(future.getRequestID()); // waiting for preloaded process from project's task queue guarantees no build is started for this project - // until this one gracefully exits and closes all its storages + // until this one gracefully exits and closes all its storages getProjectData(projectPath).taskQueue.submit(new Runnable() { @Override public void run() { @@ -558,207 +558,221 @@ public class BuildManager implements ApplicationComponent{ } }); } - }); - } + } + }); } @Nullable - public BasicFuture scheduleBuild( + private Pair, OSProcessHandler> takePreloadedProcess(String projectPath) { + Pair, OSProcessHandler> result; + final Future, OSProcessHandler>> preloadProgress = myPreloadedBuilds.remove(projectPath); + try { + result = preloadProgress != null ? preloadProgress.get() : null; + } + catch (Throwable e) { + LOG.info(e); + result = null; + } + return result; + } + + @Nullable + public TaskFuture scheduleBuild( final Project project, final boolean isRebuild, final boolean isMake, final boolean onlyCheckUpToDate, final List scopes, final Collection paths, final Map userData, final DefaultMessageHandler messageHandler) { final String projectPath = getProjectPath(project); - - final Pair, OSProcessHandler> preloaded = myPreloadedBuilds.remove(projectPath); - final RequestFuture preloadedFuture = preloaded != null? preloaded.first : null; - final boolean usingPreloadedProcess = preloadedFuture != null; - - final UUID sessionId; final BuilderMessageHandler handler = new NotifyingMessageHandler(project, messageHandler, messageHandler instanceof AutoMakeMessageHandler); - if (usingPreloadedProcess) { - LOG.info("Using preloaded build process to compile " + projectPath); - sessionId = preloadedFuture.getRequestID(); - preloadedFuture.getMessageHandler().setDelegateHandler(handler); - } - else { - sessionId = UUID.randomUUID(); - } - try { ensureListening(); } 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; } - try { - final RequestFuture future = usingPreloadedProcess? preloadedFuture : new RequestFuture(handler, sessionId, new RequestFuture.CancelAction() { - @Override - public void cancel(RequestFuture future) throws Exception { - myMessageDispatcher.cancelSession(future.getRequestID()); + final DelegateFuture _future = new DelegateFuture(); + // by using the same queue that processes events we ensure that + // the build will be aware of all events that have happened before this request + runCommand(new Runnable() { + @Override + public void run() { + + final Pair, OSProcessHandler> preloaded = takePreloadedProcess(projectPath); + final RequestFuture preloadedFuture = preloaded != null? preloaded.first : null; + final boolean usingPreloadedProcess = preloadedFuture != null; + + final UUID sessionId; + if (usingPreloadedProcess) { + LOG.info("Using preloaded build process to compile " + projectPath); + sessionId = preloadedFuture.getRequestID(); + preloadedFuture.getMessageHandler().setDelegateHandler(handler); + } + else { + sessionId = UUID.randomUUID(); } - }); - // by using the same queue that processes events we ensure that - // the build will be aware of all events that have happened before this request - runCommand(new Runnable() { - @Override - public void run() { - if (!usingPreloadedProcess && (future.isCancelled() || project.isDisposed())) { - // in case of preloaded process the process was already running, so the handler will be notified upon process termination - handler.sessionTerminated(sessionId); - future.setDone(); - return; - } - final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = - CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.newBuilder().setGlobalOptionsPath(PathManager.getOptionsPath()).build(); - CmdlineRemoteProto.Message.ControllerMessage.FSEvent currentFSChanges; - final SequentialTaskExecutor projectTaskQueue; - synchronized (myProjectDataMap) { - final ProjectData data = getProjectData(projectPath); - if (isRebuild) { - data.dropChanges(); - } - if (IS_UNIT_TEST_MODE) { - LOG.info("Scheduling build for " + - projectPath + - "; CHANGED: " + - new HashSet(convertToStringPaths(data.myChanged)) + - "; DELETED: " + - new HashSet(convertToStringPaths(data.myDeleted))); - } - currentFSChanges = data.getAndResetRescanFlag() ? null : data.createNextEvent(); - projectTaskQueue = data.taskQueue; + final RequestFuture future = usingPreloadedProcess? preloadedFuture : new RequestFuture(handler, sessionId, new RequestFuture.CancelAction() { + @Override + public void cancel(RequestFuture future) throws Exception { + myMessageDispatcher.cancelSession(future.getRequestID()); } + }); + _future.setDelegate(future); - final CmdlineRemoteProto.Message.ControllerMessage params; + if (!usingPreloadedProcess && (future.isCancelled() || project.isDisposed())) { + // in case of preloaded process the process was already running, so the handler will be notified upon process termination + handler.sessionTerminated(sessionId); + ((BasicFuture)future).setDone(); + return; + } + + final CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings globals = + CmdlineRemoteProto.Message.ControllerMessage.GlobalSettings.newBuilder().setGlobalOptionsPath(PathManager.getOptionsPath()).build(); + CmdlineRemoteProto.Message.ControllerMessage.FSEvent currentFSChanges; + final SequentialTaskExecutor projectTaskQueue; + synchronized (myProjectDataMap) { + final ProjectData data = getProjectData(projectPath); if (isRebuild) { - params = CmdlineProtoUtil.createBuildRequest(projectPath, scopes, Collections.emptyList(), userData, globals, null); + data.dropChanges(); } - else if (onlyCheckUpToDate) { - params = CmdlineProtoUtil.createUpToDateCheckRequest(projectPath, scopes, paths, userData, globals, currentFSChanges); - } - else { - params = CmdlineProtoUtil.createBuildRequest(projectPath, scopes, isMake ? Collections.emptyList() : paths, userData, globals, currentFSChanges); - } - if (!usingPreloadedProcess) { - myMessageDispatcher.registerBuildMessageHandler(future, params); + if (IS_UNIT_TEST_MODE) { + LOG.info("Scheduling build for " + + projectPath + + "; CHANGED: " + + new HashSet(convertToStringPaths(data.myChanged)) + + "; DELETED: " + + new HashSet(convertToStringPaths(data.myDeleted))); } + currentFSChanges = data.getAndResetRescanFlag() ? null : data.createNextEvent(); + projectTaskQueue = data.taskQueue; + } - try { - projectTaskQueue.submit(new Runnable() { - @Override - public void run() { - Throwable execFailure = null; - try { - if (project.isDisposed()) { - if (usingPreloadedProcess) { - future.cancel(true); - } - else { - return; - } - } - myBuildsInProgress.put(projectPath, future); - final OSProcessHandler processHandler; - final StringBuilder errorsOnLaunch = new StringBuilder(); + final CmdlineRemoteProto.Message.ControllerMessage params; + if (isRebuild) { + params = CmdlineProtoUtil.createBuildRequest(projectPath, scopes, Collections.emptyList(), userData, globals, null); + } + else if (onlyCheckUpToDate) { + params = CmdlineProtoUtil.createUpToDateCheckRequest(projectPath, scopes, paths, userData, globals, currentFSChanges); + } + else { + params = CmdlineProtoUtil.createBuildRequest(projectPath, scopes, isMake ? Collections.emptyList() : paths, userData, globals, currentFSChanges); + } + if (!usingPreloadedProcess) { + myMessageDispatcher.registerBuildMessageHandler(future, params); + } + + try { + projectTaskQueue.submit(new Runnable() { + @Override + public void run() { + Throwable execFailure = null; + try { + if (project.isDisposed()) { if (usingPreloadedProcess) { - final boolean paramsSent = myMessageDispatcher.sendBuildParameters(future.getRequestID(), params); - if (!paramsSent) { - myMessageDispatcher.cancelSession(future.getRequestID()); - } - processHandler = preloaded.second; + future.cancel(true); } else { - processHandler = launchBuildProcess(project, myListenPort, sessionId, false); - processHandler.addProcessListener(new ProcessAdapter() { - @Override - public void onTextAvailable(ProcessEvent event, Key outputType) { - if (ProcessOutputTypes.STDERR.equals(outputType)) { - if (errorsOnLaunch.length() < 1024) { - final String text = event.getText(); - if (!StringUtil.isEmptyOrSpaces(text)) { - errorsOnLaunch.append(text); - } + return; + } + } + myBuildsInProgress.put(projectPath, future); + final OSProcessHandler processHandler; + final StringBuilder errorsOnLaunch = new StringBuilder(); + if (usingPreloadedProcess) { + final boolean paramsSent = myMessageDispatcher.sendBuildParameters(future.getRequestID(), params); + if (!paramsSent) { + myMessageDispatcher.cancelSession(future.getRequestID()); + } + processHandler = preloaded.second; + } + else { + processHandler = launchBuildProcess(project, myListenPort, sessionId, false); + processHandler.addProcessListener(new ProcessAdapter() { + @Override + public void onTextAvailable(ProcessEvent event, Key outputType) { + if (ProcessOutputTypes.STDERR.equals(outputType)) { + if (errorsOnLaunch.length() < 1024) { + final String text = event.getText(); + if (!StringUtil.isEmptyOrSpaces(text)) { + errorsOnLaunch.append(text); } } } - }); - processHandler.startNotify(); - } - - final boolean terminated = processHandler.waitFor(); - if (terminated) { - final int exitValue = processHandler.getProcess().exitValue(); - if (exitValue != 0) { - final StringBuilder msg = new StringBuilder(); - msg.append("Abnormal build process termination: "); - if (errorsOnLaunch.length() > 0) { - msg.append("\n").append(errorsOnLaunch); - } - else { - msg.append("unknown error"); - } - handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null)); } - } - else { - handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null)); + }); + processHandler.startNotify(); + } + + final boolean terminated = processHandler.waitFor(); + if (terminated) { + final int exitValue = processHandler.getProcess().exitValue(); + if (exitValue != 0) { + final StringBuilder msg = new StringBuilder(); + msg.append("Abnormal build process termination: "); + if (errorsOnLaunch.length() > 0) { + msg.append("\n").append(errorsOnLaunch); + } + else { + msg.append("unknown error"); + } + handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(msg.toString(), null)); } } - catch (Throwable e) { - execFailure = e; - } - finally { - myBuildsInProgress.remove(projectPath); - if (myMessageDispatcher.getAssociatedChannel(sessionId) == null) { - // either the connection has never been established (process not started or execution failed), or no messages were sent from the launched process. - // in this case the session cannot be unregistered by the message dispatcher - final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId); - if (unregistered != null) { - if (execFailure != null) { - unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(execFailure.getMessage(), execFailure)); - } - unregistered.sessionTerminated(sessionId); - } - } - - if (Registry.is("compiler.process.preload") && !project.isDisposed()) { - try { - final Pair, OSProcessHandler> pair = launchPreloadedBuildProcess(project); - myPreloadedBuilds.put(projectPath, pair); - } - catch (Exception e) { - LOG.info("Error pre-loading build process for project " + projectPath, e); - } - } - + else { + handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure("Disconnected from build process", null)); } } - }); - } - catch (Throwable e) { - final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId); - if (unregistered != null) { - unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e)); - unregistered.sessionTerminated(sessionId); + catch (Throwable e) { + execFailure = e; + } + finally { + myBuildsInProgress.remove(projectPath); + if (myMessageDispatcher.getAssociatedChannel(sessionId) == null) { + // either the connection has never been established (process not started or execution failed), or no messages were sent from the launched process. + // in this case the session cannot be unregistered by the message dispatcher + final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId); + if (unregistered != null) { + if (execFailure != null) { + unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(execFailure.getMessage(), execFailure)); + } + unregistered.sessionTerminated(sessionId); + } + } + + if (Registry.is("compiler.process.preload") && !project.isDisposed()) { + runCommand(new Runnable() { + public void run() { + try { + final Future, OSProcessHandler>> preloadResult = launchPreloadedBuildProcess(project, projectTaskQueue); + myPreloadedBuilds.put(projectPath, preloadResult); + } + catch (Exception e) { + LOG.info("Error pre-loading build process for project " + projectPath, e); + } + } + }); + } + + } } + }); + } + catch (Throwable e) { + final BuilderMessageHandler unregistered = myMessageDispatcher.unregisterBuildMessageHandler(sessionId); + if (unregistered != null) { + unregistered.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e)); + unregistered.sessionTerminated(sessionId); } } - }); + } + }); - return future; - } - catch (Throwable e) { - handler.handleFailure(sessionId, CmdlineProtoUtil.createFailure(e.getMessage(), e)); - handler.sessionTerminated(sessionId); - } - - return null; + return _future; } @NotNull @@ -798,37 +812,42 @@ public class BuildManager implements ApplicationComponent{ return "com.intellij.compiler.server.BuildManager"; } - private Pair, OSProcessHandler> launchPreloadedBuildProcess(final Project project) throws Exception { + private Future, OSProcessHandler>> launchPreloadedBuildProcess(final Project project, SequentialTaskExecutor projectTaskQueue) throws Exception { ensureListening(); - final RequestFuture future = new RequestFuture(new PreloadedProcessMessageHandler(project), UUID.randomUUID(), new RequestFuture.CancelAction() { - @Override - public void cancel(RequestFuture future) throws Exception { - myMessageDispatcher.cancelSession(future.getRequestID()); + // launching build process from projectTaskQueue ensures that no other build process for this project is currently running + return projectTaskQueue.submit(new Callable, OSProcessHandler>>() { + public Pair, OSProcessHandler> call() throws Exception { + final RequestFuture future = new RequestFuture(new PreloadedProcessMessageHandler(project), UUID.randomUUID(), new RequestFuture.CancelAction() { + @Override + public void cancel(RequestFuture future) throws Exception { + myMessageDispatcher.cancelSession(future.getRequestID()); + } + }); + try { + myMessageDispatcher.registerBuildMessageHandler(future, null); + final OSProcessHandler processHandler = launchBuildProcess(project, myListenPort, future.getRequestID(), true); + processHandler.addProcessListener(new ProcessAdapter() { + @Override + public void onTextAvailable(ProcessEvent event, Key outputType) { + if (ProcessOutputTypes.STDERR.equals(outputType)) { + final String text = event.getText(); + if (!StringUtil.isEmptyOrSpaces(text)) { + LOG.info("PRELOADED_BUILD_PROCESS: " + text); + } + } + } + }); + + processHandler.startNotify(); + return Pair.create(future, processHandler); + } + catch (ExecutionException e) { + myMessageDispatcher.unregisterBuildMessageHandler(future.getRequestID()); + throw e; + } } }); - myMessageDispatcher.registerBuildMessageHandler(future, null); - try { - final OSProcessHandler processHandler = launchBuildProcess(project, myListenPort, future.getRequestID(), true); - processHandler.addProcessListener(new ProcessAdapter() { - @Override - public void onTextAvailable(ProcessEvent event, Key outputType) { - if (ProcessOutputTypes.STDERR.equals(outputType)) { - final String text = event.getText(); - if (!StringUtil.isEmptyOrSpaces(text)) { - LOG.info("PRELOADED_BUILD_PROCESS: " + text); - } - } - } - }); - - processHandler.startNotify(); - return Pair.create(future, processHandler); - } - catch (ExecutionException e) { - myMessageDispatcher.unregisterBuildMessageHandler(future.getRequestID()); - throw e; - } } private OSProcessHandler launchBuildProcess(Project project, final int port, final UUID sessionId, boolean requestProjectPreload) throws ExecutionException { @@ -1300,7 +1319,7 @@ public class BuildManager implements ApplicationComponent{ @Override public void projectClosing(Project project) { cancelPreloadedBuilds(project); - for (BasicFuture future : cancelAutoMakeTasks(project)) { + for (TaskFuture future : cancelAutoMakeTasks(project)) { future.waitFor(500, TimeUnit.MILLISECONDS); } } @@ -1460,5 +1479,88 @@ public class BuildManager implements ApplicationComponent{ return "/"; } } - + + private static final class DelegateFuture implements TaskFuture { + @Nullable + private TaskFuture myDelegate; + private Boolean myRequestedCancelState = null; + + @NotNull + public synchronized TaskFuture getDelegate() { + TaskFuture delegate = myDelegate; + while (delegate == null) { + try { + wait(); + } + catch (InterruptedException ignored) { + } + delegate = myDelegate; + } + return delegate; + } + + public synchronized boolean setDelegate(@NotNull TaskFuture delegate) { + if (myDelegate == null) { + try { + myDelegate = delegate; + if (myRequestedCancelState != null) { + myDelegate.cancel(myRequestedCancelState); + } + } + finally { + notifyAll(); + } + return true; + } + return false; + } + + public synchronized boolean cancel(boolean mayInterruptIfRunning) { + final TaskFuture delegate = myDelegate; + if (delegate == null) { + myRequestedCancelState = mayInterruptIfRunning; + return true; + } + return delegate.cancel(mayInterruptIfRunning); + } + + public void waitFor() { + getDelegate().waitFor(); + } + + public boolean waitFor(long timeout, TimeUnit unit) { + return getDelegate().waitFor(timeout, unit); + } + + public boolean isCancelled() { + final TaskFuture delegate; + synchronized (this) { + delegate = myDelegate; + if (delegate == null) { + return myRequestedCancelState != null; + } + } + return delegate.isCancelled(); + } + + public boolean isDone() { + final TaskFuture delegate; + synchronized (this) { + delegate = myDelegate; + if (delegate == null) { + return false; + } + } + return delegate.isDone(); + } + + public T get() throws InterruptedException, java.util.concurrent.ExecutionException { + return getDelegate().get(); + } + + public T get(long timeout, TimeUnit unit) throws InterruptedException, java.util.concurrent.ExecutionException, TimeoutException { + return getDelegate().get(timeout, unit); + } + } + } diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/BasicFuture.java b/jps/jps-builders/src/org/jetbrains/jps/api/BasicFuture.java index 0717de1c61e7..514ec5efc8d4 100644 --- a/jps/jps-builders/src/org/jetbrains/jps/api/BasicFuture.java +++ b/jps/jps-builders/src/org/jetbrains/jps/api/BasicFuture.java @@ -15,14 +15,17 @@ */ package org.jetbrains.jps.api; -import java.util.concurrent.*; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Semaphore; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; /** * @author Eugene Zhuravlev * Date: 5/3/12 */ -public class BasicFuture implements Future { +public class BasicFuture implements TaskFuture { protected final Semaphore mySemaphore = new Semaphore(1); private final AtomicBoolean myDone = new AtomicBoolean(false); private final AtomicBoolean myCanceledState = new AtomicBoolean(false); diff --git a/jps/jps-builders/src/org/jetbrains/jps/api/TaskFuture.java b/jps/jps-builders/src/org/jetbrains/jps/api/TaskFuture.java new file mode 100644 index 000000000000..c09c8446422b --- /dev/null +++ b/jps/jps-builders/src/org/jetbrains/jps/api/TaskFuture.java @@ -0,0 +1,25 @@ +/* + * Copyright 2000-2014 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jetbrains.jps.api; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +public interface TaskFuture extends Future { + void waitFor(); + + boolean waitFor(long timeout, TimeUnit unit); +}