changeset 38:510e625c9bcf

8057057: Cleanup DIO JNI code Reviewed-by: alkonsta
author jld
date Wed, 03 Sep 2014 12:04:14 -0400
parents 25e9ab48c287
children 1cad8f70dc64
files src/se/native/com/oracle/dio/dio_event_queue.cpp src/se/native/com/oracle/dio/gpio/impl/jni_gpio.cpp src/se/native/com/oracle/dio/i2cbus/impl/jni_i2c.cpp src/se/native/com/oracle/dio/spibus/impl/jni_spi.cpp src/se/native/com/oracle/dio/uart/impl/jni_uart.cpp src/share/linux/native/com/oracle/dio/uart/uart.c
diffstat 6 files changed, 221 insertions(+), 156 deletions(-) [+]
line wrap: on
line diff
--- a/src/se/native/com/oracle/dio/dio_event_queue.cpp	Thu Aug 28 18:52:15 2014 +0400
+++ b/src/se/native/com/oracle/dio/dio_event_queue.cpp	Wed Sep 03 12:04:14 2014 -0400
@@ -34,16 +34,20 @@
   (JNIEnv* env, jclass clazz, jobject buffer, jint currPos) {
     // required methods references
     jclass bufferClass = env->GetObjectClass(buffer);
-    jmethodID setPositionID = env->GetMethodID(bufferClass, "position", "(I)Ljava/nio/Buffer;");
+
+    jmethodID setPositionID = bufferClass ? env->GetMethodID(bufferClass, "position", "(I)Ljava/nio/Buffer;") :
+                                            NULL;
 
     // Not necessary to synchronize on buffer, it's always called from protected section
-    jbyte* buf = (jbyte*)env->GetDirectBufferAddress(buffer);
+    jbyte* buf = setPositionID ? (jbyte*)env->GetDirectBufferAddress(buffer) :
+                                 NULL;
 
-    jclass eventClass;
-    memcpy(&eventClass, buf + currPos, JCLASS_SIZE);
-
-    // update buffer position
-    env->CallObjectMethod(buffer, setPositionID, currPos + JCLASS_SIZE);
+    jclass eventClass = NULL;
+    if (buf) {
+        memcpy(&eventClass, buf + currPos, JCLASS_SIZE);
+        // update buffer position
+        env->CallObjectMethod(buffer, setPositionID, currPos + JCLASS_SIZE);
+    }
 
     return eventClass;
 }
@@ -61,35 +65,42 @@
     cachedJVM->AttachCurrentThread((void**)&env, NULL);
 
     jclass bufferClass = env->GetObjectClass(eventBufferRef);
-    jmethodID notifyID = env->GetMethodID(bufferClass, "notify", "()V");
-    jmethodID limitID = env->GetMethodID(bufferClass, "limit", "()I");
-    jmethodID setLimitID = env->GetMethodID(bufferClass, "limit", "(I)Ljava/nio/Buffer;");
+    jmethodID notifyID = bufferClass ? env->GetMethodID(bufferClass, "notify", "()V") :
+                                       NULL;
+    jmethodID limitID = notifyID ? env->GetMethodID(bufferClass, "limit", "()I") :
+                                  NULL;
+    jmethodID setLimitID = limitID ? env->GetMethodID(bufferClass, "limit", "(I)Ljava/nio/Buffer;") :
+                                     NULL;
 
