changeset 61:c69cb4805050

8066691: Expected UnavailableDeviceException is not thrown when again openning UART in EXCLUSIVE mode Summary: Open device list is kept for source compatibility with JavaME. File lock to prevent access from different process. Reviewed-by: snazarki Contributed-by: alexey.mironov@oracle.com
author snazarki
date Fri, 05 Dec 2014 19:57:58 +0400
parents 5d629ccf074a
children b583dbc924ea
files src/share/linux/native/com/oracle/dio/uart/serial.c src/share/linux/native/com/oracle/dio/uart/serial.h src/share/linux/native/com/oracle/dio/uart/uart.c src/share/linux/native/com/oracle/dio/utils/list_helper.c src/share/native/com/oracle/dio/list_helper.h
diffstat 5 files changed, 219 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/linux/native/com/oracle/dio/uart/serial.c	Thu Dec 04 14:49:18 2014 +0400
+++ b/src/share/linux/native/com/oracle/dio/uart/serial.c	Fri Dec 05 19:57:58 2014 +0400
@@ -24,12 +24,16 @@
  */
 
 #include "serial.h"
+#include "list_helper.h"
 
 typedef void *(thread_func)(void*);
 
 static void*           write_thread(void* arg);
 static void*           in_poll_thread(void* arg);
 
+static javacall_handle _dev_list = NULL;
+static pthread_mutex_t _list_mutex = PTHREAD_MUTEX_INITIALIZER;
+
 static javacall_result serial_create_thread(javacall_handle handle,
         thread_func func, pthread_t *thread);
 
@@ -117,6 +121,36 @@
     }
 }
 
+/*
+ * get serial config by device name
+ *
+ *@param device      pointer to device name
+ *
+ *@retval pointer to serial_descr if found or null if not
+ */
+static serial_handle get_config_by_name(const char* device_name) {
+
+    serial_handle next = NULL;
+    javacall_bool found = JAVACALL_FALSE;
+
+    if(lock_m(&_list_mutex) == JAVACALL_FAIL){
+        return NULL;
+    }
+
+    while(found == JAVACALL_FALSE && JAVACALL_OK == javautil_list_get_next(_dev_list, (javacall_handle*) &next)) {
+        if(javautil_strcmp(device_name, next->dev_name) == 0){
+            found = JAVACALL_TRUE;
+        };
+    }
+
+    unlock_m(&_list_mutex);
+    return (found == JAVACALL_TRUE?next:NULL);
+}
+
+javacall_result jc_serial_add_device(serial_handle p){
+    return add_dev_to_list(&_dev_list, &_list_mutex, p);
+}
+
 /**
  * See javacall_serial.h for definition
  */
@@ -229,6 +263,10 @@
     p->new_data_avail_cb = _new_data_avail_cb;
     p->write_complete_cb = _write_complete_cb;
 
+    if(jc_serial_add_device(p) != JAVACALL_OK){
+        javacall_serial_close_start(p, NULL);
+        return JAVACALL_FAIL;
+    }
     *pHandle = (javacall_handle)p;
 
     return JAVACALL_OK;
@@ -340,6 +378,8 @@
 
     cleanup_write_buffer(p);
     javautil_circular_buffer_destroy(p->inBuffer);
+    javacall_free(p->dev_name);
+    remove_dev_from_list(_dev_list, &_list_mutex, p);
     javacall_free(p);
 
     return JAVACALL_OK;
