Commit 5571e203 authored by Kirill Smelkov's avatar Kirill Smelkov

Y wcfs: tests: Fix double close of pipes in tSubProcess

Running tests in wcfs/wcfs_faultyprot_test.py was yielding errors about
invalid closes, e.g.

    wcfs/wcfs_faultyprot_test.py::test_wcfs_pinhfaulty_kill_on_watch[_bad_watch_no_pin_read]
    ------------------------------------ live log call -------------------------------------
    M: commit -> @at0 (03fcee2b22c56155)
    INFO     wcfs:__init__.py:293 starting for file:///tmp/testdb_fs.v5XBEf/1.fs ...
    ...
    INFO     wcfs:__init__.py:400 unmount/stop wcfs pid875517 @ /dev/shm/wcfs/1060296857b6e9e0134ffb708787deb4039140ae
    I1126 19:11:13.746387  875517 wcfs.go:3100] stop "/dev/shm/wcfs/1060296857b6e9e0134ffb708787deb4039140ae" "file:///tmp/testdb_fs.v5XBEf/1.fs"
    close failed in file object destructor:             <-- NOTE
    IOError: [Errno 9] Bad file descriptor              <-- NOTE
    PASSED

Since soon we are going to use tSubProcess not only in tests this will
become less innocent with more incentive to fix.

Looking at the strace output I saw that the same file descriptor was
being closed twice in a row. Looking at strace further revealed that
this fd was created via pip syscall and finally I could connect it to
the pipe created by subprocess.Popen.

So what happens here is that we were taking fd number from
subprocess.Popen and passing it to multiprocessing.Connection with both
thinking they own the fd, and closing it on GC.

-> Fix that by really passing the fd to MPConnection as a copy first, and
   then redirecting Popen fds to devnull - to make sure in robust way
   that stdin/out IO does not interfere with pickle exchange going on in
   between child and parent via multiprocessing connections.

Fixes 33ea7769 (wcfs: tests: Move client to be pinkill'ed into separate process)
parent 7cc71a91
...@@ -71,8 +71,10 @@ class tSubProcess(object): ...@@ -71,8 +71,10 @@ class tSubProcess(object):
't.tSubProcess._start(%r)' % f.__name__] 't.tSubProcess._start(%r)' % f.__name__]
proc.popen = subprocess.Popen(exev, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True) proc.popen = subprocess.Popen(exev, stdin=subprocess.PIPE, stdout=subprocess.PIPE, close_fds=True)
try: try:
proc.cin = MPConnection(proc.popen.stdin.fileno(), readable=False) proc.cin = MPConnection(os.dup(proc.popen.stdin.fileno()), readable=False)
proc.cout = MPConnection(proc.popen.stdout.fileno(), writable=False) proc.cout = MPConnection(os.dup(proc.popen.stdout.fileno()), writable=False)
proc.popen.stdin = open(os.devnull, 'w')
proc.popen.stdout = open(os.devnull, 'r')
proc.send(argv) proc.send(argv)
proc.send(kw) proc.send(kw)
except: except:
...@@ -82,8 +84,10 @@ class tSubProcess(object): ...@@ -82,8 +84,10 @@ class tSubProcess(object):
# _start is trampoline ran in the subprocess to launch to user function. # _start is trampoline ran in the subprocess to launch to user function.
@staticmethod @staticmethod
def _start(funcname): def _start(funcname):
cin = MPConnection(sys.stdin.fileno(), writable=False) cin = MPConnection(os.dup(sys.stdin.fileno()), writable=False)
cout = MPConnection(sys.stdout.fileno(), readable=False) cout = MPConnection(os.dup(sys.stdout.fileno()), readable=False)
sys.stdin = open(os.devnull, 'r') # XXX better dup2 ?
sys.stdout = open(os.devnull, 'w')
argv = cin.recv() argv = cin.recv()
kw = cin.recv() kw = cin.recv()
f = globals()[funcname] f = globals()[funcname]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment