Fix #49 - force close socket to kill reader thread (was blocking in read)

This commit is contained in:
Kevin Hester
2021-01-03 20:55:01 +08:00
parent 5a56207440
commit 76f475d800
2 changed files with 29 additions and 14 deletions

View File

@@ -639,7 +639,7 @@ class StreamInterface(MeshInterface):
def close(self):
"""Close a connection to the device"""
logging.debug("Closing serial stream")
logging.debug("Closing stream")
# pyserial cancel_read doesn't seem to work, therefore we ask the reader thread to close things for us
self._wantExit = True
if self._rxThread != threading.current_thread():
@@ -651,7 +651,9 @@ class StreamInterface(MeshInterface):
try:
while not self._wantExit:
# logging.debug("reading character")
b = self._readBytes(1)
# logging.debug("In reader loop")
if len(b) > 0:
# logging.debug(f"read returned {b}")
c = b[0]
@@ -692,8 +694,13 @@ class StreamInterface(MeshInterface):
# logging.debug(f"timeout")
pass
except serial.SerialException as ex:
logging.warn(
f"Meshtastic serial port disconnected, disconnecting... {ex}")
if not self._wantExit: # We might intentionally get an exception during shutdown
logging.warn(f"Meshtastic serial port disconnected, disconnecting... {ex}")
except OSError as ex:
if not self._wantExit: # We might intentionally get an exception during shutdown
logging.error(f"Unexpected OSError, terminating meshtastic reader... {ex}")
except Exception as ex:
logging.error(f"Unexpected exception, terminating meshtastic reader... {ex}")
finally:
logging.debug("reader is exiting")
self._disconnected()
@@ -741,12 +748,6 @@ class SerialInterface(StreamInterface):
StreamInterface.__init__(
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
def _disconnected(self):
"""We override the superclass implementation to close our port"""
StreamInterface._disconnected(self)
class TCPInterface(StreamInterface):
"""Interface class for meshtastic devices over a TCP link"""
@@ -770,13 +771,16 @@ class TCPInterface(StreamInterface):
StreamInterface.__init__(
self, debugOut=debugOut, noProto=noProto, connectNow=connectNow)
def _disconnected(self):
"""We override the superclass implementation to close our port"""
StreamInterface._disconnected(self)
logging.debug("Closing our socket")
def close(self):
"""Close a connection to the device"""
logging.debug("Closing TCP stream")
# Sometimes the socket read might be blocked in the reader thread. Therefore we force the shutdown by closing
# the socket here
self._wantExit = True
if not self.socket is None:
self.socket.shutdown(socket.SHUT_RDWR)
self.socket.close()
StreamInterface.close(self)
def _writeBytes(self, b):
"""Write an array of bytes to our stream and flush"""

11
tests/close-bug.py Normal file
View File

@@ -0,0 +1,11 @@
import sys
import meshtastic
import datetime, logging
from pubsub import pub
#logging.basicConfig(level=logging.DEBUG)
print(str(datetime.datetime.now()) + ": start")
interface = meshtastic.TCPInterface(sys.argv[1])
print(str(datetime.datetime.now()) + ": middle")
interface.close()
print(str(datetime.datetime.now()) + ": after close")