blob: ad046c0fd64ce44db7150f1ecd78092a412c66a4 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* 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 = 12;
public ProcessTaskManager(Compiler compiler) {
this.compiler = compiler;
this.unitIndex = 0;
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(new Integer(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(new Integer(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;
}
public void run() {
while (this.processingThread != null) {
this.unitToProcess = null;
int index = -1;
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++;
}
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 {
if (this.unitToProcess != null)
this.unitToProcess.cleanUp();
}
addNextUnit(this.unitToProcess);
} catch (Error e) {
synchronized (this) {
this.processingThread = null;
this.caughtException = e;
}
return;
} catch (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
}
}
}