-    env->MonitorEnter(eventBufferRef);
+    if (setLimitID) {
+        env->MonitorEnter(eventBufferRef);
 
-    // check enough space in direct buffer
-    jlong capacity = env->GetDirectBufferCapacity(eventBufferRef);
-    jint limit = env->CallIntMethod(eventBufferRef, limitID);
+        if (env->ExceptionCheck() != JNI_TRUE) {
+            // check enough space in direct buffer
+            jlong capacity = env->GetDirectBufferCapacity(eventBufferRef);
+            jint limit = env->CallIntMethod(eventBufferRef, limitID);
 
-    jint newLimit = limit + JCLASS_SIZE + payload_size + 2;
+            jint newLimit = limit + JCLASS_SIZE + payload_size + 2;
 
-    if (newLimit < capacity) {
-        jbyte* buf = (jbyte*)env->GetDirectBufferAddress(eventBufferRef);
+            if (newLimit < capacity) {
+                jbyte* buf = (jbyte*)env->GetDirectBufferAddress(eventBufferRef);
 
-        buf += limit;
+                buf += limit;
 
-        memcpy(buf, &eventClass, JCLASS_SIZE);
-        buf += JCLASS_SIZE;
+                memcpy(buf, &eventClass, JCLASS_SIZE);
+                buf += JCLASS_SIZE;
 
-        // payload
-        *buf++ = (jbyte)((payload_size & 0xFF00) >> 8); // high byte
-        *buf++ = (jbyte)(payload_size & 0xFF);          // then low byte
-        memcpy(buf, payload, payload_size);
+                // payload
+                *buf++ = (jbyte)((payload_size & 0xFF00) >> 8); // high byte
+                *buf++ = (jbyte)(payload_size & 0xFF);          // then low byte
+                memcpy(buf, payload, payload_size);
 
-        env->CallObjectMethod(eventBufferRef, setLimitID, newLimit);
-        env->CallVoidMethod(eventBufferRef, notifyID);
+                env->CallObjectMethod(eventBufferRef, setLimitID, newLimit);
+                env->CallVoidMethod(eventBufferRef, notifyID);
+            }
+
+            env->MonitorExit(eventBufferRef);
+        }
     }
-
-    env->MonitorExit(eventBufferRef);
     cachedJVM->DetachCurrentThread();
 }
--- a/src/se/native/com/oracle/dio/gpio/impl/jni_gpio.cpp	Thu Aug 28 18:52:15 2014 +0400
+++ b/src/se/native/com/oracle/dio/gpio/impl/jni_gpio.cpp	Wed Sep 03 12:04:14 2014 -0400
@@ -64,8 +64,9 @@
             result = saveDeviceReferenceToDeviceObject(env, obj, device);
         }
     }
