I have been bitten by this same problem but managed to debug it to the
fact that autopkgtest-virt-qemu is not closing the sockets.

On python3.6 and python3.7.1 (likely, haven't tested this one out yet),
the socket is closed when its references are gone (this is done on
socket_finalized on Modules/socketmodule.c).

As you can see on that same code, a ResourceWarning is raised, but one
can only see that on debug builds. Both 3.6 and 3.7 raise that, but only
by using some strace I could notice that 3.7.2rc1 is not closing the
socket on a function exit. And that's only when the 'with timeout' is
used, because of calling signal.signal. I will attach my minimal case
where this happens as well.

The attached autopkgtest-virt-qemu patch also fixes the problem for me.
I don't close the socket on all failure paths. Maybe we should implement
a "With Context Manager" for that as well. Though thinking a little more
about that, the code would be pretty ugly, and we should just rely on a
working python doing the correct resource management.

Regards.
Cascardo.
import signal
import socket
import time

class Timeout(RuntimeError):
    pass

def alarm_handler(*a):
    raise Timeout()

def get_unix_socket():
    s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
    signal.signal(signal.SIGALRM, alarm_handler)
    return s

def test_tty():
    sock = get_unix_socket()
    signal.signal(signal.SIGALRM, alarm_handler)

test_tty()

time.sleep(1)
>From dcd5895b808ca377255f9cc980e9ba54bbed5f75 Mon Sep 17 00:00:00 2001
From: Thadeu Lima de Souza Cascardo <casca...@debian.org>
Date: Fri, 21 Dec 2018 17:14:11 -0200
Subject: [PATCH] qemu: close sockets after being done with them

With Python 3.7.2-rc1, the socket won't be closed after being finalized.
That causes a problem when trying to connect to the same qemu unix socket
again. It won't be able to receive anything, and that breaks
autopkgtest-virt-qemu.

Closing the sockets before exiting the functions on the success cases will
make it work around that problem.

Signed-off-by: Thadeu Lima de Souza Cascardo <casca...@debian.org>
---
 virt/autopkgtest-virt-qemu | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/virt/autopkgtest-virt-qemu b/virt/autopkgtest-virt-qemu
index 573bce7..8cdcc74 100755
--- a/virt/autopkgtest-virt-qemu
+++ b/virt/autopkgtest-virt-qemu
@@ -125,6 +125,7 @@ def wait_boot():
     # don't help to determine if the system is *really* booted; running
     # commands too early causes the system time to be all wrong
     time.sleep(3)
+    term.close()
 
 
 def check_ttyS1_shell():
@@ -134,8 +135,10 @@ def check_ttyS1_shell():
     term.sendall(b'echo -n o; echo k\n')
     try:
         VirtSubproc.expect(term, b'ok', 1)
+        term.close()
         return True
     except VirtSubproc.Timeout:
+        term.close()
         return False
 
 
@@ -190,6 +193,7 @@ def login_tty_and_setup_shell():
     VirtSubproc.expect(term, None, 10, 'accepted ttyS1 shell command')
     term.sendall(b'exit\n')
     VirtSubproc.expect(term, b'\nlogout', 10)
+    term.close()
 
 
 def setup_baseimage():
@@ -215,6 +219,8 @@ def setup_baseimage():
 
     term.sendall(b'udevadm settle --exit-if-exists=/dev/baseimage\n')
     VirtSubproc.expect(term, b'#', 10)
+    term.close()
+    monitor.close()
 
 
 def setup_shared(shared_dir):
@@ -275,6 +281,7 @@ while not os.path.exists(fexit):
 EOF
 ''')
     VirtSubproc.expect(term, b'# ', 5)
+    term.close()
 
 
 def setup_config(shared_dir):
@@ -311,6 +318,8 @@ def setup_config(shared_dir):
     if b'\n# ' not in out:
         VirtSubproc.expect(term, b'# ', 5)
 
+    term.close()
+
 
 def make_auxverb(shared_dir):
     '''Create auxverb script'''
@@ -513,6 +522,7 @@ def determine_normal_user(shared_dir):
             adtlog.debug('determine_normal_user: got user "%s"' % normal_user)
         else:
             adtlog.debug('determine_normal_user: no uid in [1000,59999] available')
+    term.close()
 
 
 def hook_open():
@@ -642,6 +652,7 @@ def hook_prepare_reboot():
         monitor = VirtSubproc.get_unix_socket(os.path.join(workdir, 'monitor'))
         monitor.sendall(b'device_del virtio-baseimage\n')
         VirtSubproc.expect(monitor, b'(qemu)', 10)
+        monitor.close()
 
 
 def hook_wait_reboot():
-- 
2.20.1

Reply via email to