View | Details | Raw Unified | Return to bug 126121 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/core/internal/events/BuildManager.java (-29 / +87 lines)
Lines 13-18 Link Here
13
 *******************************************************************************/
13
 *******************************************************************************/
14
package org.eclipse.core.internal.events;
14
package org.eclipse.core.internal.events;
15
15
16
import org.eclipse.core.resources.IncrementalProjectBuilder;
17
16
import java.util.*;
18
import java.util.*;
17
import org.eclipse.core.internal.dtree.DeltaDataTree;
19
import org.eclipse.core.internal.dtree.DeltaDataTree;
18
import org.eclipse.core.internal.resources.*;
20
import org.eclipse.core.internal.resources.*;
Lines 132-150 Link Here
132
134
133
	private void basicBuild(int trigger, IncrementalProjectBuilder builder, Map args, MultiStatus status, IProgressMonitor monitor) {
135
	private void basicBuild(int trigger, IncrementalProjectBuilder builder, Map args, MultiStatus status, IProgressMonitor monitor) {
134
		try {
136
		try {
135
			currentBuilder = builder;
137
			InternalBuilder currentBuilder2 = builder;
136
			//clear any old requests to forget built state
138
			//clear any old requests to forget built state
137
			currentBuilder.clearForgetLastBuiltState();
139
			currentBuilder2.clearForgetLastBuiltState();
138
			// Figure out want kind of build is needed
140
			// Figure out want kind of build is needed
139
			boolean clean = trigger == IncrementalProjectBuilder.CLEAN_BUILD;
141
			boolean clean = trigger == IncrementalProjectBuilder.CLEAN_BUILD;
140
			currentLastBuiltTree = currentBuilder.getLastBuiltTree();
142
			currentLastBuiltTree = currentBuilder2.getLastBuiltTree();
141
			// If no tree is available we have to do a full build
143
			// If no tree is available we have to do a full build
142
			if (!clean && currentLastBuiltTree == null)
144
			if (!clean && currentLastBuiltTree == null)
143
				trigger = IncrementalProjectBuilder.FULL_BUILD;
145
				trigger = IncrementalProjectBuilder.FULL_BUILD;
144
			//don't build if this builder doesn't respond to the given trigger
146
			//don't build if this builder doesn't respond to the given trigger
145
			if (!builder.getCommand().isBuilding(trigger)) {
147
			if (!builder.getCommand().isBuilding(trigger)) {
146
				if (clean)
148
				if (clean)
147
					currentBuilder.setLastBuiltTree(null);
149
					currentBuilder2.setLastBuiltTree(null);
148
				return;
150
				return;
149
			}
151
			}
150
			// For incremental builds, grab a pointer to the current state before computing the delta
152
			// For incremental builds, grab a pointer to the current state before computing the delta
Lines 152-164 Link Here
152
			int depth = -1;
154
			int depth = -1;
153
			try {
155
			try {
154
				//short-circuit if none of the projects this builder cares about have changed.
156
				//short-circuit if none of the projects this builder cares about have changed.
155
				if (!needsBuild(currentBuilder, trigger)) {
157
				if (!needsBuild(currentBuilder2, trigger)) {
156
					//use up the progress allocated for this builder
158
					//use up the progress allocated for this builder
157
					monitor.beginTask("", 1); //$NON-NLS-1$
159
					monitor.beginTask("", 1); //$NON-NLS-1$
158
					monitor.done();
160
					monitor.done();
159
					return;
161
					return;
160
				}
162
				}
161
				String name = currentBuilder.getLabel();
163
				String name = currentBuilder2.getLabel();
162
				String message;
164
				String message;
163
				if (name != null)
165
				if (name != null)
164
					message = NLS.bind(Messages.events_invoking_2, name, builder.getProject().getFullPath());
166
					message = NLS.bind(Messages.events_invoking_2, name, builder.getProject().getFullPath());
Lines 169-191 Link Here
169
				//release workspace lock while calling builders
171
				//release workspace lock while calling builders
170
				depth = getWorkManager().beginUnprotected();
172
				depth = getWorkManager().beginUnprotected();
171
				//do the build
173
				//do the build
172
				SafeRunner.run(getSafeRunnable(trigger, args, status, monitor));
174
				SafeRunner.run(getSafeRunnable(trigger, args, status, monitor, currentBuilder2));
173
			} finally {
175
			} finally {
174
				if (depth >= 0)
176
				if (depth >= 0)
175
					getWorkManager().endUnprotected(depth);
177
					getWorkManager().endUnprotected(depth);
176
				// Be sure to clean up after ourselves.
178
				// Be sure to clean up after ourselves.
177
				if (clean || currentBuilder.wasForgetStateRequested()) {
179
				if (clean || currentBuilder2.wasForgetStateRequested()) {
178
					currentBuilder.setLastBuiltTree(null);
180
					currentBuilder2.setLastBuiltTree(null);
179
				} else {
181
				} else {
180
					// remember the current state as the last built state.
182
					// remember the current state as the last built state.
181
					ElementTree lastTree = workspace.getElementTree();
183
					ElementTree lastTree = workspace.getElementTree();
182
					lastTree.immutable();
184
					lastTree.immutable();
183
					currentBuilder.setLastBuiltTree(lastTree);
185
					currentBuilder2.setLastBuiltTree(lastTree);
184
				}
186
				}
185
				hookEndBuild(builder);
187
				hookEndBuild(builder);
186
			}
188
			}
187
		} finally {
189
		} finally {
188
			currentBuilder = null;
190
//			currentBuilder = null;
189
			currentTree = null;
191
			currentTree = null;
190
			currentLastBuiltTree = null;
192
			currentLastBuiltTree = null;
191
			currentDelta = null;
193
			currentDelta = null;
Lines 198-204 Link Here
198
				checkCanceled(trigger, monitor);
200
				checkCanceled(trigger, monitor);
199
				BuildCommand command = (BuildCommand) commands[i];
201
				BuildCommand command = (BuildCommand) commands[i];
200
				IProgressMonitor sub = Policy.subMonitorFor(monitor, 1);
202
				IProgressMonitor sub = Policy.subMonitorFor(monitor, 1);
201
				IncrementalProjectBuilder builder = getBuilder(project, command, i, status);
203
				IncrementalProjectBuilder builder;
204
				if(IncrementalProjectBuilder.PARALLEL_FULL_BUILD == trigger) {
205
					builder = getParallelBuilder(project, command, i, status);
206
				} else {
207
					builder = getBuilder(project, command, i, status);
208
				}
202
				if (builder != null)
209
				if (builder != null)
203
					basicBuild(trigger, builder, command.getArguments(false), status, sub);
210
					basicBuild(trigger, builder, command.getArguments(false), status, sub);
204
			}
211
			}
Lines 207-212 Link Here
207
		}
214
		}
