Force interrupt event waiting thread in case it gets stuck in native/driver code during close

This commit is contained in:
hedgecrw85 2020-02-19 11:48:25 -06:00
parent 8c9e671c43
commit 7aec1d59d7
1 changed files with 50 additions and 50 deletions

View File

@ -2,7 +2,7 @@
* SerialPort.java
*
* Created on: Feb 25, 2012
* Last Updated on: Feb 18, 2020
* Last Updated on: Feb 19, 2020
* Author: Will Hedgecock
*
* Copyright (C) 2012-2020 Fazecast, Inc.
@ -374,13 +374,13 @@ public final class SerialPort
private volatile int timeoutMode = TIMEOUT_NONBLOCKING, readTimeout = 0, writeTimeout = 0, flowControl = 0;
private volatile int sendDeviceQueueSize = 4096, receiveDeviceQueueSize = 4096;
private volatile int safetySleepTimeMS = 200, rs485DelayBefore = 0, rs485DelayAfter = 0;
private volatile SerialPortInputStream inputStream = null;
private volatile SerialPortOutputStream outputStream = null;
private volatile SerialPortDataListener userDataListener = null;
private volatile SerialPortEventListener serialEventListener = null;
private volatile String comPort, friendlyName, portDescription;
private volatile boolean isOpened = false, disableConfig = false, rs485Mode = false;
private volatile boolean eventListenerRunning = false, disableConfig = false, rs485Mode = false;
private volatile boolean rs485ActiveHigh = true, isRtsEnabled = true, isDtrEnabled = true;
private final SerialPortInputStream inputStream = new SerialPortInputStream();
private final SerialPortOutputStream outputStream = new SerialPortOutputStream();
/**
* Opens this serial port for reading and writing with an optional delay time and user-specified device buffer size.
@ -400,7 +400,7 @@ public final class SerialPort
safetySleepTimeMS = safetySleepTime;
sendDeviceQueueSize = deviceSendQueueSize;
receiveDeviceQueueSize = deviceReceiveQueueSize;
if (isOpened)
if (portHandle > 0)
return configPort(portHandle);
// Force a sleep to ensure that the port does not become unusable due to rapid closing/opening on the part of the user
@ -439,14 +439,13 @@ public final class SerialPort
}
}
// Open the serial port and start an event-based listener if registered
if ((portHandle = openPortNative()) > 0)
{
inputStream = new SerialPortInputStream();
outputStream = new SerialPortOutputStream();
if (serialEventListener != null)
serialEventListener.startListening();
}
return isOpened;
return (portHandle > 0);
}
/**
@ -485,13 +484,8 @@ public final class SerialPort
{
if (serialEventListener != null)
serialEventListener.stopListening();
if (isOpened && closePortNative(portHandle))
{
inputStream = null;
outputStream = null;
portHandle = -1;
}
return !isOpened;
closePortNative(portHandle);
return (portHandle <= 0);
}
/**
@ -499,7 +493,7 @@ public final class SerialPort
*
* @return Whether the port is opened.
*/
public final synchronized boolean isOpen() { return isOpened; }
public final synchronized boolean isOpen() { return (portHandle > 0); }
/**
* Disables the library from calling any of the underlying device driver configuration methods.
@ -650,7 +644,7 @@ public final class SerialPort
public final boolean setRTS()
{
isRtsEnabled = true;
return (isOpened ? setRTS(portHandle) : presetRTS());
return ((portHandle > 0) ? setRTS(portHandle) : presetRTS());
}
/**
@ -660,7 +654,7 @@ public final class SerialPort
public final boolean clearRTS()
{
isRtsEnabled = false;
return (isOpened ? clearRTS(portHandle) : preclearRTS());
return ((portHandle > 0) ? clearRTS(portHandle) : preclearRTS());
}
/**
@ -670,7 +664,7 @@ public final class SerialPort
public final boolean setDTR()
{
isDtrEnabled = true;
return (isOpened ? setDTR(portHandle) : presetDTR());
return ((portHandle > 0) ? setDTR(portHandle) : presetDTR());
}
/**
@ -680,7 +674,7 @@ public final class SerialPort
public final boolean clearDTR()
{
isDtrEnabled = false;
return (isOpened ? clearDTR(portHandle) : preclearDTR());
return ((portHandle > 0) ? clearDTR(portHandle) : preclearDTR());
}
/**
@ -766,7 +760,7 @@ public final class SerialPort
if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_WRITTEN) > 0)
eventFlags |= LISTENING_EVENT_DATA_WRITTEN;
if (isOpened)
if (portHandle > 0)
{
configEventFlags(portHandle);
serialEventListener.startListening();
@ -779,16 +773,16 @@ public final class SerialPort
*/
public final synchronized void removeDataListener()
{
eventFlags = 0;
if (portHandle > 0)
configEventFlags(portHandle);
if (serialEventListener != null)
{
serialEventListener.stopListening();
serialEventListener = null;
}
userDataListener = null;
eventFlags = 0;
if (isOpened)
configEventFlags(portHandle);
}
/**
@ -903,7 +897,7 @@ public final class SerialPort
parity = newParity;
rs485Mode = useRS485Mode;
if (isOpened)
if (portHandle > 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -969,7 +963,7 @@ public final class SerialPort
else
readTimeout = Math.round((float)newReadTimeout / 100.0f) * 100;
if (isOpened)
if (portHandle > 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -988,7 +982,7 @@ public final class SerialPort
{
baudRate = newBaudRate;
if (isOpened)
if (portHandle > 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1007,7 +1001,7 @@ public final class SerialPort
{
dataBits = newDataBits;
if (isOpened)
if (portHandle > 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1032,7 +1026,7 @@ public final class SerialPort
{
stopBits = newStopBits;
if (isOpened)
if (portHandle > 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1078,7 +1072,7 @@ public final class SerialPort
{
flowControl = newFlowControlSettings;
if (isOpened)
if (portHandle > 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1103,7 +1097,7 @@ public final class SerialPort
{
parity = newParity;
if (isOpened)
if (portHandle > 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1136,7 +1130,7 @@ public final class SerialPort
rs485DelayBefore = delayBeforeSendMicroseconds;
rs485DelayAfter = delayAfterSendMicroseconds;
if (isOpened)
if (portHandle > 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1274,7 +1268,6 @@ public final class SerialPort
// Private EventListener class
private final class SerialPortEventListener
{
private volatile boolean isListening = false;
private final boolean messageEndIsDelimited;
private final byte[] dataPacket, delimiters;
private volatile ByteArrayOutputStream messageBytes = new ByteArrayOutputStream();
@ -1287,9 +1280,9 @@ public final class SerialPort
public final void startListening()
{
if (isListening)
if (eventListenerRunning)
return;
isListening = true;
eventListenerRunning = true;
dataPacketIndex = 0;
serialEventThread = new Thread(new Runnable()
@ -1297,19 +1290,19 @@ public final class SerialPort
@Override
public void run()
{
while (isListening && isOpened)
while (eventListenerRunning && (portHandle > 0))
{
try { waitForSerialEvent(); }
catch (Exception e)
{
isListening = false;
eventListenerRunning = false;
if (userDataListener instanceof SerialPortDataListenerWithExceptions)
((SerialPortDataListenerWithExceptions)userDataListener).catchException(e);
else if (userDataListener instanceof SerialPortMessageListenerWithExceptions)
((SerialPortMessageListenerWithExceptions)userDataListener).catchException(e);
}
}
isListening = false;
eventListenerRunning = false;
}
});
serialEventThread.start();
@ -1317,15 +1310,22 @@ public final class SerialPort
public final void stopListening()
{
if (!isListening)
if (!eventListenerRunning)
return;
isListening = false;
eventListenerRunning = false;
int oldEventFlags = eventFlags;
eventFlags = 0;
configEventFlags(portHandle);
eventFlags = oldEventFlags;
try { serialEventThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
try
{
serialEventThread.join(500);
if (serialEventThread.isAlive())
serialEventThread.interrupt();
serialEventThread.join();
}
catch (InterruptedException e) { Thread.currentThread().interrupt(); }
serialEventThread = null;
}
@ -1339,7 +1339,7 @@ public final class SerialPort
{
// Read data from serial port
int numBytesAvailable, bytesRemaining, newBytesIndex;
while (isListening && ((numBytesAvailable = bytesAvailable(portHandle)) > 0))
while (eventListenerRunning && ((numBytesAvailable = bytesAvailable(portHandle)) > 0))
{
byte[] newBytes = new byte[numBytesAvailable];
newBytesIndex = 0;
@ -1413,7 +1413,7 @@ public final class SerialPort
@Override
public final int available() throws SerialPortIOException
{
if (!isOpened)
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
return bytesAvailable(portHandle);
}
@ -1422,7 +1422,7 @@ public final class SerialPort
public final int read() throws SerialPortIOException, SerialPortTimeoutException
{
// Perform error checking
if (!isOpened)
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
// Read from the serial port
@ -1438,7 +1438,7 @@ public final class SerialPort
// Perform error checking
if (b == null)
throw new NullPointerException("A null pointer was passed in for the read buffer.");
if (!isOpened)
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
if (b.length == 0)
return 0;
@ -1458,7 +1458,7 @@ public final class SerialPort
throw new NullPointerException("A null pointer was passed in for the read buffer.");
if ((len < 0) || (off < 0) || (len > (b.length - off)))
throw new IndexOutOfBoundsException("The specified read offset plus length extends past the end of the specified buffer.");
if (!isOpened)
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
if ((b.length == 0) || (len == 0))
return 0;
@ -1473,7 +1473,7 @@ public final class SerialPort
@Override
public final long skip(long n) throws SerialPortIOException
{
if (!isOpened)
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
byte[] buffer = new byte[(int)n];
return readBytes(portHandle, buffer, n, 0);
@ -1490,7 +1490,7 @@ public final class SerialPort
@Override
public final void write(int b) throws SerialPortIOException, SerialPortTimeoutException
{
if (!isOpened)
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
byteBuffer[0] = (byte)(b & 0xFF);
int bytesWritten = writeBytes(portHandle, byteBuffer, 1L, 0);
@ -1514,7 +1514,7 @@ public final class SerialPort
throw new NullPointerException("A null pointer was passed in for the write buffer.");
if ((len < 0) || (off < 0) || ((off + len) > b.length))
throw new IndexOutOfBoundsException("The specified write offset plus length extends past the end of the specified buffer.");
if (!isOpened)
if (portHandle <= 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
if (len == 0)
return;