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

5.2.1 crash in multi-thread context #188

Open pseudo555 opened 4 years ago

pseudo555 commented 4 years ago

I develop a utils class that try to connect on each available COM port to find out which one has the stuff i'l interested in plugged onto.

I use the following principle: for each Com port available:

  1. connect using some parameters( 8 bit, 1 bit stop no parity and expected baud rate)
  2. send a specific frame, wait for answer or timeout after xx ms
  3. disconnect

I use a separate thread to do one port check, thread pool is define as number of available processor minus 1. In my case, there is up to 7 ports check at the "same time". The JVM crashes. hs_err_pid9828.log

If i don't use multithread to check port com, from time to time, one is not closed.

Code used is: ` public static List findPortToUse(final Supplier<SerialManager> smGenerator, final Function<CheckPort, Boolean> identificationChecker) {

    final BasicThreadFactory factory = new BasicThreadFactory.Builder().namingPattern("findComPortToUse_thread%d").build();
    //  minus 1 (one left to manage the main thread)
    final int nbPara Math.max(Runtime.getRuntime().availableProcessors() -1, 1);
    final ExecutorService executorService = Executors.newFixedThreadPool(nbPara, factory);

    // ExecutorService's tasks to runs
    final Set<Callable<CommPortIdentifier>> callables = new HashSet<>();
    // for each serial port found, check it
    SerialManager.getAllAvailablePorts().forEach(port -> {
        callables.add(new CheckPort<>(port, smGenerator.get(), identificationChecker));
    });

    final List<CommPortIdentifier> res = new ArrayList<>();
    try {
        final List<Future<CommPortIdentifier>> futures = executorService.invokeAll(callables);
        executorService.shutdown();
        executorService.awaitTermination(callables.size() * 2L, TimeUnit.SECONDS);

        for (Future<CommPortIdentifier> future : futures) {
            if (future.get() != null) {
                res.add(future.get());
            }
        }
    } catch (Exception e) {
        executorService.shutdownNow();
        LOG.error("findPortToUse was interrupted: " + e.getMessage()), e);
    }
    return res;
}`

CheckPort's call method is defined as follow: ` public final CommPortIdentifier call() throws Exception {

    final String portName = port.getName();

    LOG.debug("Start checking of " + portName);
    if (!sm.connect(port, DataBitsMode.EIGHT, StopBitMode.ONE, ParityMode.NONE, BaudsMode.BAUDS_115200)) {
        // connection failed
        LOG.debug("Connection failed on " + portName + ", assuming bad port. ");
        return null;
    }
    // connection succeed
    LOG.debug("Connection succeed on " + portName + ", checking line identification");
    CommPortIdentifier toUse = null;
    if (identChecker != null && identChecker.apply(this) == Boolean.TRUE) {
        toUse = port;
    }

    LOG.debug("Disconnection asked on " + portName + ", sending frame");
    sm.requestDisconnect();
    // wait for disconnection end
    try {
        Thread.sleep(500);
    } catch (Exception e) {
        LOG.error("Thread sleep in findPortToUse failed: " + e, e);
    }

    return toUse;
}`
MrDOS commented 3 years ago

This may be fixed in #211. Can you see if you can still reproduce the crash when you use this build, nrjavaserial-fd5fadf?

pseudo555 commented 3 years ago

Crash doesn't seem to occur :)