208
	}
215
	}
209
216
217
	private IncrementalProjectBuilder getParallelBuilder(IProject project, BuildCommand command, int buildSpecIndex, MultiStatus status) throws CoreException {
218
		// always construct a new builder for parallel builds (think about pooling here)
219
		InternalBuilder result = initializeBuilder(command.getBuilderName(), project, buildSpecIndex, status);
220
		((BuildCommand) command).setBuilder((IncrementalProjectBuilder) result);
221
		result.setCommand(command);
222
		result.setProject(project);
223
		result.startupOnInitialize();
224
//		}
225
		if (!validateNature(result, command.getBuilderName())) {
226
			//skip this builder and null its last built tree because it is invalid
227
			//if the nature gets added or re-enabled a full build will be triggered
228
			result.setLastBuiltTree(null);
229
			return null;
230
		}
231
		return (IncrementalProjectBuilder) result;
232
	}
233
210
	/**
234
	/**
211
	 * Runs all builders on the given project. 
235
	 * Runs all builders on the given project. 
212
	 * @return A status indicating if the build succeeded or failed
236
	 * @return A status indicating if the build succeeded or failed
Lines 327-333 Link Here
327
	 * Runs all builders on all projects. 
351
	 * Runs all builders on all projects. 
328
	 * @return A status indicating if the build succeeded or failed
352
	 * @return A status indicating if the build succeeded or failed
329
	 */
353
	 */
