changeset 71:e937a3e81707

8067665: [UART] cannot send big buffer if subscribed to UARTEvent.OUTPUT_BUFFER_EMPTY Summary: Nonblocking write method was introduced Reviewed-by: snazarki Contributed-by: alexey.mironov@oracle.com
author snazarki
date Wed, 17 Dec 2014 19:12:52 +0400
parents 081bed253c1e
children 93bc1f742193
files src/se/native/com/oracle/dio/uart/impl/jni_uart.cpp src/share/classes/com/oracle/dio/uart/impl/UARTImpl.java src/share/linux/native/com/oracle/dio/uart/serial.c src/share/linux/native/com/oracle/dio/uart/uart.c src/share/native/com/oracle/dio/javacall_uart.h
diffstat 5 files changed, 132 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/src/se/native/com/oracle/dio/uart/impl/jni_uart.cpp	Wed Dec 17 19:06:44 2014 +0400
+++ b/src/se/native/com/oracle/dio/uart/impl/jni_uart.cpp	Wed Dec 17 19:12:52 2014 +0400
@@ -189,11 +189,11 @@
         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);
+                result = javacall_uart_write_start(handle,
+                                                   (unsigned char*)(directArray + pos + off),
+                                                   lim - pos,
+                                                   &bytesWritten,
+                                                   &context);
                 if (result == JAVACALL_DIO_WOULD_BLOCK) {
                     retainDeviceReference(device);
                 }
@@ -232,11 +232,11 @@
             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);
+                    result = javacall_uart_write_finish(handle,
+                                                        unsigned char*)(directArray + pos + off),
+                                                        lim - pos,
+                                                        &bytesWritten,
+                                                        context);
                     if (result == JAVACALL_DIO_WOULD_BLOCK) {
                         retainDeviceReference(device);
                     }
@@ -258,6 +258,59 @@
 
 /*
  * Class:     com_oracle_dio_uart_impl_UARTImpl
+ * Method:    writeAsynch0
+ */
+JNIEXPORT void JNICALL com_oracle_dio_uart_impl_UARTImpl_writeAsynch0
+  (JNIEnv* env, jobject obj, jobject src) {
+
+    jint pos = 0, cap = 0, off = 0, lim = 0;
+    jboolean readonly = JNI_TRUE;
+    jbyte *directArray = NULL;
+    jbyteArray heapArray = NULL;
+    if (!getByteBufferInformation(env, src, &directArray, &heapArray,
+                                  &off, &pos, &cap, &lim,
+                                  &readonly)) {
+        env->ExceptionClear();
+        throwRuntimeException(env, "fault source buffer");
+    }
+    if (heapArray != NULL) {
+        directArray = env->GetByteArrayElements(heapArray, NULL);
+    }
+
+    jint bytesWritten = 0;
+    javacall_dio_result result = JAVACALL_DIO_OK;
+    javacall_handle context = NULL;
+    bool throwClosedException = true;
+
+    // Get synchronized with the object to avoid closing the handle by another
+    // 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 = 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_uart_write_async(handle,
+                                                   (unsigned char*)(directArray + pos + off),
+                                                   lim - pos);
+                throwClosedException = false;
+            }
+        }
+        env->MonitorExit(obj);
+    }
+
+    switch (result) {
+        case JAVACALL_DIO_OK:
+        break;
+        default:
+            throwIOException(env, "writing to port has failed");
+    }
+}
+
+/*
+ * Class:     com_oracle_dio_uart_impl_UARTImpl
  * Method:    read0
  */
 JNIEXPORT jint JNICALL Java_com_oracle_dio_uart_impl_UARTImpl_read0
--- a/src/share/classes/com/oracle/dio/uart/impl/UARTImpl.java	Wed Dec 17 19:06:44 2014 +0400
+++ b/src/share/classes/com/oracle/dio/uart/impl/UARTImpl.java	Wed Dec 17 19:12:52 2014 +0400
@@ -328,15 +328,7 @@
                         //keep writing from the second buffer before user notice
                         if(isWriting){
                             if (buffer.hasRemaining()){
-                                 /* since write0 needs to be called by the following manner:
-                                 * int bytesWritten = write0(buffer.slice());
-                                 * buffer.position(buffer.position() + bytesWritten);
-                                 *
-                                 * but because write0 is calling inside processEvent as part of asynchronous write,
-                                 * bytesWritten = 0
-                                 * write0 returns immediatelly after copy data to javacall buffer.
-                                 */
-                                write0(buffer);
+                                writeAsynch0(buffer);
                             }
                         }
                         //notify user
@@ -355,7 +347,7 @@
                         }
                         if(isWriting){
                             if (buffer.hasRemaining()){
-                                write0(buffer);
+                                writeAsynch0(buffer);
                             }
                         }
                     }//end of else 1 buffer
