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 142 forks source link

Debugging crashing Java runtime under FreeBSD #175

Open RafalLukawiecki opened 4 years ago

RafalLukawiecki commented 4 years ago

I am trying to figure out what is the cause of two issues that are affecting nrjavaserial+openhab combination under FreeBSD: https://github.com/openhab/openhab-core/issues/1461 and https://github.com/openhab/openhab-core/issues/1462.

Essentially, Java throws an Abort trap, while there are locking issues being printed to the console. Interestingly, the serial works well for about 10-30 seconds, before it packs in.

To simplify debugging, I wanted to create a "Hello World" application that opens a port and just copies input to output to see if I can see the same issues. However, I am running into an absolute-beginner problem—I am not a Java developer and maven scares me (much happier in C, C++, Bourne sh, Python, R, PHP and even Lisp).

I have tried the sample from this repo's readme.md but it throws errors. This is what I tried (almsot exactly the readme.md except for the import of java.io.* and the cast to char while reading data):

package net.rafal;

import gnu.io.NRSerialPort;
import java.io.*;

public class App
{
        public static void main( String[] args )
        {
                System.out.println( "Hello World!" );
                String port = "";
                // for(String s:NRSerialPort.getAvailableSerialPorts()){
                //         System.out.println("Availible port: "+s);
                //         port=s;
                // }

                int baudRate = 115200;
                NRSerialPort serial = new NRSerialPort("/var/run/openhab2/ttyUSB0", baudRate);
                serial.connect();

                DataInputStream ins = new DataInputStream(serial.getInputStream());
                DataOutputStream outs = new DataOutputStream(serial.getOutputStream());
                try{
                        //while(ins.available()==0 && !Thread.interrupted());// wait for a byte
                        while(!Thread.interrupted()) {// read all bytes
                                if(ins.available()>0) {
                                        char b = (char) ins.read();
                                        //outs.write((byte)b);
                                        System.out.print(b);
                                }
                                Thread.sleep(5);
                        }
                }catch(Exception ex){
                        ex.printStackTrace();
                }
                serial.disconnect();
                System.out.println( "Bye World!" );
        }
}

There are two issues:

  1. If I uncomment the section that tries to enumerate the serial ports, I get a null pointer exception:

    java -Dgnu.io.rxtx.SerialPorts=/var/run/openhab2/ttyUSB0 net.rafal.App
    Hello World!
    Exception in thread "main" java.lang.ExceptionInInitializerError
        at gnu.io.NRSerialPort.getAvailableSerialPorts(NRSerialPort.java:175)
        at net.rafal.App.main(App.java:12)
    Caused by: java.lang.NullPointerException
        at gnu.io.NativeResource.copyResource(NativeResource.java:221)
        at gnu.io.NativeResource.inJarLoad(NativeResource.java:94)
        at gnu.io.NativeResource.loadLib(NativeResource.java:119)
        at gnu.io.NativeResource.load(NativeResource.java:86)
        at gnu.io.SerialManager.<init>(SerialManager.java:67)
        at gnu.io.SerialManager.getInstance(SerialManager.java:73)
        at gnu.io.RXTXCommDriver.<clinit>(RXTXCommDriver.java:95)
        ... 2 **more**

    I suspect nrjavaserial is not finding any ports hence the error, so not a biggie.

  2. If try with it commented out, hoping to open the port /var/runtime/openhab/ttyUSB0 (which is 100% functional as tested by cat and also during the 30s successful run before OpenHAB crashes) I just get gnu.io.NoSuchPortException despite specifying it as a -D option:

    java -Dgnu.io.rxtx.SerialPorts=/var/run/openhab2/ttyUSB0 net.rafal.App
    Hello World!
    java.lang.ExceptionInInitializerError thrown while loading gnu.io.RXTXCommDriver
    java.lang.NoClassDefFoundError: Could not initialize class gnu.io.RXTXCommDriver thrown while loading gnu.io.RXTXCommDriver
    Failed to connect on port: /var/run/openhab2/ttyUSB0 exception:
    gnu.io.NoSuchPortException
        at gnu.io.CommPortIdentifier.getPortIdentifier(CommPortIdentifier.java:273)
        at gnu.io.factory.RxTxPortCreator.createPort(RxTxPortCreator.java:35)
        at gnu.io.NRSerialPort.connect(NRSerialPort.java:99)
        at net.rafal.App.main(App.java:19)
    Exception in thread "main" java.lang.NullPointerException
        at gnu.io.NRSerialPort.getInputStream(NRSerialPort.java:124)
        at net.rafal.App.main(App.java:21)

    How can I tell it that there really is a port at /var/run/openhab2/ttyUSB0? For the OpenHAB runtime this is just added through the openhab2_java_opts -D variable.

