From 349f0adffbe6bf26b9df70847fe76d50ec866c11 Mon Sep 17 00:00:00 2001 From: hedgecrw85 Date: Tue, 18 Feb 2020 16:44:01 -0600 Subject: [PATCH] Use flock() to ensure exclusive access instead of TIOCEXCL --- src/main/c/Android/jni/SerialPort_Android.c | 12 ++- src/main/c/Posix/SerialPort_Posix.c | 98 +++++---------------- 2 files changed, 28 insertions(+), 82 deletions(-) diff --git a/src/main/c/Android/jni/SerialPort_Android.c b/src/main/c/Android/jni/SerialPort_Android.c index b925edc..c789a3b 100644 --- a/src/main/c/Android/jni/SerialPort_Android.c +++ b/src/main/c/Android/jni/SerialPort_Android.c @@ -2,7 +2,7 @@ * SerialPort_Android.c * * Created on: Mar 13, 2015 - * Last Updated on: Jan 21, 2020 + * Last Updated on: Feb 18, 2020 * Author: Will Hedgecock * * Copyright (C) 2012-2020 Fazecast, Inc. @@ -176,6 +176,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative( else { // Close the port if there was a problem setting the parameters + tcdrain(serialPortFD); while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); @@ -457,11 +458,9 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(J int numBytesAvailable = -1; if ((serialPortFD > 0) && (ioctl(serialPortFD, FIONREAD, &numBytesAvailable) == -1)) { - // Problem detected, allow others to open the port and close it ourselves - ioctl(serialPortFD, TIOCNXCL); + // Problem detected, close the port tcdrain(serialPortFD); while (((*env)->GetBooleanField(env, obj, isOpenedField)) && (close(serialPortFD) == -1) && (errno != EBADF)); - serialPortFD = -1; (*env)->SetLongField(env, obj, serialPortFdField, -1l); (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); } @@ -579,8 +578,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn do { numBytesWritten = write(serialPortFD, writeBuffer+offset, bytesToWrite); } while ((numBytesWritten < 0) && (errno == EINTR)); if ((numBytesWritten == -1) || ((numBytesWritten == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1))) { - // Problem writing, allow others to open the port and close it ourselves - ioctl(serialPortFD, TIOCNXCL); + // Problem writing, close the port ioctl(serialPortFD, TCSBRK, 1); while (((*env)->GetBooleanField(env, obj, isOpenedField)) && (close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; @@ -589,7 +587,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn } // Wait until all bytes were written in write-blocking mode - if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) > 0) + if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) > 0) && (serialPortFD > 0)) ioctl(serialPortFD, TCSBRK, 1); // Return number of bytes written if successful diff --git a/src/main/c/Posix/SerialPort_Posix.c b/src/main/c/Posix/SerialPort_Posix.c index de1ca6b..60b3081 100644 --- a/src/main/c/Posix/SerialPort_Posix.c +++ b/src/main/c/Posix/SerialPort_Posix.c @@ -2,7 +2,7 @@ * SerialPort_Posix.c * * Created on: Feb 25, 2012 - * Last Updated on: Jan 21, 2020 + * Last Updated on: Feb 18, 2020 * Author: Will Hedgecock * * Copyright (C) 2012-2020 Fazecast, Inc. @@ -259,7 +259,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative( // Ensure that multiple root users cannot access the device simultaneously if (flock(serialPortFD, LOCK_EX | LOCK_NB) == -1) { - while ((close(serialPortFD) == -1) && (errno != EBADF)); + while ((close(serialPortFD) == -1) && (errno == EINTR)); serialPortFD = -1; } else @@ -288,9 +288,8 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative( else { // Close the port if there was a problem setting the parameters - ioctl(serialPortFD, TIOCNXCL); tcdrain(serialPortFD); - while ((close(serialPortFD) == -1) && (errno != EBADF)); + while ((close(serialPortFD) == -1) && (errno == EINTR)); serialPortFD = -1; (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); } @@ -344,17 +343,14 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J options.c_iflag |= (INPCK | IGNPAR); options.c_iflag |= (XonXoffInEnabled | XonXoffOutEnabled); - // Set baud rate + // Set baud rate and apply changes baud_rate baudRateCode = getBaudRateCode(baudRate); unsigned char nonStandardBaudRate = (baudRateCode == 0); if (nonStandardBaudRate) baudRateCode = B38400; cfsetispeed(&options, baudRateCode); cfsetospeed(&options, baudRateCode); - - // Apply changes and block non-root users from opening this port int retVal = configDisabled ? 0 : tcsetattr(serialPortFD, TCSANOW, &options); - ioctl(serialPortFD, TIOCEXCL); // Attempt to set the transmit buffer size and any necessary custom baud rates #if defined(__linux__) @@ -514,11 +510,6 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat if (serialPortFD <= 0) return JNI_TRUE; - // Allow others to open the port - ioctl(serialPortFD, TIOCNXCL); - tcdrain(serialPortFD); - (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); - // Force the port to enter non-blocking mode to ensure that any current reads return struct termios options = {0}; tcgetattr(serialPortFD, &options); @@ -528,37 +519,32 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat options.c_cc[VTIME] = 0; int retVal = fcntl(serialPortFD, F_SETFL, flags); tcsetattr(serialPortFD, TCSANOW, &options); + tcdrain(serialPortFD); // Close the port - flock(serialPortFD, LOCK_UN); - while ((close(serialPortFD) == -1) && (errno != EBADF)); + flock(serialPortFD, LOCK_UN | LOCK_NB); + while (((*env)->GetBooleanField(env, obj, isOpenedField)) && (close(serialPortFD) == -1) && (errno == EINTR)) + errno = 0; (*env)->SetLongField(env, obj, serialPortFdField, -1l); + (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); return JNI_TRUE; } JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(JNIEnv *env, jobject obj, jlong serialPortFD) { + // Retrieve bytes available to read and close port upon error int numBytesAvailable = -1; if ((serialPortFD > 0) && (ioctl(serialPortFD, FIONREAD, &numBytesAvailable) == -1)) - { - // Problem detected, allow others to open the port and close it ourselves - ioctl(serialPortFD, TIOCNXCL); - tcdrain(serialPortFD); - while (((*env)->GetBooleanField(env, obj, isOpenedField)) && (close(serialPortFD) == -1) && (errno != EBADF)); - serialPortFD = -1; - (*env)->SetLongField(env, obj, serialPortFdField, -1l); - (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); - } - + Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD); return numBytesAvailable; } JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAwaitingWrite(JNIEnv *env, jobject obj, jlong serialPortFD) { + // Retrieve bytes awaiting write and close port upon error int numBytesToWrite = -1; - if (serialPortFD > 0) - ioctl(serialPortFD, TIOCOUTQ, &numBytesToWrite); - + if ((serialPortFD > 0) && (ioctl(serialPortFD, TIOCOUTQ, &numBytesToWrite) == -1)) + Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD); return numBytesToWrite; } @@ -581,13 +567,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1))) { - // Problem reading, allow others to open the port and close it ourselves - ioctl(serialPortFD, TIOCNXCL); - tcdrain(serialPortFD); - while (((*env)->GetBooleanField(env, obj, isOpenedField)) && (close(serialPortFD) == -1) && (errno != EBADF)); - serialPortFD = -1; - (*env)->SetLongField(env, obj, serialPortFdField, -1l); - (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); + // Problem reading, close the port + Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD); break; } @@ -614,13 +595,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1))) { - // Problem reading, allow others to open the port and close it ourselves - ioctl(serialPortFD, TIOCNXCL); - tcdrain(serialPortFD); - while (((*env)->GetBooleanField(env, obj, isOpenedField)) && (close(serialPortFD) == -1) && (errno != EBADF)); - serialPortFD = -1; - (*env)->SetLongField(env, obj, serialPortFdField, -1l); - (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); + // Problem reading, close the port + Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD); break; } @@ -638,13 +614,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer, bytesToRead); } while ((numBytesRead < 0) && (errno == EINTR)); if ((numBytesRead == -1) || ((numBytesRead == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1))) { - // Problem reading, allow others to open the port and close it ourselves - ioctl(serialPortFD, TIOCNXCL); - tcdrain(serialPortFD); - while (((*env)->GetBooleanField(env, obj, isOpenedField)) && (close(serialPortFD) == -1) && (errno != EBADF)); - serialPortFD = -1; - (*env)->SetLongField(env, obj, serialPortFdField, -1l); - (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); + // Problem reading, close the port + Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD); } else numBytesReadTotal = numBytesRead; @@ -664,42 +635,19 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn jbyte *writeBuffer = (*env)->GetByteArrayElements(env, buffer, 0); int numBytesWritten, result = 0, ioctlResult = 0; - // Set the DTR line to high if using RS-422 - //ioctl(serialPortFD, TIOCMGET, &result); - //result |= TIOCM_DTR; - //ioctl(serialPortFD, TIOCMSET, &result); - // Write to port do { numBytesWritten = write(serialPortFD, writeBuffer+offset, bytesToWrite); } while ((numBytesWritten < 0) && (errno == EINTR)); if ((numBytesWritten == -1) || ((numBytesWritten == 0) && (ioctl(serialPortFD, FIONREAD, &ioctlResult) == -1))) { - // Problem writing, allow others to open the port and close it ourselves - ioctl(serialPortFD, TIOCNXCL); - tcdrain(serialPortFD); - while (((*env)->GetBooleanField(env, obj, isOpenedField)) && (close(serialPortFD) == -1) && (errno != EBADF)); + // Problem writing, close the port + Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD); serialPortFD = -1; - (*env)->SetLongField(env, obj, serialPortFdField, -1l); - (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); } // Wait until all bytes were written in write-blocking mode - if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) > 0) + if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) > 0) && (serialPortFD > 0)) tcdrain(serialPortFD); - // Clear the DTR line if using RS-422 -//#ifdef TIOCSERGETLSR - //do - //{ - //result = ioctl(serialPortFD, TIOCSERGETLSR); - //if (result != TIOCSER_TEMT) - //usleep(100); - //} while (result != TIOCSER_TEMT); -//#endif - //ioctl(serialPortFD, TIOCMGET, &result); - //result &= ~TIOCM_DTR; - //ioctl(serialPortFD, TIOCMSET, &result); - //do { result = tcflush(serialPortFD, TCIFLUSH); } while ((result < 0) && (errno == EINTR)); - // Return number of bytes written if successful (*env)->ReleaseByteArrayElements(env, buffer, writeBuffer, JNI_ABORT); return numBytesWritten;