@@ -761,19 +801,53 @@
 
 javacall_result
 jc_serial_open(const char *devName, serial_handle p) {
-    char tmp[20] = "/dev/";
-    if (strlen(devName) >= sizeof(tmp) - strlen(tmp)) {
-        JAVACALL_REPORT_ERROR(JC_SERIAL, "Not enough room for device name");
-        return JAVACALL_FAIL;
-    }
-    strcat(tmp, devName);
-    //opening one of the /dev/ttyUSB devices, no pin busy check
-    if (-1 == (p->fd = open(tmp, O_RDWR | O_NOCTTY | O_NONBLOCK))) {
-        JAVACALL_REPORT_ERROR2(JC_SERIAL, "Can't open %s file errno %d",
-                tmp, errno);
+    struct flock lock;
+    char* dev_str = "/dev/";
+    int error_n;
+
+    if (strlen(devName) > 250) {
+        JAVACALL_REPORT_ERROR(JC_SERIAL, "Device name too long");
         return JAVACALL_FAIL;
     }
 
+    if(NULL == (p->dev_name = (char*)javacall_malloc(strlen(devName) + strlen(dev_str) + 1))){
+        JAVACALL_REPORT_ERROR(JC_SERIAL, "Not enough room for device name");
+        return JAVACALL_OUT_OF_MEMORY;
+    }
+
+    javautil_memset(p->dev_name, 0, strlen(devName) + strlen(dev_str) + 1);
+    javautil_strcat(p->dev_name, dev_str);
+    javautil_strcat(p->dev_name, devName);
+
+    if(get_config_by_name(p->dev_name) != NULL){
+        return JAVACALL_BUSY;
+    }
+    //opening one of the /dev/ttyUSB devices, no pin busy check
+    if (-1 == (p->fd = open(p->dev_name, O_RDWR | O_NOCTTY | O_NONBLOCK))) {
+        JAVACALL_REPORT_ERROR2(JC_SERIAL, "Can't open %s file errno %d",
+                p->dev_name, errno);
+        return JAVACALL_FAIL;
+    }
+    /*flock set an advisory lock*/
+    lock.l_type   = F_WRLCK;  /* exclusive lock*/
+    lock.l_whence = SEEK_SET;
+    lock.l_start  = 0;
+    lock.l_len    = 0;
+    lock.l_pid    = getpid();
+
+    if(-1 == fcntl(p->fd, F_SETLK, &lock)){
+        error_n = errno;
+        close(p->fd);
+        p->fd = -1;
+
+        if (error_n == EACCES || error_n == EAGAIN) {
+            JAVACALL_REPORT_ERROR1(JC_DIO, "[UART] Can't lock device. errno %d", errno);
+            return JAVACALL_BUSY;
+        }else{
+            JAVACALL_REPORT_ERROR1(JC_DIO, "[UART] Can't lock device. errno %d", errno);
+            return JAVACALL_FAIL;
+        }
+    }
     return JAVACALL_OK;
 }
 
--- a/src/share/linux/native/com/oracle/dio/uart/serial.h	Thu Dec 04 14:49:18 2014 +0400
+++ b/src/share/linux/native/com/oracle/dio/uart/serial.h	Fri Dec 05 19:57:58 2014 +0400
@@ -62,6 +62,7 @@
 
 typedef struct serial_descr{
     int                      fd;
+    char*                    dev_name;
     javacall_handle          inBuffer;
     pthread_t                inPollThread;
     pthread_mutex_t          lock;
@@ -89,7 +90,7 @@
 javacall_result jc_serial_init_buffers_threads(serial_handle sHandle);
 javacall_result jc_serial_read_common(serial_handle port, unsigned char* buffer,int bufferSize ,/*OUT*/int *bytesRead,/*OUT*/int *bytesAvailable);
 javacall_result jc_serial_write_common(serial_handle port,  unsigned char* buffer, int size, int *bytesMoved);
-
+javacall_result jc_serial_add_device(serial_handle p);
 javacall_result jc_serial_open(const char *devName, serial_handle p);
 int             baud_to_int(speed_t baud);
 speed_t         int_to_baud(int baud);
--- a/src/share/linux/native/com/oracle/dio/uart/uart.c	Thu Dec 04 14:49:18 2014 +0400
+++ b/src/share/linux/native/com/oracle/dio/uart/uart.c	Fri Dec 05 19:57:58 2014 +0400
@@ -82,6 +82,7 @@
         case JAVACALL_OK: dio_result = JAVACALL_DIO_OK;break;
         case JAVACALL_FAIL: dio_result = JAVACALL_DIO_FAIL;break;
         case JAVACALL_WOULD_BLOCK: dio_result = JAVACALL_DIO_WOULD_BLOCK;break;
+        case JAVACALL_BUSY: dio_result = JAVACALL_DIO_BUSY;break;
         default: dio_result= JAVACALL_DIO_FAIL;
     }
     return dio_result;
@@ -195,8 +196,7 @@
 javacall_uart_start_event_listening(javacall_handle handle, javacall_uart_event_type eventId) {
 
     uart_handle port = (uart_handle)handle;
-    javacall_int32 dataAvailable=0;
-    javacall_int32 freeSize=0;
+    javacall_int32 dataAvailable=0,freeSize=0;
 
     switch (eventId) {
     case INPUT_DATA_AVAILABLE:
@@ -487,7 +487,10 @@
     p->buffer_overrun_cb = _buffer_overrun_cb;
     p->new_data_avail_cb = _new_data_avail_cb;
     p->write_complete_cb = _write_complete_cb;
-
+    if(JAVACALL_OK != (res = jc_serial_add_device(p))){
+        javacall_uart_close_start(p, NULL);
+        return res;
+    }
     *pHandle = (javacall_handle)p;
 
     return JAVACALL_DIO_OK;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/linux/native/com/oracle/dio/utils/list_helper.c	Fri Dec 05 19:57:58 2014 +0400
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "list_helper.h"
+#include "javacall_logging.h"
+
+#include <errno.h>
+
+javacall_result lock_m(pthread_mutex_t *pM){
+    if(pthread_mutex_lock(pM)!=0) {
+        JAVACALL_REPORT_ERROR2(JC_DIO, "lock mutex errno=%d: %s\n", errno, strerror(errno));
+        return JAVACALL_FAIL;
+    }
+    return JAVACALL_OK;
+}
+
+javacall_result unlock_m(pthread_mutex_t *pM){
+    if(pthread_mutex_unlock(pM)!=0){
+        JAVACALL_REPORT_ERROR2(JC_DIO, "unlock mutex errno=%d: %s\n", errno, strerror(errno));
+        return JAVACALL_FAIL;
+    }
+    return JAVACALL_OK;
+}
+
+javacall_result add_dev_to_list(javacall_handle* plistHandle, pthread_mutex_t *mutex, javacall_handle dev){
+    javacall_result res = JAVACALL_OK;
+    javacall_int32 size;
+
+    if(lock_m(mutex) == JAVACALL_FAIL){
+        return JAVACALL_FAIL;
+    }
+
+    if(*plistHandle == NULL){
+        if(JAVACALL_OK != (res = javautil_list_create(plistHandle))){
+            JAVACALL_REPORT_ERROR(JC_DIO, "cannot create device list");
+        }
+    }
+    if(res == JAVACALL_OK){
+        res = javautil_list_add(*plistHandle, dev);
+    }
+    unlock_m(mutex);
+
+    return res;
+}
+
+javacall_result remove_dev_from_list(javacall_handle listHandle, pthread_mutex_t *mutex, javacall_handle dev){
+    javacall_result res;
+
+    if(lock_m(mutex) == JAVACALL_FAIL){
+        return JAVACALL_FAIL;
+    }
+    res = javautil_list_remove(listHandle, dev);
+    unlock_m(mutex);
+
+    return res;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/native/com/oracle/dio/list_helper.h	Fri Dec 05 19:57:58 2014 +0400
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef _LIST_HELPER_H
+#define _LIST_HELPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "javautil_linked_list.h"
+#include <pthread.h>
+
+javacall_result lock_m(pthread_mutex_t *pM);
+
+javacall_result unlock_m(pthread_mutex_t *pM);
+
+javacall_result add_dev_to_list(javacall_handle* listHandle, pthread_mutex_t *mutex, javacall_handle dev);
+
+javacall_result remove_dev_from_list(javacall_handle listHandle, pthread_mutex_t *mutex, javacall_handle dev);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _LIST_HELPER_H