diff --git a/src/main/c/src/SerialImp.c b/src/main/c/src/SerialImp.c
index 85833a86..aa0f048c 100644
--- a/src/main/c/src/SerialImp.c
+++ b/src/main/c/src/SerialImp.c
@@ -3792,23 +3792,142 @@ JNIEXPORT void JNICALL RXTXPort(setflowcontrol)( JNIEnv *env,
return;
}
-/*----------------------------------------------------------
-unlock_monitor_thread
+/**
+ * Write-lock the monitor thread to protect state mutation.
+ *
+ * Blocks until the write lock comes available.
+ *
+ * @param [in] env the JNI environment
+ * @param [in] obj an RXTXPort instance
+ * @return 0 on success; 1 on error
+ */
+int lock_monitor_thread(JNIEnv *env, jobject jobj)
+{
+ jfieldID monitorThreadStateWriteLockField = (*env)->GetFieldID(
+ env,
+ (*env)->GetObjectClass(env, jobj),
+ "monitorThreadStateWriteLock",
+ "Ljava/util/concurrent/locks/Lock;");
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
- accept: event_info_struct
- perform: unlock the monitor thread so event notification can start.
- return: none
- exceptions: none
- comments: Events can be missed otherwise.
-----------------------------------------------------------*/
+ jobject monitorThreadStateWriteLock = (*env)->GetObjectField(
+ env,
+ jobj,
+ monitorThreadStateWriteLockField);
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ jmethodID lock = (*env)->GetMethodID(
+ env,
+ (*env)->GetObjectClass(env, monitorThreadStateWriteLock),
+ "lock",
+ "()V");
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ (*env)->CallVoidMethod(env, monitorThreadStateWriteLock, lock);
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
-void unlock_monitor_thread( struct event_info_struct *eis )
+ return 0;
+}
+
+/**
+ * Signal that the monitor thread is ready for work.
+ *
+ * In order to signal the condition, the current thread must already hold the
+ * write lock.
+ *
+ * @param [in] env the JNI environment
+ * @param [in] obj an RXTXPort instance
+ * @return 0 on success; 1 on error
+ */
+int signal_monitor_thread_ready(JNIEnv *env, jobject jobj)
{
- JNIEnv *env = eis->env;
- jobject jobj = *(eis->jobj);
+ jfieldID monitorThreadReadyField = (*env)->GetFieldID(
+ env,
+ (*env)->GetObjectClass(env, jobj),
+ "monitorThreadReady",
+ "Ljava/util/concurrent/locks/Condition;");
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ jobject monitorThreadReady = (*env)->GetObjectField(
+ env,
+ jobj,
+ monitorThreadReadyField);
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
- jfieldID jfid = (*env)->GetFieldID( env, (*env)->GetObjectClass( env, jobj ), "MonitorThreadLock", "Z" );
- (*env)->SetBooleanField( env, jobj, jfid, (jboolean) 0 );
+ jmethodID signal = (*env)->GetMethodID(
+ env,
+ (*env)->GetObjectClass(env, monitorThreadReady),
+ "signal",
+ "()V");
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ (*env)->CallVoidMethod(env, monitorThreadReady, signal);
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Unlock the write lock on the monitor thread to permit read and write access
+ * by other threads.
+ *
+ * In order to unlock the monitor thread, the current thread must already hold
+ * the write lock.
+ *
+ * @param [in] env the JNI environment
+ * @param [in] obj an RXTXPort instance
+ * @return 0 on success; 1 on error
+ */
+int unlock_monitor_thread(JNIEnv *env, jobject jobj)
+{
+ jfieldID monitorThreadStateWriteLockField = (*env)->GetFieldID(
+ env,
+ (*env)->GetObjectClass(env, jobj),
+ "monitorThreadStateWriteLock",
+ "Ljava/util/concurrent/locks/Lock;");
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ jobject monitorThreadStateWriteLock = (*env)->GetObjectField(
+ env,
+ jobj,
+ monitorThreadStateWriteLockField);
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ jmethodID unlock = (*env)->GetMethodID(
+ env,
+ (*env)->GetObjectClass(env, monitorThreadStateWriteLock),
+ "unlock",
+ "()V");
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ (*env)->CallVoidMethod(env, monitorThreadStateWriteLock, unlock);
+ if ((*env)->ExceptionCheck(env)) {
+ return 1;
+ }
+
+ return 0;
}
/*----------------------------------------------------------
@@ -4254,6 +4373,8 @@ RXTXPort.eventLoop
----------------------------------------------------------*/
JNIEXPORT void JNICALL RXTXPort(eventLoop)( JNIEnv *env, jobject jobj )
{
+ if (lock_monitor_thread(env, jobj)) goto end;
+
#ifdef WIN32
int i = 0;
#endif /* WIN32 */
@@ -4266,16 +4387,37 @@ JNIEXPORT void JNICALL RXTXPort(eventLoop)( JNIEnv *env, jobject jobj )
ENTER( "eventLoop\n" );
if ( !initialise_event_info_struct( &eis ) ) goto end;
if ( !init_threads( &eis ) ) goto end;
- unlock_monitor_thread( &eis );
+
+ if (signal_monitor_thread_ready(env, jobj)) goto end;
+ if (unlock_monitor_thread(env, jobj)) goto end;
+
do{
report_time_eventLoop( );
do {
if(RXTXPort(nativeavailable)( env, jobj )<0){
report("eventLoop: Hardware Missing\n");
- finalize_threads( &eis );
- finalize_event_info_struct( &eis );
- LEAVE("eventLoop:error");
- return;
+ /* The hardware is gone, so we need to stop the monitor thread.
+ * Conveniently, this function is supposed to be an infinite
+ * loop, so once we return from it to Java-land, the thread will
+ * close up shop. However, that also means that we need to make
+ * sure any native cleanup happens before we return, or else it
+ * will never run. We'll trigger that by the usual method to
+ * ensure platform-specific cleanup happens (e.g., killing the
+ * drain loop). That will also set `eis.closing`, so the
+ * function will return as usual in the next block.
+ *
+ * `nativeavailable()` has thrown an exception at this point, so
+ * in order to call anything else which uses exceptions (like
+ * the locking functions), we'll temporarily clear the exception
+ * then reset it before continuing. */
+ jthrowable hardwareException = (*env)->ExceptionOccurred(env);
+ (*env)->ExceptionClear(env);
+
+ if (lock_monitor_thread(env, jobj)) goto end;
+ RXTXPort(interruptEventLoop)(env, jobj);
+ if (unlock_monitor_thread(env, jobj)) goto end;
+
+ (*env)->Throw(env, hardwareException);
}
/* nothing goes between this call and select */
if( eis.closing )
@@ -4964,7 +5106,22 @@ JNIEXPORT void JNICALL RXTXPort(interruptEventLoop)(JNIEnv *env,
usleep(1000);
}
}
+
index->eventloop_interrupted = 1;
+
+ jfieldID monThreadisInterruptedField = (*env)->GetFieldID(
+ env,
+ (*env)->GetObjectClass(env, jobj),
+ "monThreadisInterrupted",
+ "Z");
+ if ((*env)->ExceptionCheck(env)) {
+ return;
+ }
+ (*env)->SetBooleanField(env, jobj, monThreadisInterruptedField, JNI_TRUE);
+ if ((*env)->ExceptionCheck(env)) {
+ return;
+ }
+
/*
Many OS's need a thread running to determine if output buffer is
empty. For Linux and Win32 it is not needed. So closing is used to
diff --git a/src/main/java/gnu/io/RXTXPort.java b/src/main/java/gnu/io/RXTXPort.java
index c9604e88..f0559661 100644
--- a/src/main/java/gnu/io/RXTXPort.java
+++ b/src/main/java/gnu/io/RXTXPort.java
@@ -62,6 +62,9 @@
import java.util.TooManyListenersException;
import java.lang.Math;
import java.util.concurrent.*;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* An extension of gnu.io.SerialPort
@@ -146,7 +149,6 @@ protected void finalize() throws Throwable
/** Initialize the native library */
private native static void Initialize();
- boolean MonitorThreadAlive=false;
/**
* Open the named port
@@ -173,12 +175,16 @@ public RXTXPort( String name ) throws PortInUseException
fd = open( name );
this.name = name;
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
monThread = new MonitorThread();
monThread.setName("RXTXPortMonitor("+name+")");
monThread.start();
- waitForTheNativeCodeSilly();
- MonitorThreadAlive=true;
+ try {
+ this.monitorThreadReady.await();
+ } catch (InterruptedException e) {
+ z.reportln("Interrupted while waiting for the monitor thread to start!");
+ }
+ this.monitorThreadState.writeLock().unlock();
// } catch ( PortInUseException e ){}
timeout = -1; /* default disabled timeout */
if (debug)
@@ -189,7 +195,7 @@ public RXTXPort( String name ) throws PortInUseException
/* dont close the file while accessing the fd */
- private final java.util.concurrent.locks.ReentrantReadWriteLock IOLockedMutex = new java.util.concurrent.locks.ReentrantReadWriteLock(true);
+ private final ReentrantReadWriteLock IOLockedMutex = new ReentrantReadWriteLock(true);
/** File descriptor */
private int fd = 0;
@@ -666,13 +672,43 @@ protected native int readTerminatedArray( byte b[], int off, int len, byte t[] )
/** Thread to monitor data */
private MonitorThread monThread;
+ /**
+ * A lock around the monitor thread state. Used to synchronize event
+ * configuration changes (event types enabled/disabled).
+ *
+ * This is a {@link ReentrantReadWriteLock} rather than a plain old object
+ * (i.e., as used with synchronized
blocks) to enable the
+ * InputStream
/OutputStream
read/write methods to
+ * take out a read lock on the monitor thread state.
+ */
+ private final ReentrantReadWriteLock monitorThreadState = new ReentrantReadWriteLock();
+
+ /**
+ * Shortcut field to make acquisition of the write lock easier from JNI code.
+ * Saves retrieval of the {@link #monitorThreadState} field ID, then the
+ * value of the field, then the writeLock()
method ID,
+ * then invoking that method.
+ */
+ private final Lock monitorThreadStateWriteLock = this.monitorThreadState.writeLock();
+
+ /**
+ * Signalled by JNI code from inside {@link #eventLoop()} when the event
+ * loop has finished initialization of the native data structures and is
+ * ready to service events.
+ */
+ private final Condition monitorThreadReady = this.monitorThreadState.writeLock().newCondition();
+
/** Process SerialPortEvents */
native void eventLoop();
- /**
- * @return boolean true if monitor thread is interrupted
- */
+ /**
+ * Whether the monitor thread has been interrupted.
+ *
+ * The flag is cleared when the monitor thread is started, and set by the
+ * native code in {@ #interruptEventLoop()}.
+ */
boolean monThreadisInterrupted=true;
+
private native void interruptEventLoop( );
public boolean checkMonitorThread()
{
@@ -854,9 +890,6 @@ public boolean sendEvent( int event, boolean state )
* @param lsnr SerialPortEventListener
* TooManyListenersException
*/
-
- boolean MonitorThreadLock = true;
-
public void addEventListener(
SerialPortEventListener lsnr ) throws TooManyListenersException
{
@@ -871,94 +904,54 @@ public void addEventListener(
throw new TooManyListenersException();
}
SPEventListener = lsnr;
- if( !MonitorThreadAlive )
+ if (this.monThread == null)
{
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
monThread = new MonitorThread();
monThread.setName("RXTXPortMonitor("+name+")");
monThread.start();
- waitForTheNativeCodeSilly();
- MonitorThreadAlive=true;
+ try {
+ this.monitorThreadReady.await();
+ } catch (InterruptedException e) {
+ z.reportln("Interrupted while waiting for the monitor thread to start!");
+ }
+ this.monitorThreadState.writeLock().unlock();
}
if (debug)
z.reportln( "RXTXPort:Interrupt=false");
}
- /**
- * Remove the serial port event listener
- */
- public void removeEventListener()
- {
- if (debug)
- z.reportln( "RXTXPort:removeEventListener() called");
- waitForTheNativeCodeSilly();
- //if( monThread != null && monThread.isAlive() )
- if( monThreadisInterrupted == true )
- {
- z.reportln( " RXTXPort:removeEventListener() already interrupted");
- monThread = null;
- SPEventListener = null;
- return;
- }
- else if( monThread != null && monThread.isAlive() && !HARDWARE_FAULT)
- {
- if (debug)
- z.reportln( " RXTXPort:Interrupt=true");
- monThreadisInterrupted=true;
- /*
- Notify all threads in this PID that something is up
- They will call back to see if its their thread
- using isInterrupted().
- */
- if (debug)
- z.reportln( " RXTXPort:calling interruptEventLoop");
- interruptEventLoop( );
-
- if (debug)
- z.reportln( " RXTXPort:calling monThread.join()");
- try {
-
- // wait a reasonable moment for the death of the monitor thread
- monThread.join(3000);
- } catch (InterruptedException ex) {
- // somebody called interrupt() on us (ie wants us to abort)
- // we dont propagate InterruptedExceptions so lets re-set the flag
- Thread.currentThread().interrupt();
- return;
- }
-
- if ( debug ) {
- if (monThread.isAlive()) {
- z.reportln( " MonThread is still alive!");
- }
- }
-
- }
- monThread = null;
- SPEventListener = null;
- MonitorThreadLock = false;
- MonitorThreadAlive=false;
- monThreadisInterrupted=true;
- z.reportln( "RXTXPort:removeEventListener() returning");
- }
/**
- * Give the native code a chance to start listening to the hardware
- * or should we say give the native code control of the issue.
+ * Remove the serial port event listener.
*
- * This is important for applications that flicker the Monitor
- * thread while keeping the port open.
- * In worst case test cases this loops once or twice every time.
+ * Also interrupts the monitor thread.
*/
-
- protected void waitForTheNativeCodeSilly()
- {
- while( MonitorThreadLock )
- {
- try {
- Thread.sleep(5);
- } catch( Exception e ) {}
+ public void removeEventListener() {
+ this.monitorThreadState.writeLock().lock();
+ try {
+ /* The monitor thread might already be interrupted if it
+ * encountered a hardware error and shut itself down. */
+ if (!this.monThreadisInterrupted) {
+ this.interruptEventLoop();
+ }
+ if (this.monThread != null && this.monThread.isAlive()) {
+ try {
+ // wait a reasonable moment for the death of the monitor thread
+ this.monThread.join(3000);
+ } catch (InterruptedException ex) {
+ // somebody called interrupt() on us (ie wants us to abort)
+ // we dont propagate InterruptedExceptions so lets re-set the flag
+ Thread.currentThread().interrupt();
+ return;
+ }
+ }
+ this.monThread = null;
+ this.SPEventListener = null;
+ } finally {
+ this.monitorThreadState.writeLock().unlock();
}
}
+
/**
* @param enable
*/
@@ -969,14 +962,11 @@ public void notifyOnDataAvailable( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnDataAvailable( " +
enable+" )");
-
- waitForTheNativeCodeSilly();
-
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.DATA_AVAILABLE,
enable );
monThread.Data = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
@@ -987,12 +977,11 @@ public void notifyOnOutputEmpty( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnOutputEmpty( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.OUTPUT_BUFFER_EMPTY,
enable );
monThread.Output = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
@@ -1003,11 +992,10 @@ public void notifyOnCTS( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnCTS( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.CTS, enable );
monThread.CTS = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
* @param enable
@@ -1017,11 +1005,10 @@ public void notifyOnDSR( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnDSR( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.DSR, enable );
monThread.DSR = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
* @param enable
@@ -1031,11 +1018,10 @@ public void notifyOnRingIndicator( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnRingIndicator( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.RI, enable );
monThread.RI = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
* @param enable
@@ -1045,11 +1031,10 @@ public void notifyOnCarrierDetect( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnCarrierDetect( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.CD, enable );
monThread.CD = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
* @param enable
@@ -1059,11 +1044,10 @@ public void notifyOnOverrunError( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnOverrunError( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.OE, enable );
monThread.OE = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
* @param enable
@@ -1073,11 +1057,10 @@ public void notifyOnParityError( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnParityError( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.PE, enable );
monThread.PE = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
* @param enable
@@ -1087,11 +1070,10 @@ public void notifyOnFramingError( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnFramingError( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.FE, enable );
monThread.FE = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/**
* @param enable
@@ -1101,11 +1083,10 @@ public void notifyOnBreakInterrupt( boolean enable )
if (debug)
z.reportln( "RXTXPort:notifyOnBreakInterrupt( " +
enable+" )");
- waitForTheNativeCodeSilly();
- MonitorThreadLock = true;
+ this.monitorThreadState.writeLock().lock();
nativeSetEventFlag( fd, SerialPortEvent.BI, enable );
monThread.BI = enable;
- MonitorThreadLock = false;
+ this.monitorThreadState.writeLock().unlock();
}
/** Close the port */
@@ -1193,8 +1174,8 @@ public void write( int b ) throws IOException
return;
}
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try {
- waitForTheNativeCodeSilly();
if ( fd == 0 )
{
System.err.println("File Descriptor for prot zero!!");
@@ -1204,6 +1185,7 @@ public void write( int b ) throws IOException
if (debug_write)
z.reportln( "Leaving RXTXPort:SerialOutputStream:write( int )");
} finally {
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
}
@@ -1224,12 +1206,13 @@ public void write( byte b[] ) throws IOException
}
if ( fd == 0 ) throw new IOException();
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try {
- waitForTheNativeCodeSilly();
writeArray( b, 0, b.length, monThreadisInterrupted );
if (debug_write)
z.reportln( "Leaving RXTXPort:SerialOutputStream:write(" +b.length +")");
} finally {
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
@@ -1263,13 +1246,14 @@ public void write( byte b[], int off, int len )
return;
}
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try
{
- waitForTheNativeCodeSilly();
writeArray( send, 0, len, monThreadisInterrupted );
if( debug_write )
z.reportln( "Leaving RXTXPort:SerialOutputStream:write(" + send.length + " " + off + " " + len + " " +") " /*+ new String(send)*/ );
} finally {
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
}
@@ -1288,9 +1272,9 @@ public void flush() throws IOException
return;
}
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try
{
- waitForTheNativeCodeSilly();
/*
this is probably good on all OS's but for now
just sendEvent from java on Sol
@@ -1302,6 +1286,7 @@ public void flush() throws IOException
}
finally
{
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
}
@@ -1335,10 +1320,10 @@ public synchronized int read() throws IOException
z.reportln( "+++++++++ read() monThreadisInterrupted" );
}
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try {
if (debug_read_results)
z.reportln( "RXTXPort:SerialInputStream:read() L" );
- waitForTheNativeCodeSilly();
if (debug_read_results)
z.reportln( "RXTXPort:SerialInputStream:read() N" );
int result = readByte();
@@ -1349,6 +1334,7 @@ public synchronized int read() throws IOException
}
finally
{
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
}
@@ -1375,9 +1361,9 @@ public synchronized int read( byte b[] ) throws IOException
return(0);
}
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try
{
- waitForTheNativeCodeSilly();
result = read( b, 0, b.length);
if (debug_read_results)
z.reportln( "RXTXPort:SerialInputStream:read() returned " + result + " bytes" );
@@ -1385,6 +1371,7 @@ public synchronized int read( byte b[] ) throws IOException
}
finally
{
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
}
@@ -1486,9 +1473,9 @@ public synchronized int read( byte b[], int off, int len )
return(0);
}
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try
{
- waitForTheNativeCodeSilly();
result = readArray( b, off, Minimum);
if (debug_read_results)
z.reportln( "RXTXPort:SerialInputStream:read(" + b.length + " " + off + " " + len + ") returned " + result + " bytes" /*+ new String(b) */);
@@ -1496,6 +1483,7 @@ public synchronized int read( byte b[], int off, int len )
}
finally
{
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
}
@@ -1595,9 +1583,9 @@ public synchronized int read( byte b[], int off, int len, byte t[] )
return(0);
}
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try
{
- waitForTheNativeCodeSilly();
result = readTerminatedArray( b, off, Minimum, t );
if (debug_read_results)
z.reportln( "RXTXPort:SerialInputStream:read(" + b.length + " " + off + " " + len + ") returned " + result + " bytes" /*+ new String(b) */);
@@ -1605,6 +1593,7 @@ public synchronized int read( byte b[], int off, int len, byte t[] )
}
finally
{
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
}
@@ -1621,6 +1610,7 @@ public synchronized int available() throws IOException
if ( debug_verbose )
z.reportln( "RXTXPort:available() called" );
IOLockedMutex.readLock().lock();
+ RXTXPort.this.monitorThreadState.readLock().lock();
try
{
int r = nativeavailable();
@@ -1631,6 +1621,7 @@ public synchronized int available() throws IOException
}
finally
{
+ RXTXPort.this.monitorThreadState.readLock().unlock();
IOLockedMutex.readLock().unlock();
}
}