Use flock() to ensure exclusive access instead of TIOCEXCL

This commit is contained in:
hedgecrw85 2020-02-18 16:44:01 -06:00
parent ed126f4235
commit 349f0adffb
2 changed files with 28 additions and 82 deletions

View File

@ -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

View File

@ -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;