summary refs log tree commit diff
path: root/nixos/lib
diff options
context:
space:
mode:
authorK900 <me@0upti.me>2021-10-19 15:42:27 +0300
committerK900 <me@0upti.me>2021-10-19 16:23:51 +0300
commita874235dff32bd77125034cfd9542a91b68efb03 (patch)
treee3671142191b84bd8eaf9d299e1fa77e8aa6f66b /nixos/lib
parent0c084c89fe6406b1d76e448f234a206d9a23f837 (diff)
downloadnixpkgs-a874235dff32bd77125034cfd9542a91b68efb03.tar
nixpkgs-a874235dff32bd77125034cfd9542a91b68efb03.tar.gz
nixpkgs-a874235dff32bd77125034cfd9542a91b68efb03.tar.bz2
nixpkgs-a874235dff32bd77125034cfd9542a91b68efb03.tar.lz
nixpkgs-a874235dff32bd77125034cfd9542a91b68efb03.tar.xz
nixpkgs-a874235dff32bd77125034cfd9542a91b68efb03.tar.zst
nixpkgs-a874235dff32bd77125034cfd9542a91b68efb03.zip
nixos/lib/test-driver: clean up threads correctly
The current implementation just forks off a thread to read
QEMU's stdout and lets it exist forever. This, however,
makes the interpreter shutdown racy, as the thread could
still be running and writing out buffered stdout when the
main thread exits (and since it's using the low level API,
the worker thread does not get cleaned up by the atexit hooks
installed by `threading`, either). So, instead of doing that,
let's create a real `threading.Thread` object, and also
explicitly `join` it along with the other stuff when cleaning up.
Diffstat (limited to 'nixos/lib')
-rwxr-xr-xnixos/lib/test-driver/test-driver.py11
1 files changed, 9 insertions, 2 deletions
diff --git a/nixos/lib/test-driver/test-driver.py b/nixos/lib/test-driver/test-driver.py
index e659b0c04f5..f2e7bf3c1d5 100755
--- a/nixos/lib/test-driver/test-driver.py
+++ b/nixos/lib/test-driver/test-driver.py
@@ -6,7 +6,7 @@ from xml.sax.saxutils import XMLGenerator
 from colorama import Style
 import queue
 import io
-import _thread
+import threading
 import argparse
 import atexit
 import base64
@@ -409,6 +409,7 @@ class Machine:
     pid: Optional[int] = None
     monitor: Optional[socket.socket] = None
     shell: Optional[socket.socket] = None
+    serial_thread: Optional[threading.Thread]
 
     booted: bool = False
     connected: bool = False
@@ -444,6 +445,8 @@ class Machine:
             self.cleanup_statedir()
         self.state_dir.mkdir(mode=0o700, exist_ok=True)
 
+        self.serial_thread = None
+
     @staticmethod
     def create_startcommand(args: Dict[str, str]) -> StartCommand:
         rootlog.warning(
@@ -921,7 +924,8 @@ class Machine:
                 self.last_lines.put(line)
                 self.log_serial(line)
 
-        _thread.start_new_thread(process_serial_output, ())
+        self.serial_thread = threading.Thread(target=process_serial_output)
+        self.serial_thread.start()
 
         self.wait_for_monitor_prompt()
 
@@ -1021,9 +1025,12 @@ class Machine:
         assert self.process
         assert self.shell
         assert self.monitor
+        assert self.serial_thread
+
         self.process.terminate()
         self.shell.close()
         self.monitor.close()
+        self.serial_thread.join()
 
 
 class VLan: