org.eclipse.jdt.internal.compiler.ProcessTaskManager Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ecj Show documentation
Show all versions of ecj Show documentation
Eclipse Compiler for Java(TM)
/*******************************************************************************
* Copyright (c) 2008, 2016 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.compiler;
import org.eclipse.jdt.internal.compiler.ast.CompilationUnitDeclaration;
import org.eclipse.jdt.internal.compiler.util.Messages;
public class ProcessTaskManager implements Runnable {
Compiler compiler;
private int unitIndex;
private Thread processingThread;
CompilationUnitDeclaration unitToProcess;
private Throwable caughtException;
// queue
volatile int currentIndex, availableIndex, size, sleepCount;
CompilationUnitDeclaration[] units;
public static final int PROCESSED_QUEUE_SIZE = 100;
public ProcessTaskManager(Compiler compiler, int startingIndex) {
this.compiler = compiler;
this.unitIndex = startingIndex;
this.currentIndex = 0;
this.availableIndex = 0;
this.size = PROCESSED_QUEUE_SIZE;
this.sleepCount = 0; // 0 is no one, +1 is the processing thread & -1 is the writing/main thread
this.units = new CompilationUnitDeclaration[this.size];
synchronized (this) {
this.processingThread = new Thread(this, "Compiler Processing Task"); //$NON-NLS-1$
this.processingThread.setDaemon(true);
this.processingThread.start();
}
}
// add unit to the queue - wait if no space is available
private synchronized void addNextUnit(CompilationUnitDeclaration newElement) {
while (this.units[this.availableIndex] != null) {
//System.out.print('a');
//if (this.sleepCount < 0) throw new IllegalStateException(Integer.valueOf(this.sleepCount).toString());
this.sleepCount = 1;
try {
wait(250);
} catch (InterruptedException ignore) {
// ignore
}
this.sleepCount = 0;
}
this.units[this.availableIndex++] = newElement;
if (this.availableIndex >= this.size)
this.availableIndex = 0;
if (this.sleepCount <= -1)
notify(); // wake up writing thread to accept next unit - could be the last one - must avoid deadlock
}
public CompilationUnitDeclaration removeNextUnit() throws Error {
CompilationUnitDeclaration next = null;
boolean yield = false;
synchronized (this) {
next = this.units[this.currentIndex];
if (next == null || this.caughtException != null) {
do {
if (this.processingThread == null) {
if (this.caughtException != null) {
// rethrow the caught exception from the processingThread in the main compiler thread
if (this.caughtException instanceof Error)
throw (Error) this.caughtException;
throw (RuntimeException) this.caughtException;
}
return null;
}
//System.out.print('r');
//if (this.sleepCount > 0) throw new IllegalStateException(Integer.valueOf(this.sleepCount).toString());
this.sleepCount = -1;
try {
wait(100);
} catch (InterruptedException ignore) {
// ignore
}
this.sleepCount = 0;
next = this.units[this.currentIndex];
} while (next == null);
}
this.units[this.currentIndex++] = null;
if (this.currentIndex >= this.size)
this.currentIndex = 0;
if (this.sleepCount >= 1 && ++this.sleepCount > 4) {
notify(); // wake up processing thread to add next unit but only after removing some elements first
yield = this.sleepCount > 8;
}
}
if (yield)
Thread.yield();
return next;
}
@Override
public void run() {
boolean noAnnotations = this.compiler.annotationProcessorManager == null;
while (this.processingThread != null) {
this.unitToProcess = null;
int index = -1;
boolean cleanup = noAnnotations || this.compiler.shouldCleanup(this.unitIndex);
try {
synchronized (this) {
if (this.processingThread == null) return;
this.unitToProcess = this.compiler.getUnitToProcess(this.unitIndex);
if (this.unitToProcess == null) {
this.processingThread = null;
return;
}
index = this.unitIndex++;
if (this.unitToProcess.compilationResult.hasBeenAccepted)
continue;
}
try {
this.compiler.reportProgress(Messages.bind(Messages.compilation_processing, new String(this.unitToProcess.getFileName())));
if (this.compiler.options.verbose)
this.compiler.out.println(
Messages.bind(Messages.compilation_process,
new String[] {
String.valueOf(index + 1),
String.valueOf(this.compiler.totalUnits),
new String(this.unitToProcess.getFileName())
}));
this.compiler.process(this.unitToProcess, index);
} finally {
// cleanup compilation unit result, but only if not annotation processed.
if (this.unitToProcess != null && cleanup)
this.unitToProcess.cleanUp();
}
addNextUnit(this.unitToProcess);
} catch (Error | RuntimeException e) {
synchronized (this) {
this.processingThread = null;
this.caughtException = e;
}
return;
}
}
}
public void shutdown() {
try {
Thread t = null;
synchronized (this) {
if (this.processingThread != null) {
t = this.processingThread;
this.processingThread = null;
notifyAll();
}
}
if (t != null)
t.join(250); // do not wait forever
} catch (InterruptedException ignored) {
// ignore
}
}
}