Could you, please, help me fix this nrjavaserial Hello World? I would like to see if the library is going to crash under FreeBSD without OpenHAB in place. Many thanks and apologies for the newbie question.

RafalLukawiecki commented 4 years ago

One extra bit of info. When I try to open the port using RFC2217 URI, it also says there is no such port:

java net.rafal.App
Hello World!
java.lang.ExceptionInInitializerError thrown while loading gnu.io.RXTXCommDriver
java.lang.NoClassDefFoundError: Could not initialize class gnu.io.RXTXCommDriver thrown while loading gnu.io.RXTXCommDriver
Failed to connect on port: rfc2217://192.168.1.1:2001 exception:
gnu.io.NoSuchPortException
        at gnu.io.CommPortIdentifier.getPortIdentifier(CommPortIdentifier.java:273)
        at gnu.io.factory.RxTxPortCreator.createPort(RxTxPortCreator.java:35)
        at gnu.io.NRSerialPort.connect(NRSerialPort.java:99)
        at net.rafal.App.main(App.java:19)
Exception in thread "main" java.lang.NullPointerException
        at gnu.io.NRSerialPort.getInputStream(NRSerialPort.java:124)
        at net.rafal.App.main(App.java:21)

...and I pass it as

NRSerialPort serial = new NRSerialPort("rfc2217://192.168.1.1:2001", baudRate);

...which, I understand, nrjavaserial supports, as it supports RFC2217 since 3.16.

madhephaestus commented 4 years ago

Before you search or connect connect, try running this:

String port = "/var/run/openhab2/ttyUSB0"
System.setProperty("gnu.io.rxtx.SerialPorts", port);
madhephaestus commented 4 years ago

As a more permanent fix we would need to look at:

https://github.com/NeuronRobotics/nrjavaserial/blob/master/src/main/java/gnu/io/RXTXCommDriver.java#L734

and

https://github.com/NeuronRobotics/nrjavaserial/blob/master/src/main/java/gnu/io/RXTXCommDriver.java#L270

To ensure that the correct directories are searched and and the device prefixes are listed.

At this point it would be worth the effort for you to fire up Eclipse and step through debug the device search and listing issue. THis is very much an OS specific runtime issue of detection so it will be hard to debug further without using a step-through IDE debugger.

RafalLukawiecki commented 4 years ago

String port = "/var/run/openhab2/ttyUSB0" System.setProperty("gnu.io.rxtx.SerialPorts", port);

Tried adding the above, but still getting the NoSuchPortException.

Considering RFC2217 ports are specified as "rfc2217://host:port" I wonder why they are being rejected as "NoSuchPort". Any idea why? I can see code referring to rfc2217 in several places, like: https://github.com/NeuronRobotics/nrjavaserial/blob/af0e83d320920cf0ca3cc8fd25a4f25f482fd0d6/src/main/java/gnu/io/factory/RFC2217PortCreator.java#L13

Even if I could not get the local (socat'ed) port to work, being able to connect with rfc2217 would be a perfectly good (actually a superior) option to my application.

Fire up Eclipse...I would have to install and set it all up. My fear is that I would need to ramp up my understanding of Java significantly more to be of help—I actually had to search to figure out how to do Hello World in Maven. I was really hoping I could avoid digging into Java. :/ Moving to a VM with another OS just for this application is increasingly attractive. :) Maybe fixing rfc2217 is an easier way forward?

RafalLukawiecki commented 4 years ago

I think I can see why rfc2217 is not working: it looks like the code responsible for it never gets called. I will open a separate issue about it in a second.

