diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialConnectWorker.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialConnectWorker.java index 02cb974f8d7..0685f00a4cf 100644 --- a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialConnectWorker.java +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialConnectWorker.java @@ -14,6 +14,7 @@ * Michael Scharf (Wind River) - extracted from TerminalControl * Martin Oberhuber (Wind River) - fixed copyright headers and beautified * Martin Oberhuber (Wind River) - [207158] improve error message when port not available + * Martin Oberhuber (Wind River) - [208029] COM port not released after quick disconnect/reconnect *******************************************************************************/ package org.eclipse.tm.internal.terminal.serial; @@ -26,6 +27,7 @@ import java.util.Arrays; import java.util.Enumeration; import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; public class SerialConnectWorker extends Thread { @@ -41,7 +43,6 @@ public class SerialConnectWorker extends Thread { super(); fControl = control; fConn = conn; - fControl.setState(TerminalState.CONNECTING); } /** @@ -91,7 +92,7 @@ public class SerialConnectWorker extends Thread { // nothing to do -- should never happen... return; } - // Reinitialise the ports because we have changed the list of known ports + // Reinitialize the ports because we have changed the list of known ports CommPortIdentifier.getPortIdentifiers(); } @@ -101,6 +102,7 @@ public class SerialConnectWorker extends Thread { //TODO [206884] This is part of API and should be changed for the next release final String strID = getClass().getPackage().getName(); //final String strID = "org.eclipse.tm.terminal.serial"; //$NON-NLS-1$ + SerialPort serialPort = null; try { fControl.setState(TerminalState.OPENED); ISerialSettings s=fConn.getSerialSettings(); @@ -116,7 +118,7 @@ public class SerialConnectWorker extends Thread { fConn.setSerialPortIdentifier(CommPortIdentifier.getPortIdentifier(portName)); int timeoutInMs = s.getTimeout() * 1000; - SerialPort serialPort=(SerialPort) fConn.getSerialPortIdentifier().open(strID,timeoutInMs); + serialPort=(SerialPort) fConn.getSerialPortIdentifier().open(strID,timeoutInMs); serialPort.setSerialPortParams(s.getBaudRate(), s.getDataBits(), s.getStopBits(), s.getParity()); serialPort.setFlowControlMode(s.getFlowControl()); serialPort.addEventListener(fConn.getSerialPortHandler()); @@ -139,7 +141,22 @@ public class SerialConnectWorker extends Thread { fControl.displayTextInTerminal("No such port: \"" + msg+"\"\r\n"); //$NON-NLS-1$ //$NON-NLS-2$ } catch (Exception exception) { + Logger.logException(exception); + if (serialPort!=null) { + //Event listener is removed as part of close(), + //but exceptions need to be caught to ensure that close() really succeeds + try { + serialPort.removeEventListener(); + Thread.sleep(50); //allow a little time for RXTX Native to catch up - makes stuff more stable + } catch(Exception e) { + Logger.logException(e); + } + serialPort.close(); + fConn.getSerialPortIdentifier().removePortOwnershipListener(fConn.getSerialPortHandler()); + } fControl.setState(TerminalState.CLOSED); + } finally { + fConn.doneConnect(); } } } \ No newline at end of file diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialConnector.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialConnector.java index 2a3dfd00a93..c63fec23d53 100644 --- a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialConnector.java +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/internal/terminal/serial/SerialConnector.java @@ -13,7 +13,8 @@ * Contributors: * Michael Scharf (Wind River) - extracted from TerminalControl * Martin Oberhuber (Wind River) - fixed copyright headers and beautified - * Martin Oberhuber (Wind River) - [206892] Dont connect if already connecting + * Martin Oberhuber (Wind River) - [206892] Don't connect if already connecting + * Martin Oberhuber (Wind River) - [208029] COM port not released after quick disconnect/reconnect *******************************************************************************/ package org.eclipse.tm.internal.terminal.serial; @@ -42,7 +43,9 @@ public class SerialConnector implements ITerminalConnector { private CommPortIdentifier fSerialPortIdentifier; private SerialPortHandler fTerminalSerialPortHandler; private SerialSettings fSettings; - private SerialConnectWorker fConnectWorker; + private SerialConnectWorker fConnectWorker = null; + private volatile boolean fDisconnectGoingOn = false; + public SerialConnector() { } public SerialConnector(SerialSettings settings) { @@ -58,16 +61,37 @@ public class SerialConnector implements ITerminalConnector { } public void connect(ITerminalControl control) { Logger.log("entered."); //$NON-NLS-1$ - if (fConnectWorker!=null && fConnectWorker.isAlive()) { - //already connecting - return; + synchronized(this) { + if (fConnectWorker!=null || fDisconnectGoingOn) { + //avoid multiple background connect/disconnect threads at the same time + return; + } + fConnectWorker = new SerialConnectWorker(this, control); } - fConnectWorker = new SerialConnectWorker(this, control); fControl=control; + fControl.setState(TerminalState.CONNECTING); fConnectWorker.start(); } + /** + * Indicate that the connectWorker is finished. + */ + void doneConnect() { + synchronized(this) { + fConnectWorker = null; + } + } public void disconnect() { Logger.log("entered."); //$NON-NLS-1$ + synchronized(this) { + //avoid multiple background connect/disconnect threads at the same time + if (fConnectWorker!=null) { + fConnectWorker.interrupt(); + return; + } else if (fDisconnectGoingOn) { + return; + } + fDisconnectGoingOn = true; + } // Fix for SPR 112422. When output is being received from the serial port, the // below call to removePortOwnershipListener() attempts to lock the serial port @@ -85,37 +109,53 @@ public class SerialConnector implements ITerminalConnector { new Thread("Terminal View Serial Port Disconnect Worker") //$NON-NLS-1$ { public void run() { - - if (getSerialPortIdentifier() != null) { - getSerialPortIdentifier() - .removePortOwnershipListener(getSerialPortHandler()); - } - - if (getSerialPort() != null) { - getSerialPort().removeEventListener(); - Logger.log("Calling close() on serial port ..."); //$NON-NLS-1$ - getSerialPort().close(); - } - - if (getInputStream() != null) { - try { - getInputStream().close(); - } catch (Exception exception) { - Logger.logException(exception); + try { + if (getSerialPortIdentifier() != null) { + try { + getSerialPortIdentifier() + .removePortOwnershipListener(getSerialPortHandler()); + } catch(Exception e) { + Logger.logException(e); + } } - } - - if (getOutputStream() != null) { - try { - getOutputStream().close(); - } catch (Exception exception) { - Logger.logException(exception); + + if (getSerialPort() != null) { + //Event listener is removed as part of close(), + //but exceptions need to be caught to ensure that close() really succeeds + try { + getSerialPort().removeEventListener(); + Thread.sleep(50); //allow a little time for RXTX Native to catch up - makes stuff more stable + } catch(Exception e) { + Logger.logException(e); + } + Logger.log("Calling close() on serial port ..."); //$NON-NLS-1$ + getSerialPort().close(); } + + if (getInputStream() != null) { + try { + getInputStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + + if (getOutputStream() != null) { + try { + getOutputStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + + setSerialPortIdentifier(null); + cleanSerialPort(); + setSerialPortHandler(null); + } catch(Exception e) { + Logger.logException(e); + } finally { + fDisconnectGoingOn = false; } - - setSerialPortIdentifier(null); - cleanSerialPort(); - setSerialPortHandler(null); } }.start(); @@ -165,6 +205,7 @@ public class SerialConnector implements ITerminalConnector { return fSerialPortIdentifier; } protected void setSerialPortIdentifier(CommPortIdentifier serialPortIdentifier) { + //System.out.println("setSerialPortId: "+Thread.currentThread().getName()+ " - "+serialPortIdentifier + " - "+System.currentTimeMillis()); fSerialPortIdentifier = serialPortIdentifier; } void setSerialPortHandler(SerialPortHandler serialPortHandler) { @@ -175,6 +216,7 @@ public class SerialConnector implements ITerminalConnector { } public ISerialSettings getSerialSettings() { return fSettings; + } public ISettingsPage makeSettingsPage() { return new SerialSettingsPage(fSettings);