-
-    checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        checkJavacallFailure(env, result);
+    }
 }
 
 /*
@@ -121,7 +122,9 @@
     } else {
         result = JAVACALL_DIO_OUT_OF_MEMORY;
     }
-    checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        checkJavacallFailure(env, result);
+    }
 }
 
 /*
@@ -191,7 +194,9 @@
     device_reference device = getDeviceReferenceFromDeviceObject(env, obj);
     javacall_dio_result result;
     result = javacall_gpio_pin_notification_start(getDeviceHandle(device));
-    checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        checkJavacallFailure(env, result);
+    }
 }
 
 /*
@@ -204,7 +209,9 @@
     device_reference device = getDeviceReferenceFromDeviceObject(env, obj);
     javacall_dio_result result;
     result = javacall_gpio_port_notification_start(getDeviceHandle(device));
-    checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+       checkJavacallFailure(env, result);
+    }
 }
 
 /*
@@ -358,8 +365,11 @@
 JNIEXPORT void JNICALL Java_com_oracle_dio_gpio_impl_GPIOPortImpl_assignPins0
   (JNIEnv* env, jobject obj, jobject cfg, jobjectArray pins) {
     jclass cfgClass = env->GetObjectClass(cfg);
-    jfieldID pinsField = env->GetFieldID(cfgClass, "pins", "[Lcom/oracle/dio/gpio/impl/GPIOPinFake;");
-    env->SetObjectField(cfg, pinsField, pins);
+    jfieldID pinsField = cfgClass ? env->GetFieldID(cfgClass, "pins", "[Lcom/oracle/dio/gpio/impl/GPIOPinFake;") :
+                                    NULL;
+    if (pinsField) {
+        env->SetObjectField(cfg, pinsField, pins);
+    }
 }
 
 
--- a/src/se/native/com/oracle/dio/i2cbus/impl/jni_i2c.cpp	Thu Aug 28 18:52:15 2014 +0400
+++ b/src/se/native/com/oracle/dio/i2cbus/impl/jni_i2c.cpp	Wed Sep 03 12:04:14 2014 -0400
@@ -45,38 +45,58 @@
   (JNIEnv* env, jobject obj, jobject config, jboolean exclusive) {
     jclass configClass = env->GetObjectClass(config);
 
-    jfieldID deviceNumberID = env->GetFieldID(configClass, "controllerNumber", "I");
-    jint deviceNumber = env->GetIntField(config, deviceNumberID);
+    jfieldID deviceNumberID = configClass ?
+            env->GetFieldID(configClass, "controllerNumber", "I") :
+            NULL;
+    jint deviceNumber = deviceNumberID ?
+            env->GetIntField(config, deviceNumberID) :
+            0;
 
-    jfieldID addressID = env->GetFieldID(configClass, "address", "I");
-    jint address = env->GetIntField(config, addressID);
+    jfieldID addressID = deviceNumberID ?
+            env->GetFieldID(configClass, "address", "I") :
+            NULL;
+    jint address = addressID ?
+            env->GetIntField(config, addressID) :
+            0;
 
-    jfieldID addressSizeID = env->GetFieldID(configClass, "addressSize", "I");
-    jint addressSize = env->GetIntField(config, addressSizeID);
+    jfieldID addressSizeID = addressID ?
+            env->GetFieldID(configClass, "addressSize", "I") :
+            NULL;
+    jint addressSize = addressSizeID ?
+            env->GetIntField(config, addressSizeID) :
+            0;
 
-    jfieldID clockFrequencyID = env->GetFieldID(configClass, "clockFrequency", "I");
-    jint clockFrequency = env->GetIntField(config, clockFrequencyID);
+    jfieldID clockFrequencyID = addressSizeID ?
+            env->GetFieldID(configClass, "clockFrequency", "I") :
+            NULL;
+    jint clockFrequency = clockFrequencyID ?
+            env->GetIntField(config, clockFrequencyID) :
+            0;
 
     javacall_handle handle = JAVACALL_INVALID_HANDLE;
-    javacall_dio_result result;
-    result = javacall_i2c_open_slave_with_config(deviceNumber, address,
-                                                 addressSize, clockFrequency,
-                                                 exclusive != JNI_FALSE ? JAVACALL_TRUE : JAVACALL_FALSE,
-                                                 &handle);
+    javacall_dio_result result = JAVACALL_DIO_FAIL;
+    if (clockFrequencyID) {
+        result = javacall_i2c_open_slave_with_config(deviceNumber, address,
+                                                     addressSize, clockFrequency,
+                                                     exclusive != JNI_FALSE ? JAVACALL_TRUE : JAVACALL_FALSE,
+                                                     &handle);
 
-    device_reference device = INVALID_DEVICE_REFERENCE;
-    if (result == JAVACALL_DIO_OK) {
-        device = createDeviceReference(handle, _i2c_close,
-                                       javacall_i2c_lock, javacall_i2c_unlock);
-        if (device == INVALID_DEVICE_REFERENCE) {
-            javacall_i2c_close(handle);
-            result = JAVACALL_DIO_OUT_OF_MEMORY;
-        } else {
-            result = saveDeviceReferenceToDeviceObject(env, obj, device);
+        device_reference device = INVALID_DEVICE_REFERENCE;
+        if (result == JAVACALL_DIO_OK) {
+            device = createDeviceReference(handle, _i2c_close,
+                                           javacall_i2c_lock, javacall_i2c_unlock);
+            if (device == INVALID_DEVICE_REFERENCE) {
+                javacall_i2c_close(handle);
+                result = JAVACALL_DIO_OUT_OF_MEMORY;
+            } else {
+                result = saveDeviceReferenceToDeviceObject(env, obj, device);
+            }
         }
     }
 
-    checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        checkJavacallFailure(env, result);
+    }
 }
 
 /*
@@ -109,23 +129,26 @@
     javacall_int32 bytesTransferred = 0;
     bool throwClosedException = true;
     env->MonitorEnter(obj);
-    device_reference device = getDeviceReferenceFromDeviceObject(env, obj);
-    if (device != INVALID_DEVICE_REFERENCE) {
-        javacall_handle handle = getDeviceHandle(device);
-        if (handle != JAVACALL_INVALID_HANDLE) {
-            result = javacall_i2c_transfer_start(handle,
-                                (javacall_i2c_message_type)flag,
-                                (write != JNI_FALSE ? JAVACALL_TRUE : JAVACALL_FALSE),
-                                (char*)(directArray + off + pos),
-                                lim - pos,
-                                &bytesTransferred);
-            if (result == JAVACALL_DIO_WOULD_BLOCK) {
-                retainDeviceReference(device);
+    device_reference device = INVALID_DEVICE_REFERENCE;
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        device = getDeviceReferenceFromDeviceObject(env, obj);
+        if (device != INVALID_DEVICE_REFERENCE) {
+            javacall_handle handle = getDeviceHandle(device);
+            if (handle != JAVACALL_INVALID_HANDLE) {
+                result = javacall_i2c_transfer_start(handle,
+                                    (javacall_i2c_message_type)flag,
+                                    (write != JNI_FALSE ? JAVACALL_TRUE : JAVACALL_FALSE),
+                                    (char*)(directArray + off + pos),
+                                    lim - pos,
+                                    &bytesTransferred);
+                if (result == JAVACALL_DIO_WOULD_BLOCK) {
+                    retainDeviceReference(device);
+                }
+                throwClosedException = false;
             }
-            throwClosedException = false;
         }
+        env->MonitorExit(obj);
     }
-    env->MonitorExit(obj);
 
     // If the call returns JAVACALL_DIO_WOULD_BLOCK, have to wait for a
     // completion signal.
@@ -141,23 +164,25 @@
                 // again, get synchronized, check the handle is valid
                 throwClosedException = true;
                 env->MonitorEnter(obj);
-                device = getDeviceReferenceFromDeviceObject(env, obj);
-                if (device != INVALID_DEVICE_REFERENCE) {
-                    javacall_handle handle = getDeviceHandle(device);
-                    if (handle != JAVACALL_INVALID_HANDLE) {
-                        result = javacall_i2c_transfer_finish(handle,
-                                         JAVACALL_FALSE,
-                                         (char*)(directArray + off + pos),
-                                         lim - pos,
-                                         &bytesTransferred);
-                        if (result != JAVACALL_DIO_OK) {
-                            // notified status has higher proirity
-                            result = (javacall_dio_result)(javacall_int32)status;
+                if (env->ExceptionCheck() == JNI_FALSE) {
+                    device = getDeviceReferenceFromDeviceObject(env, obj);
+                    if (device != INVALID_DEVICE_REFERENCE) {
+                        javacall_handle handle = getDeviceHandle(device);
+                        if (handle != JAVACALL_INVALID_HANDLE) {
+                            result = javacall_i2c_transfer_finish(handle,
+                                             JAVACALL_FALSE,
+                                             (char*)(directArray + off + pos),
+                                             lim - pos,
+                                             &bytesTransferred);
+                            if (result != JAVACALL_DIO_OK) {
+                                // notified status has higher proirity
+                                result = (javacall_dio_result)(javacall_int32)status;
+                            }
+                            throwClosedException = false;
                         }
-                        throwClosedException = false;
                     }
+                    env->MonitorExit(obj);
                 }
-                env->MonitorExit(obj);
             }
         }
     }
@@ -166,10 +191,12 @@
         env->ReleaseByteArrayElements(heapArray, directArray, 0);
     }
 
-    if (throwClosedException) {
-        throwClosedDeviceException(env);
-    } else {
-        checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        if (throwClosedException) {
+            throwClosedDeviceException(env);
+        } else {
+            checkJavacallFailure(env, result);
+        }
     }
 
     return bytesTransferred;
--- a/src/se/native/com/oracle/dio/spibus/impl/jni_spi.cpp	Thu Aug 28 18:52:15 2014 +0400
+++ b/src/se/native/com/oracle/dio/spibus/impl/jni_spi.cpp	Wed Sep 03 12:04:14 2014 -0400
@@ -67,8 +67,9 @@
             result = saveDeviceReferenceToDeviceObject(env, obj, device);
         }
     }
-
-    checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        checkJavacallFailure(env, result);
+    }
 }
 
 /*
@@ -154,22 +155,27 @@
     javacall_dio_result result = JAVACALL_DIO_OK;
     bool throwClosedException = true;
     env->MonitorEnter(obj);
-    device_reference device = getDeviceReferenceFromDeviceObject(env, obj);
-    if (device != INVALID_DEVICE_REFERENCE) {
-        javacall_handle handle = getDeviceHandle(device);
-        if (handle != JAVACALL_INVALID_HANDLE) {
-            result = javacall_spi_send_and_receive_start(
-                                handle,
-                                (const char*)(srcDirectArray + srcOff + srcPos),
-                                (char*)(dstDirectArray + dstOff + dstPos),
-                                srcLim - srcPos);
-            if (result == JAVACALL_DIO_WOULD_BLOCK) {
-                retainDeviceReference(device);
+    device_reference device = INVALID_DEVICE_REFERENCE;
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        device = getDeviceReferenceFromDeviceObject(env, obj);
+        if (device != INVALID_DEVICE_REFERENCE) {
+            javacall_handle handle = getDeviceHandle(device);
+            if (handle != JAVACALL_INVALID_HANDLE) {
+                result = javacall_spi_send_and_receive_start(
+                                    handle,
+                                    (const char*)(srcDirectArray + srcOff + srcPos),
+                                    (char*)(dstDirectArray + dstOff + dstPos),
+                                    srcLim - srcPos);
+                if (result == JAVACALL_DIO_WOULD_BLOCK) {
+                    retainDeviceReference(device);
+                }
+                throwClosedException = false;
             }
-            throwClosedException = false;
         }
+        env->MonitorExit(obj);
+    } else {
+        result = JAVACALL_DIO_FAIL;
     }
-    env->MonitorExit(obj);
 
     // If the call returns JAVACALL_WOULD_BLOCK, have to wait for a
     // completion signal.
@@ -185,24 +191,26 @@
                 // again, get synchronized, check the handle is valid
                 throwClosedException = true;
                 env->MonitorEnter(obj);
-                device = getDeviceReferenceFromDeviceObject(env, obj);
-                if (device != INVALID_DEVICE_REFERENCE) {
-                    javacall_handle handle = getDeviceHandle(device);
-                    if (handle != JAVACALL_INVALID_HANDLE) {
-                        result = javacall_spi_send_and_receive_finish(
-                                         handle,
-                                         JAVACALL_FALSE,
-                                         (const char*)(srcDirectArray + srcOff + srcPos),
-                                         (char*)(dstDirectArray + dstOff + dstPos),
-                                         dstLim - dstPos);
-                        if (result != JAVACALL_DIO_OK) {
-                            // the notified status has higher priority
-                            result = (javacall_dio_result)(javacall_int32)status;
+                if (env->ExceptionCheck() != JNI_TRUE) {
+                    device = getDeviceReferenceFromDeviceObject(env, obj);
+                    if (device != INVALID_DEVICE_REFERENCE) {
+                        javacall_handle handle = getDeviceHandle(device);
+                        if (handle != JAVACALL_INVALID_HANDLE) {
+                            result = javacall_spi_send_and_receive_finish(
+                                             handle,
+                                             JAVACALL_FALSE,
+                                             (const char*)(srcDirectArray + srcOff + srcPos),
+                                             (char*)(dstDirectArray + dstOff + dstPos),
+                                             dstLim - dstPos);
+                            if (result != JAVACALL_DIO_OK) {
+                                // the notified status has higher priority
+                                result = (javacall_dio_result)(javacall_int32)status;
+                            }
+                            throwClosedException = false;
                         }
-                        throwClosedException = false;
                     }
+                    env->MonitorExit(obj);
                 }
-                env->MonitorExit(obj);
             }
         }
     }
@@ -215,11 +223,12 @@
         env->ReleaseByteArrayElements(dstHeapArray, dstDirectArray,
                                       result == JAVACALL_DIO_OK ? 0 : JNI_ABORT);
     }
-
-    if (throwClosedException) {
-        throwClosedDeviceException(env);
-    } else {
-        checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        if (throwClosedException) {
+            throwClosedDeviceException(env);
+        } else {
+            checkJavacallFailure(env, result);
+        }
     }
 }
 
--- a/src/se/native/com/oracle/dio/uart/impl/jni_uart.cpp	Thu Aug 28 18:52:15 2014 +0400
+++ b/src/se/native/com/oracle/dio/uart/impl/jni_uart.cpp	Wed Sep 03 12:04:14 2014 -0400
@@ -108,7 +108,7 @@
 
     javacall_free(devName);
 
-    if (result == JAVACALL_DIO_OK) {
+    if (result == JAVACALL_DIO_OK && env->ExceptionCheck() == JNI_FALSE) {
         device_reference device;
         device = createDeviceReference(handle, uart_cleanup, javacall_uart_lock,
                                        javacall_uart_unlock);
@@ -121,7 +121,9 @@
 
     }
 
-    checkJavacallFailure(env, result);
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        checkJavacallFailure(env, result);
+    }
 }
 
 /*
@@ -209,28 +211,31 @@
     // thread. See the implementation of close(). Always check the handle is valid.
     // Do not generate ClosedDeviceException until all JNI calls are made.
     env->MonitorEnter(obj);
-    device_reference device = getDeviceReferenceFromDeviceObject(env, obj);
-    if (device != INVALID_DEVICE_REFERENCE) {
-        javacall_handle handle = getDeviceHandle(device);
-        if (handle != JAVACALL_INVALID_HANDLE) {
-            result = result = javacall_uart_write_start(handle,
-                                                        (unsigned char*)(directArray + pos + off),
-                                                        lim - pos,
-                                                        &bytesWritten,
-                                                        &context);
-            if (result == JAVACALL_DIO_WOULD_BLOCK) {
-                retainDeviceReference(device);
+    device_reference device = INVALID_DEVICE_REFERENCE;
+    if (env->ExceptionCheck() != JNI_TRUE) {
+        device = getDeviceReferenceFromDeviceObject(env, obj);
+        if (device != INVALID_DEVICE_REFERENCE) {
+            javacall_handle handle = getDeviceHandle(device);
+            if (handle != JAVACALL_INVALID_HANDLE) {
+                result = result = javacall_uart_write_start(handle,
+                                                            (unsigned char*)(directArray + pos + off),
+                                                            lim - pos,
+                                                            &bytesWritten,
+                                                            &context);
+                if (result == JAVACALL_DIO_WOULD_BLOCK) {
+                    retainDeviceReference(device);
+                }
+                throwClosedException = false;
             }
-            throwClosedException = false;
         }
+        env->MonitorExit(obj);
     }
-    env->MonitorExit(obj);
 
     do {
         if (result == JAVACALL_DIO_OK) {
             break;
         }
-        if (result != JAVACALL_DIO_WOULD_BLOCK) {
+        if (result != JAVACALL_DIO_WOULD_BLOCK && env->ExceptionCheck() != JNI_TRUE) {
             throwIOException(env, "writing to port has failed");
             break;
         }
@@ -249,28 +254,31 @@
         // again, get synchronized, check the handle is valid
         throwClosedException = true;
         env->MonitorEnter(obj);
-        device = device = getDeviceReferenceFromDeviceObject(env, obj);
-        if (device != INVALID_DEVICE_REFERENCE) {
-            javacall_handle handle = getDeviceHandle(device);
-            if (handle != JAVACALL_INVALID_HANDLE) {
-                result = result = javacall_uart_write_finish(handle,
-                                                             (unsigned char*)(directArray + pos + off),
-                                                             lim - pos,
-                                                             &bytesWritten,
-                                                             context);
-                if (result == JAVACALL_DIO_WOULD_BLOCK) {
-                    retainDeviceReference(device);
+        device = INVALID_DEVICE_REFERENCE;
+        if (env->ExceptionCheck() != JNI_TRUE) {
+            device = getDeviceReferenceFromDeviceObject(env, obj);
+            if (device != INVALID_DEVICE_REFERENCE) {
+                javacall_handle handle = getDeviceHandle(device);
+                if (handle != JAVACALL_INVALID_HANDLE) {
+                    result = result = javacall_uart_write_finish(handle,
+                                                                 (unsigned char*)(directArray + pos + off),
+                                                                 lim - pos,
+                                                                 &bytesWritten,
+                                                                 context);
+                    if (result == JAVACALL_DIO_WOULD_BLOCK) {
+                        retainDeviceReference(device);
+                    }
+                    throwClosedException = false;
                 }
-                throwClosedException = false;
             }
+            env->MonitorExit(obj);
         }
-        env->MonitorExit(obj);
     } while (1);
 
     if (heapArray != NULL && directArray != NULL) {
         env->ReleaseByteArrayElements(heapArray, directArray, JNI_ABORT);
     }
-    if (throwClosedException) {
+    if (throwClosedException && env->ExceptionCheck() != JNI_TRUE) {
         throwClosedDeviceException(env);
     }
     return bytesWritten;
--- a/src/share/linux/native/com/oracle/dio/uart/uart.c	Thu Aug 28 18:52:15 2014 +0400
+++ b/src/share/linux/native/com/oracle/dio/uart/uart.c	Wed Sep 03 12:04:14 2014 -0400
@@ -268,7 +268,7 @@
 
 static javacall_dio_result uart_open(const char *devName, serial_handle p) {
 
-    javacall_result2dio_result(jc_serial_open(devName, p));
+    return javacall_result2dio_result(jc_serial_open(devName, p));
 }
 
 /**