330
	public IStatus build(int trigger, IProgressMonitor monitor) {
354
	public IStatus build(final int trigger, IProgressMonitor monitor) {
331
		monitor = Policy.monitorFor(monitor);
355
		monitor = Policy.monitorFor(monitor);
332
		try {
356
		try {
333
			monitor.beginTask(Messages.events_building_0, TOTAL_BUILD_WORK);
357
			monitor.beginTask(Messages.events_building_0, TOTAL_BUILD_WORK);
Lines 335-346 Link Here
335
				return Status.OK_STATUS;
359
				return Status.OK_STATUS;
336
			try {
360
			try {
337
				hookStartBuild(trigger);
361
				hookStartBuild(trigger);
338
				IProject[] ordered = workspace.getBuildOrder();
362
				final MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.BUILD_FAILED, Messages.events_errors, null);
339
				HashSet leftover = new HashSet(Arrays.asList(workspace.getRoot().getProjects(IContainer.INCLUDE_HIDDEN)));
363
					IProject[] ordered = workspace.getBuildOrder();
340
				leftover.removeAll(Arrays.asList(ordered));
364
					HashSet leftover = new HashSet(Arrays.asList(workspace.getRoot().getProjects(IContainer.INCLUDE_HIDDEN)));
341
				IProject[] unordered = (IProject[]) leftover.toArray(new IProject[leftover.size()]);
365
					leftover.removeAll(Arrays.asList(ordered));
342
				MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.BUILD_FAILED, Messages.events_errors, null);
366
					IProject[] unordered = (IProject[]) leftover.toArray(new IProject[leftover.size()]);
343
				basicBuildLoop(ordered, unordered, trigger, status, monitor);
367
					basicBuildLoop(ordered, unordered, trigger, status, monitor);
344
				return status;
368
				return status;
345
			} finally {
369
			} finally {
346
				hookEndBuild(trigger);
370
				hookEndBuild(trigger);
Lines 455-461 Link Here
455
	 * The outermost workspace operation has finished.  Do an autobuild if necessary.
479
	 * The outermost workspace operation has finished.  Do an autobuild if necessary.
456
	 */
480
	 */
457
	public void endTopLevel(boolean needsBuild) {
481
	public void endTopLevel(boolean needsBuild) {
458
		autoBuildJob.build(needsBuild);
482
//		autoBuildJob.build(needsBuild);
459
	}
483
	}
460
484
461
	/**
485
	/**
Lines 594-601 Link Here
594
618
595
	/**
619
	/**
596
	 * Returns the safe runnable instance for invoking a builder
620
	 * Returns the safe runnable instance for invoking a builder
621
	 * @param currentBuilder2 
597
	 */
622
	 */
598
	private ISafeRunnable getSafeRunnable(final int trigger, final Map args, final MultiStatus status, final IProgressMonitor monitor) {
623
	private ISafeRunnable getSafeRunnable(final int trigger, final Map args, final MultiStatus status, final IProgressMonitor monitor, final InternalBuilder currentBuilder2) {
599
		return new ISafeRunnable() {
624
		return new ISafeRunnable() {
600
			public void handleException(Throwable e) {
625
			public void handleException(Throwable e) {
601
				if (e instanceof OperationCanceledException) {
626
				if (e instanceof OperationCanceledException) {
Lines 603-620 Link Here
603
						Policy.debug("Build canceled"); //$NON-NLS-1$
628
						Policy.debug("Build canceled"); //$NON-NLS-1$
604
					//just discard built state when a builder cancels, to ensure
629
					//just discard built state when a builder cancels, to ensure
605
					//that it is called again on the very next build.
630
					//that it is called again on the very next build.
606
					currentBuilder.forgetLastBuiltState();
631
					currentBuilder2.forgetLastBuiltState();
607
					throw (OperationCanceledException) e;
632
					throw (OperationCanceledException) e;
608
				}
633
				}
609
				//ResourceStats.buildException(e);
634
				//ResourceStats.buildException(e);
610
				// don't log the exception....it is already being logged in SafeRunner#run
635
				// don't log the exception....it is already being logged in SafeRunner#run
611
636
612
				//add a generic message to the MultiStatus
637
				//add a generic message to the MultiStatus
613
				String builderName = currentBuilder.getLabel();
638
				String builderName = currentBuilder2.getLabel();
614
				if (builderName == null || builderName.length() == 0)
639
				if (builderName == null || builderName.length() == 0)
615
					builderName = currentBuilder.getClass().getName();
640
					builderName = currentBuilder2.getClass().getName();
616
				String pluginId = currentBuilder.getPluginId();
641
				String pluginId = currentBuilder2.getPluginId();
617
				String message = NLS.bind(Messages.events_builderError, builderName, currentBuilder.getProject().getName());
642
				String message = NLS.bind(Messages.events_builderError, builderName, currentBuilder2.getProject().getName());
618
				status.add(new Status(IStatus.ERROR, pluginId, IResourceStatus.BUILD_FAILED, message, e));
643
				status.add(new Status(IStatus.ERROR, pluginId, IResourceStatus.BUILD_FAILED, message, e));
619
644
620
				//add the exception status to the MultiStatus
645
				//add the exception status to the MultiStatus
Lines 626-637 Link Here
626
				IProject[] prereqs = null;
651
				IProject[] prereqs = null;
627
				//invoke the appropriate build method depending on the trigger
652
				//invoke the appropriate build method depending on the trigger
628
				if (trigger != IncrementalProjectBuilder.CLEAN_BUILD)
653
				if (trigger != IncrementalProjectBuilder.CLEAN_BUILD)
629
					prereqs = currentBuilder.build(trigger, args, monitor);
654
					prereqs = currentBuilder2.build(trigger, args, monitor);
630
				else
655
				else
631
					currentBuilder.clean(monitor);
656
					currentBuilder2.clean(monitor);
632
				if (prereqs == null)
657
				if (prereqs == null)
633
					prereqs = new IProject[0];
658
					prereqs = new IProject[0];
634
				currentBuilder.setInterestingProjects((IProject[]) prereqs.clone());
659
				currentBuilder2.setInterestingProjects((IProject[]) prereqs.clone());
635
			}
660
			}
636
		};
661
		};
637
	}
662
	}
Lines 1032-1035 Link Here
1032
			Policy.log(status);
1057
			Policy.log(status);
1033
		return workspace.getRoot();
1058
		return workspace.getRoot();
1034
	}
1059
	}
1060
1061
	public void buildParallel(IProgressMonitor subMonitorFor) {
1062
			IProject[] projects = workspace.getRoot().getProjects(IContainer.INCLUDE_HIDDEN);
1063
			DirectedGraphs<IProject> directedGraphs = new DirectedGraphs<IProject>();
1064
			for (IProject project : projects) {
1065
				directedGraphs.addNode(new Node<IProject>(project));
1066
			}
1067
			for (IProject project : projects) {
1068
				if (!project.isAccessible())
1069
					continue;
1070
				ProjectDescription desc = ((Project)project).internalGetDescription();
1071
				if (desc == null)
1072
					continue;
1073
				IProject[] refs = desc.getAllReferences(false);
1074
				Node<IProject> node = directedGraphs.getNodeWithContent(project);
1075
				for (IProject referencedProject : refs) {
1076
					Node<IProject> node2 = directedGraphs.getNodeWithContent(referencedProject);
1077
					node2.addOutgoingEdge(node);
1078
				}
1079
			}
1080
			ThreadPoolBuilder threadPoolBuilder = new ThreadPoolBuilder();
1081
			try {
1082
				final MultiStatus status = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.BUILD_FAILED, Messages.events_errors, null);
1083
				IBuildExecutor<IProject> buildExecutor = new IBuildExecutor<IProject>() {
1084
				public void executeBuild(IProject project) {
1085
					NullProgressMonitor progressMonitor = new NullProgressMonitor();
1086
					basicBuild(project, IncrementalProjectBuilder.PARALLEL_FULL_BUILD, status, progressMonitor);
1087
				}};
1088
				threadPoolBuilder.run(directedGraphs, buildExecutor);
1089
			} catch (InterruptedException e) {
1090
				e.printStackTrace();
1091
			}
1092
	}
1035
}
1093
}
(-)src/org/eclipse/core/internal/events/BuildRunnable.java (+31 lines)
Added Link Here
1
package org.eclipse.core.internal.events;
2
3
import java.util.ArrayList;
4
import java.util.List;
5
import java.util.concurrent.BlockingQueue;
6
7
public final class BuildRunnable<T> implements Runnable {
8
	
9
	private final Node<T> currentNode;
10
	private final BlockingQueue queue;
11
	private final IBuildExecutor<T> executor;
12
13
	protected BuildRunnable(Node<T> currentNode, BlockingQueue queue, IBuildExecutor<T> executor) {
14
		this.currentNode = currentNode;
15
		this.queue = queue;
16
		this.executor = executor;
17
	}
18
	
19
	public void run() {
20
			System.out.println("start compile " + currentNode.getContent()); //$NON-NLS-1$
21
			executor.executeBuild(currentNode.getContent());
22
			System.out.println("end compile " + currentNode.getContent()); //$NON-NLS-1$
23
			List<Node<T>> outgoingNodes = new ArrayList<Node<T>>(currentNode.getOutgoingEdges()); 
24
			currentNode.removeAllOutgoingEdges();
25
				for (Node<T> node : outgoingNodes) {
26
					if(node.getIncomingEdges().isEmpty()) {
27
						queue.add(node);
28
					}
29
				}
30
	}
31
}
(-)src/org/eclipse/core/internal/events/DirectedGraphs.java (+58 lines)
Added Link Here
1
package org.eclipse.core.internal.events;
2
3
import java.util.Collection;
4
import java.util.Collections;
5
import java.util.HashSet;
6
import java.util.LinkedHashSet;
7
import java.util.Set;
8
9
/**
10
 * A directed graph holds all nodes. Nodes need not be connected which is why a container object is required
11
 * 
12
 * @author jens
13
 *
14
 */
