From 30f4af59139ccb93bba80eb08242e88175e0a5bb Mon Sep 17 00:00:00 2001 From: KIU Shueng Chuan Date: Tue, 22 Jun 2021 21:59:39 +0800 Subject: [PATCH] remote: exchange pids if running in Windows venv --- pyqtgraph/multiprocess/processes.py | 24 +++++++++++++++++++++--- pyqtgraph/multiprocess/remoteproxy.py | 7 +++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/pyqtgraph/multiprocess/processes.py b/pyqtgraph/multiprocess/processes.py index 6e9da206..1d213582 100644 --- a/pyqtgraph/multiprocess/processes.py +++ b/pyqtgraph/multiprocess/processes.py @@ -122,13 +122,24 @@ class Process(RemoteEventHandler): targetStr = pickle.dumps(target) ## double-pickle target so that child has a chance to ## set its sys.path properly before unpickling the target pid = os.getpid() # we must send pid to child because windows does not have getppid - + + # When running in a venv on Windows platform, since Python >= 3.7.3, the launched + # subprocess is a grandchild instead of a child, leading to self.proc.pid not being + # the pid of the launched subprocess. + # https://bugs.python.org/issue38905 + # + # As a workaround, when we detect such a situation, we perform exchange of pids via + # the multiprocessing connection. Technically, only the launched subprocess needs to + # send its pid back. Practically, we hijack the ppid parameter to indicate to the + # subprocess that pid exchange is needed. + xchg_pids = sys.platform == 'win32' and os.getenv('VIRTUAL_ENV') is not None + ## Send everything the remote process needs to start correctly data = dict( name=name+'_child', port=port, authkey=authkey, - ppid=pid, + ppid=pid if not xchg_pids else None, targetStr=targetStr, path=sysPath, qt_lib=QT_LIB, @@ -150,7 +161,14 @@ class Process(RemoteEventHandler): else: raise - RemoteEventHandler.__init__(self, conn, name+'_parent', pid=self.proc.pid, debug=self.debug) + child_pid = self.proc.pid + if xchg_pids: + # corresponding code is in: + # remoteproxy.py::RemoteEventHandler.__init__() + conn.send(pid) + child_pid = conn.recv() + + RemoteEventHandler.__init__(self, conn, name+'_parent', pid=child_pid, debug=self.debug) self.debugMsg('Connected to child process.') atexit.register(self.join) diff --git a/pyqtgraph/multiprocess/remoteproxy.py b/pyqtgraph/multiprocess/remoteproxy.py index 8509cc57..7f6e4750 100644 --- a/pyqtgraph/multiprocess/remoteproxy.py +++ b/pyqtgraph/multiprocess/remoteproxy.py @@ -86,6 +86,13 @@ class RemoteEventHandler(object): # Mutexes to help prevent issues when multiple threads access the same RemoteEventHandler self.processLock = threading.RLock() self.sendLock = threading.RLock() + + # parent sent us None as its pid, wants us to exchange pids + # corresponding code is in: + # processes.py::Process.__init__() + if pid is None: + connection.send(os.getpid()) + pid = connection.recv() RemoteEventHandler.handlers[pid] = self ## register this handler as the one communicating with pid