Secondly, I started setting up Eclipse only to realise that it won't help, even if I invested more time into it. I run nrjavaserial on a FreeBSD server, which does not have any GUI: it is purely a server. All the development work is done on my MacBook Pro. I suspect running Eclipse on the Mac but the code inside another host, on FreeBSD, is possible, but I imagine the set-up would be complex—let me know if you think otherwise.

Oh, I also edited RXTXCommDriver.java and added the FreeBSD port, but it made no difference, still "no such port". I hope I can get ahead with rfc2217.

madhephaestus commented 4 years ago

I added the code to access rcf2217, if you pull the latest you can get it and test from there.

See commit 61746b78aa65e2fa638515b5b94929afb2fa0374

RafalLukawiecki commented 4 years ago

Thanks to you adding the test harness, which I was able to use for #176, I have returned to testing connecting on a non-rfc2217 port. I am afraid this simplified test (ie without Openhab in the way) throws check_lock_status: device is locked by another application messages that are exactly the same as the errors that I have been seeing under Openhab. I suppose, it means we may be getting closer to the root cause. It does not create a lock file, nor is there one present. If I try running the test without permissions to write to the lock directory (/var/spool/lock) I correctly get a permission error check_group_uucp(): error testing lock file creation Error details:Permission deniedcheck_lock_status: No permission to create lock file.. However, with the right permissions, this is what I get:

> Task :test FAILED
check_lock_status: device is locked by another application
check_lock_status: device is locked by another application
check_lock_status: device is locked by another application

test.SerialTest > test FAILED
    java.lang.NullPointerException at SerialTest.java:26

1 test completed, 1 failed

And this is my current version of the test:

package test;

import static org.junit.Assert.*;
import org.junit.Test;
import gnu.io.NRSerialPort;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.TooManyListenersException;
import gnu.io.SerialPortEvent;
import gnu.io.Zystem;

public class SerialTest {

        @Test
        public void test() throws Exception {
                // NRJavaSerialTest.main(new String[0]);
                String port = "/var/run/openhab2/ttyUSB0";
                System.setProperty("gnu.io.rxtx.SerialPorts", port);
                NRSerialPort serial = new NRSerialPort(port);
                serial.connect();
                Thread.sleep(1000);
                // serial.disconnect();
                System.err.print("Outside the loop");

                DataInputStream ins = new DataInputStream(serial.getInputStream());
                try{
                        //while(ins.available()==0 && !Thread.interrupted());// wait for a byte
                        while(!Thread.interrupted()) {// read all bytes
                                if(ins.available()>0) {
                                        char b = (char) ins.read();
                                        //outs.write((byte)b);
                                        System.out.print(b);
                                }
                                Thread.sleep(5);
                        }
                }catch(Exception ex){
                        ex.printStackTrace();
                }
        }
}

and this is the full report, showing the Null pointer exception but NoSuchPort error in the output.

<?xml version="1.0" encoding="UTF-8"?>
<testsuite name="test.SerialTest" tests="1" skipped="0" failures="1" errors="0" timestamp="2020-05-09T18:51:00" hostname="openhab" time="1.057">
  <properties/>
  <testcase name="test" classname="test.SerialTest" time="1.057">
    <failure message="java.lang.NullPointerException" type="java.lang.NullPointerException">java.lang.NullPointerException
    at gnu.io.NRSerialPort.getInputStream(NRSerialPort.java:164)
    at test.SerialTest.test(SerialTest.java:26)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.lang.Thread.run(Thread.java:748)
</failure>
  </testcase>
  <system-out><![CDATA[]]></system-out>
  <system-err><![CDATA[Failed to connect on port: /var/run/openhab2/ttyUSB0 exception: 
gnu.io.NoSuchPortException
    at gnu.io.CommPortIdentifier.getPortIdentifier(CommPortIdentifier.java:273)
    at gnu.io.factory.RxTxPortCreator.createPort(RxTxPortCreator.java:35)
    at gnu.io.NRSerialPort.connect(NRSerialPort.java:138)
    at test.SerialTest.test(SerialTest.java:21)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
    at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
    at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
    at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
    at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
    at com.sun.proxy.$Proxy2.processTestClass(Unknown Source)
    at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
    at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:182)
    at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:164)
    at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:412)
    at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:64)
    at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:48)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:56)
    at java.lang.Thread.run(Thread.java:748)
