NeuronRobotics / nrjavaserial

A Java Serial Port system. This is a fork of the RXTX project that uses in jar loading of the native code.
Other
344 stars 143 forks source link

Error "File exists. It is mine" when calling CommPortIdentifier.getPortIdentifiers() with open port #166

Closed wborn closed 4 years ago

wborn commented 4 years ago

When using v3.19.0 (and earlier) on Linux x86_64 we see the following errors printed:

testRead() Lock file failed
RXTX fhs_lock() Error: opening lock file: /var/lock/LCK..ttyUSB0: File exists. It is mine

It occurs when calling CommPortIdentifier.getPortIdentifiers() with an open (locked) connection while gnu.io.rxtx.SerialPorts isn't set so the library registers scanned ports:

https://github.com/NeuronRobotics/nrjavaserial/blob/13fd9e19e5d03bcf8d52e694675311bdbcddf45f/src/main/java/gnu/io/RXTXCommDriver.java#L413-L422

We call this method to see what the available serial ports are so we have an up to date list of identifiers so the user can select between available ports in the UI.

wborn commented 4 years ago

I've made this example which reproduces the issue. It prints all available ports, opens a port after 2 secs and then prints all available ports every 5 secs.

package example;

import java.util.Enumeration;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import gnu.io.CommPortIdentifier;

public class Main {

    private static final Lock LOCK = new ReentrantLock();
    private static final String PORT = "/dev/ttyUSB0";

    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(Main::printPortIdentifiers);
        thread.start();

        Thread.sleep(2000L);

        CommPortIdentifier id = CommPortIdentifier.getPortIdentifier(PORT);
        id.open(Main.class.getSimpleName(), 5000);

        System.out.println("Opened: " + PORT);

        LOCK.lock();
    }

    @SuppressWarnings("unchecked")
    private static void printPortIdentifiers() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                Enumeration<CommPortIdentifier> ids = CommPortIdentifier.getPortIdentifiers();
                System.out.println("--- Port Identifiers ---");
                while (ids.hasMoreElements()) {
                    System.out.println("name: " + ids.nextElement().getName());
                }
                System.out.println();
                Thread.sleep(5000L);
            }
        } catch (InterruptedException e) {
            System.out.println("Thread interrupted");
        }
    }
}

The output is:

--- Port Identifiers ---
name: /dev/ttyUSB0

Opened: /dev/ttyUSB0
RXTX fhs_lock() Error: opening lock file: /var/lock/LCK..ttyUSB0: File exists. It is mine

 testRead() Lock file failed
--- Port Identifiers ---

RXTX fhs_lock() Error: opening lock file: /var/lock/LCK..ttyUSB0: File exists. It is mine

 testRead() Lock file failed
--- Port Identifiers ---

RXTX fhs_lock() Error: opening lock file: /var/lock/LCK..ttyUSB0: File exists. It is mine

 testRead() Lock file failed
--- Port Identifiers ---

RXTX fhs_lock() Error: opening lock file: /var/lock/LCK..ttyUSB0: File exists. It is mine

 testRead() Lock file failed
--- Port Identifiers ---
wborn commented 4 years ago

As workaround for this we currently use a recompiled version (see this Maven repo) that doesn't use lockfiles (-DDISABLE_LOCKFILES).

When running the same example with this workaround it will not print error messages and the opened port is still part of the getPortIdentifiers() result:

--- Port Identifiers ---
name: /dev/ttyUSB0

Opened: /dev/ttyUSB0
--- Port Identifiers ---
name: /dev/ttyUSB0

--- Port Identifiers ---
name: /dev/ttyUSB0

--- Port Identifiers ---
name: /dev/ttyUSB0

--- Port Identifiers ---
name: /dev/ttyUSB0

I would prefer to keep using the lockfiles but also have a complete list of identifiers returned without any errors.

madhephaestus commented 4 years ago

I just pushed a code chang and binaries. Can you jar it and test on your end, or do i need to do a full maven release?

wborn commented 4 years ago

Thanks for the quick changes! :+1: I will give it a test by building the JARs myself using Gradle.

wborn commented 4 years ago

With the changes I see that it is now causing less error messages but still some. Also the locked port is still missing from the result:

--- Port Identifiers ---
name: /dev/ttyUSB0

Opened: /dev/ttyUSB0
 testRead() Lock file failed
--- Port Identifiers ---

 testRead() Lock file failed
--- Port Identifiers ---

 testRead() Lock file failed
--- Port Identifiers ---

 testRead() Lock file failed
--- Port Identifiers ---
madhephaestus commented 4 years ago

@wborn my understanding is: that is expected behavior. The list is of availible ports, and since the port is open, it isn't availible.

madhephaestus commented 4 years ago

I did just check that it can see any other ports connected, and leaves the connected port out of the list. I removed the testRead() print statement too and pushed new binaries for you to try.

wborn commented 4 years ago

Thanks! I will give it a try again and I'll check what happens in our application when it doesn't return locked ports.

wborn commented 4 years ago

All errors are gone now so it would be nice to also have these changes in an official release @madhephaestus. :smile:

So far I didn't find any major issues in our application when the locked ports aren't returned. We have a wrapper around nrjavaserial, so there are also possibilities for tracking the locked ports if we do run into any issues.

madhephaestus commented 4 years ago

released changes in 3.20.0

wborn commented 4 years ago

Excellent! And many thanks for your help! :+1: