# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: src/org/netbeans/modules/cnd/actions/ShellRunAction.java *** C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\src\org\netbeans\modules\cnd\actions\ShellRunAction.java Base (1.2.2.1) --- C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\src\org\netbeans\modules\cnd\actions\ShellRunAction.java Locally Modified (Based On 1.2.2.1) *************** *** 105,111 **** // Windows: The command is usually of the from "/bin/sh", but this // doesn't work here, so extract the 'sh' part and use that instead. // FIXUP: This is not entirely correct though. ! if (Utilities.isWindows() && shellCommand.length() > 0) { int i = shellCommand.lastIndexOf("/"); // UNIX PATH if (i >= 0) { shellCommand = shellCommand.substring(i+1); --- 105,111 ---- // Windows: The command is usually of the from "/bin/sh", but this // doesn't work here, so extract the 'sh' part and use that instead. // FIXUP: This is not entirely correct though. ! if (false && Utilities.isWindows() && shellCommand.length() > 0) { int i = shellCommand.lastIndexOf("/"); // UNIX PATH if (i >= 0) { shellCommand = shellCommand.substring(i+1); Index: makeproject/src/org/netbeans/modules/cnd/makeproject/api/DefaultProjectActionHandler.java *** C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\makeproject\src\org\netbeans\modules\cnd\makeproject\api\DefaultProjectActionHandler.java Base (1.2.2.7) --- C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\makeproject\src\org\netbeans\modules\cnd\makeproject\api\DefaultProjectActionHandler.java Locally Modified (Based On 1.2.2.7) *************** *** 35,40 **** --- 35,41 ---- import org.openide.NotifyDescriptor; import org.openide.filesystems.FileObject; import org.openide.util.NbBundle; + import org.openide.util.RequestProcessor; import org.openide.windows.IOProvider; import org.openide.windows.InputOutput; *************** *** 65,77 **** public void actionPerformed(ActionEvent actionEvent) { ProjectActionEvent[] paes = (ProjectActionEvent[])actionEvent.getSource(); ! new HandleEvents(paes).go(); } private static InputOutput mainTab = null; private static HandleEvents mainTabHandler = null; ! class HandleEvents implements ExecutionListener { private InputOutput reuseTab = null; private ProjectActionEvent[] paes; int currentAction = 0; --- 66,79 ---- public void actionPerformed(ActionEvent actionEvent) { ProjectActionEvent[] paes = (ProjectActionEvent[])actionEvent.getSource(); ! // #16720 part 2: don't do this in the event thread... ! RequestProcessor.getDefault().post(new HandleEvents(paes)); } private static InputOutput mainTab = null; private static HandleEvents mainTabHandler = null; ! class HandleEvents implements ExecutionListener, Runnable { private InputOutput reuseTab = null; private ProjectActionEvent[] paes; int currentAction = 0; *************** *** 280,286 **** --- 282,292 ---- } return true; } + + public void run() { + go(); } + } /** Look up i18n strings here */ private static String getString(String s) { Index: makeproject/src/org/netbeans/modules/cnd/makeproject/MakeActionProvider.java *** C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\makeproject\src\org\netbeans\modules\cnd\makeproject\MakeActionProvider.java Base (1.2.2.8) --- C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\makeproject\src\org\netbeans\modules\cnd\makeproject\MakeActionProvider.java Locally Modified (Based On 1.2.2.8) *************** *** 350,356 **** path = makeArtifact.getWorkingDirectory() + "/" + path; // NOI18N path = FilePathAdaptor.naturalize(path); path = IpeUtils.toRelativePath(conf.getProfile().getRunDirectory(), path); ! path = FilePathAdaptor.naturalize(path); } } else { // Always absolute --- 350,357 ---- path = makeArtifact.getWorkingDirectory() + "/" + path; // NOI18N path = FilePathAdaptor.naturalize(path); path = IpeUtils.toRelativePath(conf.getProfile().getRunDirectory(), path); ! // IZ#75120 use unix path now as all is done through shell script ! path = FilePathAdaptor.normalize(path); } } else { // Always absolute Index: src/org/netbeans/modules/cnd/execution/NativeExecution.java *** C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\src\org\netbeans\modules\cnd\execution\NativeExecution.java Base (1.2.2.3) --- C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\src\org\netbeans\modules\cnd\execution\NativeExecution.java Locally Modified (Based On 1.2.2.3) *************** *** 79,85 **** String arguments, String[] envp, PrintWriter out, ! Reader in) throws IOException, InterruptedException { String commandInterpreter; String commandLine; int rc = -1; --- 79,85 ---- String arguments, String[] envp, PrintWriter out, ! Reader in, Object processKey) throws IOException, InterruptedException { String commandInterpreter; String commandLine; int rc = -1; *************** *** 110,116 **** envp = (String[] ) nueEnvp.toArray(new String[0]); executionProcess = desc.exec(null, envp, true, runDirFile); ! outputReaderThread = new OutputReaderThread(executionProcess.getErrorStream(), out); outputReaderThread.start(); if (in != null) { inputReaderThread = new InputReaderThread(executionProcess.getOutputStream(), in); --- 110,116 ---- envp = (String[] ) nueEnvp.toArray(new String[0]); executionProcess = desc.exec(null, envp, true, runDirFile); ! outputReaderThread = new OutputReaderThread(executionProcess.getErrorStream(), out, processKey); outputReaderThread.start(); if (in != null) { inputReaderThread = new InputReaderThread(executionProcess.getOutputStream(), in); *************** *** 120,143 **** } try { rc = executionProcess.waitFor(); - } catch (InterruptedException ex) { - // We've interupted the process. Kill it and wait for the process to finish. - executionProcess.destroy(); - while (rc < 0) { try { - rc = executionProcess.waitFor(); - } catch (InterruptedException ex1) { - } - } - } - try { outputReaderThread.join(); // wait for the thread to complete } catch (InterruptedException ex2) { // On Windows join() throws InterruptedException if process was terminated/interrupted } return rc; --- 120,137 ---- } try { rc = executionProcess.waitFor(); try { outputReaderThread.join(); // wait for the thread to complete } catch (InterruptedException ex2) { // On Windows join() throws InterruptedException if process was terminated/interrupted } + } catch (InterruptedException ex) { + if (ProcessManager.TRACE) ProcessManager.log("InterruptedException " + executable + " " + arguments); + // kill external process + ProcessManager.getDefault().killProcess(processKey); + // We've interupted the process. Destroy it. + ProcessManager.getDefault().destroyProcess(executionProcess); + } return rc; } *************** *** 162,174 **** private Reader err; private Writer output; private Reader tmp_in; ! public OutputReaderThread(InputStream err, Writer output) { this.err = new InputStreamReader(err); this.output = output; setName("OutputReaderThread"); } --- 159,170 ---- private Reader err; private Writer output; private Reader tmp_in; + private Object processKey; ! public OutputReaderThread(InputStream err, Writer output, Object processKey) { this.err = new InputStreamReader(err); this.output = output; + this.processKey = processKey; setName("OutputReaderThread"); } *************** *** 179,185 **** public void run() { try { int read; ! while ((read = err.read()) != (-1)) { output.write((char) read); output.flush(); --- 178,184 ---- public void run() { try { int read; ! readPID(processKey, err, output); while ((read = err.read()) != (-1)) { output.write((char) read); output.flush(); *************** *** 229,235 **** } } ! /** * Find the script stdouterr.sh somewhere in the installation tree. It is needed to merge stdout and stderr * for for instance makefile execution. --- 228,250 ---- } } ! private static void readPID(Object processKey, Reader reader, Writer output) throws IOException { ! // read process ID ! int pID = 0; ! int read = 0; ! while ((read = reader.read()) != (-1)) { ! assert (read != '\r') : "only \\n as delimeter in scripts"; ! if (read == '\n') { ! break; ! } ! pID = pID * 10 + (read - '0'); ! if (ProcessManager.TRACE) { ! output.write((char) read); ! output.flush(); ! } ! } ! ProcessManager.getDefault().registerProcess(processKey, pID); ! } /** * Find the script stdouterr.sh somewhere in the installation tree. It is needed to merge stdout and stderr * for for instance makefile execution. Index: release/bin/stdouterr.sh *** C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\release\bin\stdouterr.sh Base (1.2.2.1) --- C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\release\bin\stdouterr.sh Locally Modified (Based On 1.2.2.1) *************** *** 19,24 **** --- 19,28 ---- if [ -n "$1" ] then + # IZ#75120 + # $$ is used to inform caller about PID of this process. + # caller should read the first line of ouput to catch this number + echo $$ >&2 + # now just execute arguments and redirect stdout into stderr exec "$@" >&2 fi Index: release/bin/stdouterr.bat *** C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\release\bin\stdouterr.bat Base (1.2.2.1) --- C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\release\bin\stdouterr.bat Locally Modified (Based On 1.2.2.1) *************** *** 19,23 **** setlocal if ""%1"" == """" goto end ! %* >&2 :end --- 19,29 ---- setlocal if ""%1"" == """" goto end ! REM IZ#75120 we want to call shell script from this batch file ! REM to have the same behavior in any OS ! set SH_SCRIPT="%~dp0stdouterr.sh" ! REM @echo %SH_SCRIPT% ! ! REM CND expects cygwin to be installed, so "sh" should be valid ! sh %SH_SCRIPT% %* >&2 :end Index: src/org/netbeans/modules/cnd/execution/ProcessManager.java *** C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\src\org\netbeans\modules\cnd\execution\ProcessManager.java No Base Revision --- C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\src\org\netbeans\modules\cnd\execution\ProcessManager.java Locally New *************** *** 1,0 **** --- 1,161 ---- + /* + * The contents of this file are subject to the terms of the Common Development + * and Distribution License (the License). You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at http://www.netbeans.org/cddl.html + * or http://www.netbeans.org/cddl.txt. + + * When distributing Covered Code, include this CDDL Header Notice in each file + * and include the License file at http://www.netbeans.org/cddl.txt. + * If applicable, add the following below the CDDL Header, with the fields + * enclosed by brackets [] replaced by your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + */ + + package org.netbeans.modules.cnd.execution; + + import java.io.BufferedOutputStream; + import java.io.File; + import java.io.FileOutputStream; + import java.io.IOException; + import java.util.Collections; + import java.util.Date; + import java.util.HashMap; + import java.util.Map; + import org.openide.execution.NbProcessDescriptor; + import org.openide.util.Utilities; + + /** + * + * @author Vladimir Voskresensky + */ + public class ProcessManager { + private static Map processes = Collections.synchronizedMap(new HashMap()); + + private static ProcessManager instance = null; + /** Creates a new instance of ProcessManager */ + private ProcessManager() { + } + + public synchronized static ProcessManager getDefault() { + if (instance == null) { + instance = new ProcessManager(); + } + return instance; + } + + public void registerProcess(Object key, int pID) { + if (pID != 0) { + if (TRACE) ProcessManager.log("register: " + key + " with pID = " + pID); + processes.put(key, new Integer(pID)); + } + } + + public void unregisterProcess(Object key) { + Integer pID = (Integer) processes.remove(key); + if (TRACE) ProcessManager.log("unregister: " + key + " with pID = " + pID); + } + + public void killProcess(Object key) { + if (TRACE) ProcessManager.log("trying to kill " + key); + Integer pID = (Integer) processes.remove(key); + if (pID != null) { + killProcess(pID.intValue()); + } + } + + private static void killProcess(int pID) { + if (pID == 0) { + return; + } + String cmdline = getKillCommand(pID); + Process process = null; + try { + if (TRACE) ProcessManager.log("killing: " + cmdline); + String commandInterpreter = NativeExecution.getStdOutErrFile().getPath(); + NbProcessDescriptor desc = new NbProcessDescriptor(commandInterpreter, cmdline); + process = desc.exec(); + //process = Runtime.getRuntime().exec(cmdline); + if (process != null) { + try { + waitFinished(process); + } catch (InterruptedException ex) { + destroyProcess(process); + } + } + } catch (IOException ex) { + destroyProcess(process); + } + } + + private static String getKillCommand(int pID) { + String cmdline = null; + // TODO: need correct kill utility + // "tskill pID" for XP Home and XP Pro + // "taskkill /PID pID" for XP Pro + // "kill pID" for others + if (Utilities.isWindows()) { + if (Utilities.getOperatingSystem() == Utilities.OS_WINNT) { + cmdline = "kill " + pID; + } else { + cmdline = "kill " + pID; + } + } else { + cmdline = "kill " + pID; + } + return cmdline; + } + + private static final int TIMEOUT = 10000; + public static void destroyProcess(Process process) { + if (process == null) { + return; + } + process.destroy(); + try { + waitFinished(process); + } catch (InterruptedException ex) { + //skip + } + } + + private static void waitFinished(Process process) throws InterruptedException { + int rc = -1; + int timeout = 500; + // let process to exec correctly, wait a second + Thread.sleep(timeout); + while (rc < 0 && timeout < TIMEOUT) { + rc = process.waitFor(); + if (rc < 0) { + Thread.sleep(100); + timeout += 100; + } + } + } + + public static final boolean TRACE = false; + private static final String LOG_PATH = System.getProperty("java.io.tmpdir") + File.separator + "ProcessManager.log"; + public synchronized static void log(String msg) { + try { + File logFile = new File(LOG_PATH); + if (!logFile.exists()) { + logFile.getParentFile().mkdirs(); + logFile.createNewFile(); + } + Date date = new Date(); + FileOutputStream os = new FileOutputStream(logFile, true); + BufferedOutputStream bos = new BufferedOutputStream(os); + msg = date.toString() + msg + "\n"; + bos.write(msg.getBytes()); + bos.flush(); + bos.close(); + } catch (IOException ex) { + // skip it + } + } + } Index: src/org/netbeans/modules/cnd/api/execution/NativeExecutor.java *** C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\src\org\netbeans\modules\cnd\api\execution\NativeExecutor.java Base (1.2.2.1) --- C:\Documents and Settings\BOBA\My Documents\My Projects\cnd-cvs\cnd\src\org\netbeans\modules\cnd\api\execution\NativeExecutor.java Locally Modified (Based On 1.2.2.1) *************** *** 27,32 **** --- 27,33 ---- import java.util.ResourceBundle; import org.netbeans.modules.cnd.execution.NativeExecution; import org.netbeans.modules.cnd.execution.OutputWindowWriter; + import org.netbeans.modules.cnd.execution.ProcessManager; import org.openide.ErrorManager; import org.openide.awt.StatusDisplayer; import org.openide.execution.ExecutionEngine; *************** *** 144,150 **** out = new PrintWriter(new OutputWindowWriter(io.getOut(), FileUtil.toFileObject(runDirFile), parseOutputForErrors)); executionStarted(); int rc = 0; ! try { // Execute the selected command rc = new NativeExecution().executeCommand( --- 145,151 ---- out = new PrintWriter(new OutputWindowWriter(io.getOut(), FileUtil.toFileObject(runDirFile), parseOutputForErrors)); executionStarted(); int rc = 0; ! Thread thisProcess = Thread.currentThread(); try { // Execute the selected command rc = new NativeExecution().executeCommand( *************** *** 153,164 **** arguments, envp, out, ! showInput ? io.getIn() : null); } catch (ThreadDeath td) { StatusDisplayer.getDefault().setStatusText("FAILED"); // FIXUP executionFinished(-1); out.close(); ! throw td; } catch (Throwable t) { StatusDisplayer.getDefault().setStatusText("FAILED"); // FIXUP ErrorManager.getDefault().notify(t); --- 154,170 ---- arguments, envp, out, ! showInput ? io.getIn() : null, thisProcess); } catch (ThreadDeath td) { + if (ProcessManager.TRACE) ProcessManager.log("ThreadDeath " + executable + " " + arguments); + if (thisProcess != null && thisProcess.isAlive()) { + thisProcess.interrupt(); + } + ProcessManager.getDefault().killProcess(thisProcess); StatusDisplayer.getDefault().setStatusText("FAILED"); // FIXUP executionFinished(-1); out.close(); ! // throw td; } catch (Throwable t) { StatusDisplayer.getDefault().setStatusText("FAILED"); // FIXUP ErrorManager.getDefault().notify(t); *************** *** 172,177 **** --- 178,184 ---- ex.printStackTrace(); } } + ProcessManager.getDefault().unregisterProcess(thisProcess); } executionFinished(rc); out.close();