15
public class DirectedGraphs<T> {
16
	
17
	private Set<Node<T>> nodes;
18
19
	public DirectedGraphs() {
20
		nodes = Collections.synchronizedSet(new HashSet<Node<T>>());
21
	}
22
	
23
	public void addNode(Node<T> node) {
24
		nodes.add(node);
25
	}
26
27
	public void removeNode(Node<T> node) {
28
		nodes.remove(node);
29
	}
30
	
31
	public void addAll(Collection<Node<T>> nodesToBeAdded) {
32
		nodes.addAll(nodesToBeAdded);
33
	}
34
	
35
	public Node<T> getNodeWithContent(T content) {
36
		for (Node<T> node : nodes) {
37
			if(content.equals(node.getContent())) {
38
				return node;
39
			}
40
		}
41
		return null;
42
	}
43
	
44
	public synchronized Set<Node<T>> getRootNodes() {
45
		Set<Node<T>> set = new LinkedHashSet<Node<T>>();
46
		for (Node<T> node : nodes) {
47
			if(node.getIncomingEdges().isEmpty()) {
48
				set.add(node);
49
			}
50
		}
51
		return set;
52
	}
53
	
54
	public boolean isEmtpy() {
55
		return nodes.isEmpty();
56
	}
57
58
}
(-)src/org/eclipse/core/internal/events/IBuildExecutor.java (+21 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2011 IBM Corporation and others.
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
6
 * http://www.eclipse.org/legal/epl-v10.html
7
 * 
8
 * Contributors:
9
 *     IBM Corporation - initial API and implementation
10
 *******************************************************************************/
11
package org.eclipse.core.internal.events;
12
13
14
/**
15
 * 
16
 */
17
public interface IBuildExecutor<T> {
18
	
19
	public void executeBuild(T content);
20
21
}
(-)src/org/eclipse/core/internal/events/Node.java (+129 lines)
Added Link Here
1
package org.eclipse.core.internal.events;
2
3
import java.text.MessageFormat;
4
5
import java.util.Collections;
6
import java.util.Iterator;
7
import java.util.LinkedHashSet;
8
import java.util.Set;
9
10
/**
11
 * A simple node object having references to other node objects 
12
 *
13
 * @param <T>
14
 */
15
public class Node<T> {
16
	
17
	private Set<Node<T>> incomingEdges;
18
19
	private Set<Node<T>> outgoingEdges;
20
	
21
	private T content;
22
	
23
	public Node(T content) {
24
		this.content = content;
25
		incomingEdges = Collections.synchronizedSet(new LinkedHashSet<Node<T>>()); 
26
		outgoingEdges = Collections.synchronizedSet(new LinkedHashSet<Node<T>>()); 
27
	}
28
	
29
	public T getContent() {
30
		return content;
31
	}
32
33
	public void setContent(T content) {
34
		this.content = content;
35
	}
36
37
	public synchronized Set<Node<T>> getIncomingEdges() {
38
		return incomingEdges;
39
	}
40
41
	public synchronized Set<Node<T>> getOutgoingEdges() {
42
		return outgoingEdges;
43
	}
44
45
	public synchronized void addIncomingEdge(Node<T> node) {
46
		if(!incomingEdges.contains(node)) {
47
			incomingEdges.add(node);
48
			node.addOutgoingEdge(this);
49
		}
50
	}
51
52
	public synchronized void addOutgoingEdge(Node<T> node) {
53
		if(!outgoingEdges.contains(node)) {
54
			outgoingEdges.add(node);
55
			node.addIncomingEdge(this);
56
		}
57
	}
58
	
59
	public synchronized void removeOutgoingEdge(Node<T> node) {
60
		if(outgoingEdges.contains(node)) {
61
			outgoingEdges.remove(node);
62
			node.removeIncomingEdge(this);
63
		}
64
	}
65
	
66
	public synchronized void removeIncomingEdge(Node<T> node) {
67
		if(incomingEdges.contains(node)) {
68
			incomingEdges.remove(node);
69
			node.removeOutgoingEdge(this);
70
		}
71
	}
72
73
	public synchronized void removeAllOutgoingEdges() {
74
		for (Iterator<Node<T>> iterator = outgoingEdges.iterator(); iterator.hasNext();) {
75
			Node<T> node = iterator.next();
76
			node.internalRemoveIncomingEdge(this);
77
			iterator.remove();
78
		}
79
	}
80
81
	public synchronized void removeAllIncomingEdges() {
82
		for (Iterator<Node<T>> iterator = incomingEdges.iterator(); iterator.hasNext();) {
83
			Node<T> node = iterator.next();
84
			node.internalRemoveOutgoingEdge(this);
85
			iterator.remove();
86
		}
87
	}
88
89
	synchronized void internalRemoveOutgoingEdge(Node<T> node) {
90
		outgoingEdges.remove(node);
91
	}
92
93
	synchronized void internalRemoveIncomingEdge(Node<T> node) {
94
		incomingEdges.remove(node);
95
	}
96
97
	@Override
98
	public int hashCode() {
99
		final int prime = 31;
100
		int result = 1;
101
		result = prime * result + ((content == null) ? 0 : content.hashCode());
102
		return result;
103
	}
104
105
	@Override
106
	public boolean equals(Object obj) {
107
		if (this == obj)
108
			return true;
109
		if (obj == null)
110
			return false;
111
		if (getClass() != obj.getClass())
112
			return false;
113
		Node other = (Node) obj;
114
		if (content == null) {
115
			if (other.content != null)
116
				return false;
117
		} else if (!content.equals(other.content))
118
			return false;
119
		return true;
120
	}
121
122
	@Override
123
	public String toString() {
124
		return MessageFormat.format("Node [content={0}]", content); //$NON-NLS-1$
125
	}
126
127
	
128
	
129
}
(-)src/org/eclipse/core/internal/events/ThreadPoolBuilder.java (+31 lines)
Added Link Here
1
package org.eclipse.core.internal.events;
2
3
import java.util.concurrent.ArrayBlockingQueue;
4
import java.util.concurrent.BlockingQueue;
5
import java.util.concurrent.ExecutorService;
6
import java.util.concurrent.Executors;
7
8
public class ThreadPoolBuilder {
9
	
10
	private ExecutorService threadPool;
11
	
12
	private BlockingQueue<Node<?>> queue;
13
14
	public ThreadPoolBuilder() {
15
		threadPool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 2);
16
		queue = new ArrayBlockingQueue<Node<?>>(100);
17
	}
18
	
19
	public <T> void run(DirectedGraphs<T> directedGraphs, IBuildExecutor<T> runnable) throws InterruptedException {
20
		queue.addAll(directedGraphs.getRootNodes());
21
			while (!threadPool.isTerminated()) {
22
				if(directedGraphs.isEmtpy()) {
23
					threadPool.shutdown();
24
				} else {
25
					Node<?>nodeToCompile = queue.take();
26
					directedGraphs.removeNode((Node<T>) nodeToCompile);
27
					threadPool.execute(new BuildRunnable(nodeToCompile, queue, runnable));
28
				}
29
		}
30
	}
31
}

Return to bug 126121