@@ -495,7 +487,7 @@
     @Override
     public synchronized void setParity(int parity) throws IOException, UnavailableDeviceException, ClosedDeviceException{
         checkPowerState();
-        setParity0( parity);
+        setParity0(parity);
     }
 
     /**
@@ -505,7 +497,7 @@
     @Override
     public synchronized void setStopBits(int stopBits) throws IOException, UnavailableDeviceException, ClosedDeviceException{
         checkPowerState();
-        setStopBits0( stopBits);
+        setStopBits0(stopBits);
     }
 
     /**
@@ -524,7 +516,7 @@
         writeBufferIdx = 0;
         outRoundListener = listener;
         subscribe(UARTEvent.OUTPUT_BUFFER_EMPTY);
-        write0(src);
+        writeAsynch0(src);
         isWriting = true;
     }
 
@@ -650,6 +642,10 @@
             UnavailableDeviceException, ClosedDeviceException{
         int ret;
 
+        synchronized(this){
+            checkRead();
+        }
+
         synchronized(handle){
 
             if (dst == null){
@@ -661,21 +657,17 @@
             if(!dst.hasRemaining()){
                 ret = 0;
             }else{
-
                 ret = dst.position();
                 /*read all data available*/
                 int readRes = read0(dst);
                 shiftBufferPosition(dst, ret + readRes);
-                if(UARTEventHandler.getInstance().isDispatchThread() ){
+                if (dst.hasRemaining()) {
+                    if (!UARTEventHandler.getInstance().isDispatchThread()) {
                     /*
-                        the user calls read() from the event callback,
-                        exit immediatelly
+                     * the user calls read() from the event callback,
+                     * exit immediatelly,
+                     * else read with timeout
                      */
-                }else{
-                    /*
-                        start asynch read with timer
-                    */
-                    if(dst.hasRemaining()){
                         startReading(dst, getLocalInputRoundListener());
                         synchronized(synchReadLock){
                             try{
@@ -683,13 +675,13 @@
                             }catch(InterruptedException iE){
                                 throw new IOException();
                             }
-                        } //synch
+                        } // synch
                         stopReading();
                     }
-                }// else if isDispatchThread()
-                ret = dst.position() - ret;
-            }//if(dst.hasRemaining())
-        }//synch handle
+                } // if !event thread
+            } // if has Remaining
+            ret = dst.position() - ret;
+        } // synch handle
         return ret==0?-1:ret;
     }
 
@@ -801,6 +793,10 @@
      */
     private native int write0(ByteBuffer src);
     /*
+     * starts asynch write session
+     */
+    private native void writeAsynch0(ByteBuffer src);
+    /*
      * read0 does not shift the buffer's position, it only returns bytes read.
      */
     private native int read0(ByteBuffer src);
--- a/src/share/linux/native/com/oracle/dio/uart/serial.c	Wed Dec 17 19:06:44 2014 +0400
+++ b/src/share/linux/native/com/oracle/dio/uart/serial.c	Wed Dec 17 19:12:52 2014 +0400
@@ -45,7 +45,7 @@
     }
 }
 
