From b19080bf4e87c191f264e54e57dfe8cd5567d4b3 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jan 2024 17:04:14 -0500 Subject: [PATCH 1/5] Disconnect stream readers and writers without closing the transport --- universal_silabs_flasher/xmodemcrc.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/universal_silabs_flasher/xmodemcrc.py b/universal_silabs_flasher/xmodemcrc.py index 516d8d3..d69237a 100644 --- a/universal_silabs_flasher/xmodemcrc.py +++ b/universal_silabs_flasher/xmodemcrc.py @@ -16,6 +16,17 @@ RECEIVE_TIMEOUT = 2 +class UncloseableTransport(asyncio.Transport): + """Transport that cannot be closed.""" + + def close(self) -> None: + """Do nothing.""" + + def is_closing(self) -> bool: + """Always return False.""" + return False + + class PacketType(zigpy.types.enum8): """XModem packet type byte.""" @@ -144,6 +155,10 @@ async def send_xmodem128_crc( max_failures=max_failures, ) finally: + # Make sure the writer doesn't close our transport when garbage collected + writer._transport = UncloseableTransport() + del writer + # Reset the old protocol transport.set_protocol(old_protocol) From 234ab4a6e303adcf9dd2b5adcbbb4c0f196e034b Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:01:28 -0500 Subject: [PATCH 2/5] Use a writer graveyard instead of private attribute access --- universal_silabs_flasher/xmodemcrc.py | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/universal_silabs_flasher/xmodemcrc.py b/universal_silabs_flasher/xmodemcrc.py index d69237a..520a2a2 100644 --- a/universal_silabs_flasher/xmodemcrc.py +++ b/universal_silabs_flasher/xmodemcrc.py @@ -15,16 +15,7 @@ BLOCK_SIZE = 128 RECEIVE_TIMEOUT = 2 - -class UncloseableTransport(asyncio.Transport): - """Transport that cannot be closed.""" - - def close(self) -> None: - """Do nothing.""" - - def is_closing(self) -> bool: - """Always return False.""" - return False +_WRITER_GRAVEYARD = [] class PacketType(zigpy.types.enum8): @@ -155,9 +146,8 @@ async def send_xmodem128_crc( max_failures=max_failures, ) finally: - # Make sure the writer doesn't close our transport when garbage collected - writer._transport = UncloseableTransport() - del writer + # XXX: Make sure the writer doesn't close our transport when garbage collected + _WRITER_GRAVEYARD.append(writer) # Reset the old protocol transport.set_protocol(old_protocol) From 3544535b394bb8fef4d29b2dd2b0811f05fa9b75 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:06:40 -0500 Subject: [PATCH 3/5] Clean up writer graveyard --- universal_silabs_flasher/xmodemcrc.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/universal_silabs_flasher/xmodemcrc.py b/universal_silabs_flasher/xmodemcrc.py index 520a2a2..764fe84 100644 --- a/universal_silabs_flasher/xmodemcrc.py +++ b/universal_silabs_flasher/xmodemcrc.py @@ -149,6 +149,16 @@ async def send_xmodem128_crc( # XXX: Make sure the writer doesn't close our transport when garbage collected _WRITER_GRAVEYARD.append(writer) + stale_entries = [ + index + for index, writer in enumerate(_WRITER_GRAVEYARD) + if writer.transport.is_closing() + ] + + for index in stale_entries[::-1]: + _LOGGER.debug("Removing stale writer %s", _WRITER_GRAVEYARD[index]) + del _WRITER_GRAVEYARD[index] + # Reset the old protocol transport.set_protocol(old_protocol) From f4b1ae5c72cccb70f12cd0f40002aaacda91ba92 Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:12:49 -0500 Subject: [PATCH 4/5] Simplify cleanup code --- universal_silabs_flasher/xmodemcrc.py | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/universal_silabs_flasher/xmodemcrc.py b/universal_silabs_flasher/xmodemcrc.py index 764fe84..d0afd90 100644 --- a/universal_silabs_flasher/xmodemcrc.py +++ b/universal_silabs_flasher/xmodemcrc.py @@ -15,7 +15,7 @@ BLOCK_SIZE = 128 RECEIVE_TIMEOUT = 2 -_WRITER_GRAVEYARD = [] +_WRITER_GRAVEYARD: list[asyncio.StreamWriter] = [] class PacketType(zigpy.types.enum8): @@ -147,18 +147,15 @@ async def send_xmodem128_crc( ) finally: # XXX: Make sure the writer doesn't close our transport when garbage collected - _WRITER_GRAVEYARD.append(writer) + global _WRITER_GRAVEYARD - stale_entries = [ - index - for index, writer in enumerate(_WRITER_GRAVEYARD) - if writer.transport.is_closing() + _WRITER_GRAVEYARD.append(writer) + _WRITER_GRAVEYARD = [ + w + for w in _WRITER_GRAVEYARD + if w.transport is None or w.transport.is_closing() ] - for index in stale_entries[::-1]: - _LOGGER.debug("Removing stale writer %s", _WRITER_GRAVEYARD[index]) - del _WRITER_GRAVEYARD[index] - # Reset the old protocol transport.set_protocol(old_protocol) From 7822f5364184264adfc9c1774b1510e65b84e4de Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 3 Jan 2024 18:14:05 -0500 Subject: [PATCH 5/5] Use correct logic --- universal_silabs_flasher/xmodemcrc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/universal_silabs_flasher/xmodemcrc.py b/universal_silabs_flasher/xmodemcrc.py index d0afd90..145a6e0 100644 --- a/universal_silabs_flasher/xmodemcrc.py +++ b/universal_silabs_flasher/xmodemcrc.py @@ -153,7 +153,7 @@ async def send_xmodem128_crc( _WRITER_GRAVEYARD = [ w for w in _WRITER_GRAVEYARD - if w.transport is None or w.transport.is_closing() + if w.transport is not None and not w.transport.is_closing() ] # Reset the old protocol