/*******************************************************************************
* Copyright (c) 2006, 2007 Intel 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:
* Intel Corporation - Initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.managedbuilder.internal.buildmodel;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.cdt.managedbuilder.buildmodel.IBuildCommand;
import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager;
import org.eclipse.cdt.managedbuilder.envvar.IBuildEnvironmentVariable;
import org.eclipse.cdt.managedbuilder.envvar.IEnvironmentVariableProvider;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
/**
* This class implements process pool management for internal builder
*
* NOTE: This class is subject to change and discuss,
* and is currently available in experimental mode only
*/
public class BuildProcessManager {
protected OutputStream out;
protected OutputStream err;
protected boolean show;
protected ProcessLauncher[] processes;
protected int maxProcesses;
// Number of CPUs is not dependent of object instance.
// But user can change UI settings for processes number.
// So we cannot set procNumber directly to maxProcesses.
static int procNumber = 0;
/**
* Initializes process manager
*
* @param _out Output stream
* @param _err Error output stream
* @param _show If true, print command line before launching
*/
public BuildProcessManager(OutputStream _out, OutputStream _err, boolean _show, int _procNumber) {
out = _out;
err = _err;
show = _show;
maxProcesses = _procNumber;
processes = new ProcessLauncher[maxProcesses];
}
/**
* Returns maximum number of processes
*/
public int getMaxProcesses() {
return maxProcesses;
}
/**
* Performs an attempt to launch new process. Returns BuildProcessLauncher
* if it was successfully launched, null if there is no room for it yet in
* the process pool.
*
* @param cmd Command to launch
* @param cwd Command working directory
* @param monitor Progress monitor for this task
*/
public ProcessLauncher launchProcess(IBuildCommand cmd, IPath cwd, IProgressMonitor monitor) {
if (hasEmpty()) {
int i = 0;
for (; i < maxProcesses; i++) {
if (processes[i] == null || processes[i].queryState() == ProcessLauncher.STATE_DONE) {
break;
}
}
if (i < maxProcesses) {
processes[i] = new ProcessLauncher(cmd.getCommand(), cmd.getArgs(), mapToStringArray(cmd.getEnvironment()), cwd, out, err, monitor, show);
processes[i].launch();
return processes[i];
}
}
return null;
}
/**
* Checks states of all currently running processes. If it finds
* one with state other than STATE_DONE or STATE_RUNNING, it is
* returned as a result. Otherwise this method returns null.
*/
public ProcessLauncher queryStates() {
ProcessLauncher result = null;
for (int i = 0; i < maxProcesses; i++) {
if (processes[i] != null) {
int state = processes[i].queryState();
if (state != ProcessLauncher.STATE_RUNNING) {
if (state != ProcessLauncher.STATE_DONE && result == null)
result = processes[i];
}
}
}
return result;
}
/**
* Checks states of all currently running processes.
*/
public boolean hasEmpty() {
for (int i = 0; i < maxProcesses; i++) {
if (processes[i] == null)
return true;
else {
if (processes[i].queryState() != ProcessLauncher.STATE_RUNNING)
return true;
}
}
return false;
}
/**
* Converts map to strings array
*/
protected String[] mapToStringArray(Map<String, String> map){
if(map == null)
return null;
List<String> list = new ArrayList<String>();
Set<Entry<String, String>> entrySet = map.entrySet();
for (Entry<String, String> entry : entrySet) {
list.add(entry.getKey() + '=' + entry.getValue());
}
return list.toArray(new String[list.size()]);
}
/**
* @return Number of processors detected
*/
static public int checkCPUNumber() {
if (procNumber > 0) return procNumber;
procNumber = 1;
int x = 0;
String os = System.getProperty("os.name"); //$NON-NLS-1$
if (os != null) {
if (os.startsWith("Win")) { //$NON-NLS-1$
IEnvironmentVariableProvider evp = ManagedBuildManager.getEnvironmentVariableProvider();
if (evp != null) {
IBuildEnvironmentVariable var = evp.getVariable("NUMBER_OF_PROCESSORS", null, false, false); //$NON-NLS-1$
if (var != null) {
try {
x = new Integer(var.getValue()).intValue();
if (x > 0) { procNumber = x; }
} catch (NumberFormatException e) {} // fallthrough and return default
}
}
} else { // linux
String p = "/proc/cpuinfo"; //$NON-NLS-1$
try {
BufferedReader r = new BufferedReader(new InputStreamReader(new FileInputStream(p)));
String s;
while ((s = r.readLine() ) != null )
{ if (s.startsWith("processor\t:")) x++; } //$NON-NLS-1$
r.close();
if (x > 0) { procNumber = x; }
}
catch (IOException e) {} // fallthrough and return default
}
}
if(DbgUtil.DEBUG)
DbgUtil.trace("Number of processors detected: " + procNumber); //$NON-NLS-1$
return procNumber;
}
}