-char* skipDelimiters(char* ptr) {
+const char* skipDelimiters(const char* ptr) {
     char ch = *ptr;
     // skip Delimiters
     while (' ' == ch) {
@@ -56,7 +56,7 @@
 }
 
 /** CLDC spec req: only alphabet and digits */
-int checkName(char* name) {
+int checkName(const char* name) {
     char ch = *name;
     while (0 != ch) {
         if (!(('a' <= ch && ch <= 'z') ||
@@ -70,7 +70,7 @@
     return 1;
 }
 
-char* getNextDelimiterPtr(char* prefixList) {
+const char* getNextDelimiterPtr(const char* prefixList) {
     char ch = *prefixList;
     while (0 != ch && ' ' != ch ) {
         prefixList++;
@@ -80,7 +80,7 @@
 }
 
 /* fills provided {@code dst} buffer with file names from {@code /dev} folder that matches prefixes from comma separated {@code prefix} list */
-void getDeviceList(char* dst, size_t dstLen, char* prefix) {
+void getDeviceList(char* dst, size_t dstLen, const char* prefix) {
     int found = 0;
     *dst = 0;
     DIR* dir = opendir("/dev");
@@ -88,7 +88,7 @@
         struct dirent* de;
         while (NULL != (de = readdir(dir))) {
             if (!(de->d_type & DT_DIR)) {
-                char* curPrefix = prefix;
+                const char* curPrefix = prefix;
                 // retuns curPrefix if no more templates found
                 char* nextPrefix = getNextDelimiterPtr(curPrefix);
 
@@ -158,7 +158,7 @@
         int maxBufLen) {
 
     int i, len, totalCount;
-    char *devPrefix;
+    const char *devPrefix;
     javacall_result res;
 
     JAVACALL_REPORT_INFO(JC_SERIAL, "Checking what serial ports are available");
@@ -461,14 +461,14 @@
     serial_handle p = (serial_handle)handle;
     javacall_result result = JAVACALL_FAIL;
 
-        /*
-       write_thread write result stored in out_buffer_offset
-           if synch operations
-    */
+    /*
+     * write_thread write result stored in out_buffer_offset
+     * if synch operations
+     */
     *bytesWritten = p->out_total_written;
     /*
-        all incoming java buffer is written
-    */
+     * all incoming java buffer is written
+     */
     if(size == p->out_total_written){
         p->write_complete_cb(p, 0, JAVACALL_OK);
         cleanup_write_buffer(p);
--- a/src/share/linux/native/com/oracle/dio/uart/uart.c	Wed Dec 17 19:06:44 2014 +0400
+++ b/src/share/linux/native/com/oracle/dio/uart/uart.c	Wed Dec 17 19:12:52 2014 +0400
@@ -37,6 +37,7 @@
     SERIAL_DESC              serial_descr;
     volatile int             subscribedEvents;
     volatile int             notifiedEvents;
+    javacall_bool            async_write_ongoing;
 } UART_DESC, *uart_handle;
 
 typedef void *(thread_func)(void*);
@@ -50,7 +51,8 @@
             javanotify_uart_event(OUTPUT_BUFFER_EMPTY, handle, param, res);
             port->notifiedEvents |= SERIAL_OUT_EMPTY;
         }
-    }else{
+    }
+    if (port->async_write_ongoing == JAVACALL_FALSE){
         javanotify_serial_event(JAVACALL_EVENT_SERIAL_WRITE, handle, res);
     }
 }
@@ -165,10 +167,6 @@
 
     javacall_result result = jc_serial_write_common(handle, buffer, size, bytesWritten);
 
-    if(JAVACALL_WOULD_BLOCK == result && ((uart_handle)handle)->subscribedEvents & SERIAL_OUT_EMPTY){
-        //case of asynch operation no WOULD_BLOCK
-        result = JAVACALL_OK;
-    }
     return javacall_result2dio_result(result);
 }
 
@@ -182,7 +180,23 @@
 
     javacall_result result = jc_serial_write_common(handle, buffer, size, bytesWritten);
 
-    if(JAVACALL_WOULD_BLOCK == result && ((uart_handle)handle)->subscribedEvents & SERIAL_OUT_EMPTY){
+    return javacall_result2dio_result(result);
+}
+
+/**
+ * See javacall_uart.h for definition
+ */
+javacall_dio_result
+javacall_uart_write_async(javacall_handle handle, unsigned char* buffer, int size) {
+
+    int bytesWritten;
+    ((serial_handle)handle)->out_total_written = 0;
+    ((uart_handle)handle)->async_write_ongoing = JAVACALL_TRUE;
+    ((uart_handle)handle)->notifiedEvents &= ~SERIAL_OUT_EMPTY;
+
+    javacall_result result = jc_serial_write_common(handle, buffer, size, &bytesWritten);
+
+    if(JAVACALL_WOULD_BLOCK == result){
         // case of asynch operation no WOULD_BLOCK
         result = JAVACALL_OK;
     }
@@ -522,6 +536,7 @@
         void *value;
     serial_handle p = (serial_handle)handle;
 
+    ((uart_handle)handle)->async_write_ongoing = JAVACALL_FALSE;
     uint64_t c = 1;
     int r;
     if(0 != p->write_thread){
--- a/src/share/native/com/oracle/dio/javacall_uart.h	Wed Dec 17 19:06:44 2014 +0400
+++ b/src/share/native/com/oracle/dio/javacall_uart.h	Wed Dec 17 19:12:52 2014 +0400
@@ -263,6 +263,19 @@
 javacall_uart_write_finish(javacall_handle hPort, unsigned char* buffer, int size, int *bytesWritten, void *context);
 
 /**
+ * starts asynchronous writing a specified number of bytes to serial link,
+ * function MUST return ASAP.
+ *
+ * @param hPort the port to write the data to
+ * @param buffer buffer to write data from
+ * @param size number of bytes to be write.
+ * @retval JAVACALL_OK          success
+ * @retval JAVACALL_FAIL        if there was an error
+ */
+javacall_dio_result /*OPTIONAL*/
+javacall_uart_write_async(javacall_handle hPort, unsigned char* buffer, int size);
+
+/**
  * Update the stopBits of an open uart port
  *
  * @param hPort the port to configure