plc4x icon indicating copy to clipboard operation
plc4x copied to clipboard

[Bug]: SerialSocketChannel does not properly close itself

Open zawodskoj opened this issue 1 year ago • 0 comments

What happened?

For some reason, if Bootstrap.connect(...) had failed for any reason, EventLoopGroup.shutdownGracefullly does not close channel and keeps select-ing it indefinitely, causing a lot of logs to appear

NioEventLoop -- Selector.select() returned prematurely 512 times in a row; rebuilding Selector org.apache.plc4x.java.transport.serial.SerialPollingSelector@5bb67f2.
NioEventLoop -- Migrated 1 channel(s) to the new Selector.
NioEventLoop -- Selector.select() returned prematurely 512 times in a row; rebuilding Selector org.apache.plc4x.java.transport.serial.SerialPollingSelector@4a67eb86.
NioEventLoop -- Migrated 1 channel(s) to the new Selector.
NioEventLoop -- Selector.select() returned prematurely 512 times in a row; rebuilding Selector org.apache.plc4x.java.transport.serial.SerialPollingSelector@748a37b5.
NioEventLoop -- Migrated 1 channel(s) to the new Selector.

There is a basic repro - it purposely tries to open non-existent serial port and fails: https://gist.github.com/zawodskoj/68987f535bbfe199eeee9be43cf4bf13

There is also a dirty workaround - it is possible to obtain SerialPollingSelector through reflection and invoke close() on them, catching meaningless NotImplementedException

val getJCh = AbstractNioChannel::class.java.getDeclaredMethod("javaChannel")
getJCh.isAccessible = true
val javach = getJCh.invoke(cch) as AbstractInterruptibleChannel
try {
    javach.close()
} catch (e: NotImplementedException) {
    // ???
}

Soon after another rebuildSelector0(), Netty attempts to re-register channel, fails to do so (because it is already closed) and exits the infinite loop

WARN  io.netty.channel.nio.NioEventLoop -- Selector.select() returned prematurely 512 times in a row; rebuilding Selector org.apache.plc4x.java.transport.serial.SerialPollingSelector@287d3f58.
WARN  io.netty.channel.nio.NioEventLoop -- Failed to re-register a Channel to the new Selector.
java.nio.channels.ClosedChannelException: null
	at java.base/java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:222)
	at io.netty.channel.nio.NioEventLoop.rebuildSelector0(NioEventLoop.java:467)
	at io.netty.channel.nio.NioEventLoop.rebuildSelector(NioEventLoop.java:368)
	at io.netty.channel.nio.NioEventLoop.unexpectedSelectorWakeup(NioEventLoop.java:630)
	at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:578)
	at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
	at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:840)
INFO  io.netty.channel.nio.NioEventLoop -- Migrated 0 channel(s) to the new Selector.

Version

v0.11.0

Programming Languages

  • [X] plc4j
  • [ ] plc4go
  • [ ] plc4c
  • [ ] plc4net

Protocols

  • [ ] AB-Ethernet
  • [ ] ADS /AMS
  • [ ] BACnet/IP
  • [ ] CANopen
  • [ ] DeltaV
  • [ ] DF1
  • [ ] EtherNet/IP
  • [ ] Firmata
  • [ ] KNXnet/IP
  • [ ] Modbus
  • [ ] OPC-UA
  • [ ] S7

zawodskoj avatar Jan 15 '24 16:01 zawodskoj