From d2ed5158ca0b10f5ba93ffabd199a1857fe8350d Mon Sep 17 00:00:00 2001
From: Hannes Feldt <feldt@astron.nl>
Date: Fri, 7 Oct 2022 08:42:02 +0000
Subject: [PATCH] Resolve L2SS-960 "Unit tests deadlock starting python 3.7.5"

---
 .../tangostationcontrol/clients/tcp_replicator.py | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py b/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py
index fd44bcc72..5bec83ceb 100644
--- a/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py
+++ b/tangostationcontrol/tangostationcontrol/clients/tcp_replicator.py
@@ -1,4 +1,4 @@
-
+import atexit
 from threading import Condition
 from threading import Semaphore
 from threading import Thread
@@ -54,7 +54,7 @@ class TCPReplicator(Thread, StatisticsClientThread):
     }
 
     def __init__(self, options: dict = None, queuesize=0):
-        super().__init__()
+        super().__init__(daemon=True)
 
         self.queuesize = queuesize
 
@@ -162,7 +162,8 @@ class TCPReplicator(Thread, StatisticsClientThread):
             self._loop = asyncio.new_event_loop()
 
             # Create the input queue
-            self.queue = asyncio.Queue(maxsize=self.queuesize, loop=self._loop)
+            asyncio.set_event_loop(self._loop)
+            self.queue = asyncio.Queue(maxsize=self.queuesize)
 
             # When wanting to debug event loop behavior, uncomment this
             # self._loop.set_debug(True)
@@ -178,6 +179,10 @@ class TCPReplicator(Thread, StatisticsClientThread):
             # call self._loop.stop()
             server_task.add_done_callback(self._server_start_callback)
 
+            # Register _clean_shutdown to be executed at termination to make
+            # sure all tcp connections are cleaned up.
+            atexit.register(self._clean_shutdown)
+
             # Keep running event loop until self._loop.stop() is called.
             # Calling this will lose control flow to the event loop
             # indefinitely, upon self._loop.stop() control flow is returned
@@ -325,6 +330,10 @@ class TCPReplicator(Thread, StatisticsClientThread):
     def _clean_shutdown(self):
         """Disconnect clients, stop the event loop and wait for it to close"""
 
+        # Unregister _clean_shutdown to prevent double execution and make
+        # sure the thread gets cleaned up on stop/join
+        atexit.unregister(self._clean_shutdown)
+
         # The event loop is not running anymore, we can't send tasks to shut
         # it down further.
         if not self._loop.is_running():
-- 
GitLab