Outside the loop]]></system-err>
</testsuite>

What do you think? And...many thanks! 🙏

RafalLukawiecki commented 4 years ago

Scratch that: my mistake. I failed to have the port ready. I am very pleased to say that the port is working, under FreeBSD, and I am receiving data from it!

All that remains is to test it under OpenHAB, which I will do as soon as the current build is on Maven.

Thank you, very much, for your help, @madhephaestus!

wborn commented 4 years ago

I think I can see why rfc2217 is not working: it looks like the code responsible for it never gets called

If this was while testing with the ZWave binding, it's probably explained by https://github.com/openhab/org.openhab.binding.zwave/issues/1332.

RafalLukawiecki commented 4 years ago

If this was while testing with the ZWave binding, it's probably explained by openhab/org.openhab.binding.zwave#1332.

I was debugging the ZWave binding at the time, but the reason RFC2217 code was inaccessible was different: nrjavaserial prior to 5.1.1 never checked for the presence of the protocol specifier, ie. "rfc2217://" in the port name and it just defaulted to always opening a serial port. This was fixed following my report of the issue in this commit only 4 days ago (9 May 2020).

That is one other reason why I believe no one has ever managed to make RFC2217 work in OpenHAB before my well-documented attempts, unless there was an older version of nrjavaserial that already had it working.

wborn commented 4 years ago

The reason why it already works in openHAB is because we don't use the NRSerialPort but the TelnetSerialPort see RFC2217PortProvider.getPortIdentifier(URI).

RafalLukawiecki commented 4 years ago

That is interesting, @wborn. I read that code, but I still thought it was being routed through nrjavaserial—apologies for my misunderstanding. I wonder if there are other differences in the implementations that could affect ZWave.

madhephaestus commented 4 years ago

my understanding this is resolved now?

RafalLukawiecki commented 4 years ago

I am afraid only half of it is resolved, the support for RFC2217. The other part is still here. It is currently not possible to use "real" locally plugged devices, or virtual devices created using socat, with the current combination of nrjavaserial and OpenHAB. It causes 100% abort traps after about 20-30s of otherwise successful operation.

madhephaestus commented 4 years ago

Take a look at the changes in 5.2.1, there were some issues that resulted in the process exiting (there were exit() commands in fuserimp!)

The more i look at the C portion the more glaring errors are becoming apparent. JNI should not process exit the JVM above it, this JNI does. One should never use goto in C, it has goto all over the place.

In any case, the easy fix was to use Java to bypass that JNI call entirely. Try this issue now?

MrDOS commented 4 years ago

The more i look at the C portion the more glaring errors are becoming apparent.

As mentioned in #19, I'm in the middle of an experiment to port all the JNI code to Java + JNA. It's... Even if this project does not bear direct fruit, I think I'll be in a better position than anyone has been for some years to dramatically reduce the footprint of the JNI code. There is a lot of duplicate code – lots of getter/setter functions which are entirely identical but for a different bitmask or flag being used. Either way, hopefully I can contribute some meaningful improvements soon.

madhephaestus commented 4 years ago

yeah, that would be great. Things like lockfiles and the event queue thread should move up to java anyway.

and the goto's oh god so many gotos...

I did manage to remove the exit() calls in C today. That was astounding to find TBH. JNI code should not cause the whole jvm to shutdown under any conditions.

MrDOS commented 4 years ago

My greatest astonishment so far has been finding out that the monitor thread is managed from within the JNI code through direct pthread invocation.

I intend to open a preview pull request within the week to solicit feedback. My initial syntax-focused port will compile but won't actually function; but from that stage onward, I'd like progress to be visible (as much so that I stay motivated as anything else).

madhephaestus commented 4 years ago

another issue is that this code still uses SELECT() which has been depricated and replaced with poll() for almost a decade...

Dropping select would fix all of the issues we have with plug/unplug cycles eventually leading to a crash, as well as the limit on number of serial ports supported.