[Python-checkins] cpython: Issue #18762: Fix EBADF error when using forkserver.

richard.oudkerk python-checkins at python.org
Thu Aug 22 12:47:31 CEST 2013


http://hg.python.org/cpython/rev/a94555d5070f
changeset:   85312:a94555d5070f
user:        Richard Oudkerk <shibturn at gmail.com>
date:        Thu Aug 22 11:38:55 2013 +0100
summary:
  Issue #18762: Fix EBADF error when using forkserver.

files:
  Lib/multiprocessing/forkserver.py |  55 ++++++++----------
  1 files changed, 25 insertions(+), 30 deletions(-)


diff --git a/Lib/multiprocessing/forkserver.py b/Lib/multiprocessing/forkserver.py
--- a/Lib/multiprocessing/forkserver.py
+++ b/Lib/multiprocessing/forkserver.py
@@ -23,11 +23,12 @@
 MAXFDS_TO_SEND = 256
 UNSIGNED_STRUCT = struct.Struct('Q')     # large enough for pid_t
 
+_forkserver_address = None
+_forkserver_alive_fd = None
 _inherited_fds = None
 _lock = threading.Lock()
 _preload_modules = ['__main__']
 
-
 #
 # Public function
 #
@@ -56,31 +57,15 @@
     '''
     if len(fds) + 3 >= MAXFDS_TO_SEND:
         raise ValueError('too many fds')
-    address, alive_w = process.current_process()._config['forkserver_info']
     with socket.socket(socket.AF_UNIX) as client:
-        client.connect(address)
+        client.connect(_forkserver_address)
         parent_r, child_w = util.pipe()
         child_r, parent_w = util.pipe()
-        allfds = [child_r, child_w, alive_w]
+        allfds = [child_r, child_w, _forkserver_alive_fd]
         allfds += fds
         try:
             reduction.sendfds(client, allfds)
             return parent_r, parent_w
-        except OSError:
-            # XXX This is debugging info for Issue #18762
-            import fcntl
-            L = []
-            for fd in allfds:
-                try:
-                    flags = fcntl.fcntl(fd, fcntl.F_GETFL)
-                except OSError as e:
-                    L.append((fd, e))
-                else:
-                    L.append((fd, flags))
-            print('*** connect_to_new_process: %r' % L, file=sys.stderr)
-            os.close(parent_r)
-            os.close(parent_w)
-            raise
         except:
             os.close(parent_r)
             os.close(parent_w)
@@ -97,12 +82,13 @@
     process will just reuse the forkserver started by its parent, so
     ensure_running() will do nothing.
     '''
+    global _forkserver_address, _forkserver_alive_fd
     with _lock:
-        config = process.current_process()._config
-        if config.get('forkserver_info') is not None:
+        if _forkserver_alive_fd is not None:
             return
 
         assert all(type(mod) is str for mod in _preload_modules)
+        config = process.current_process()._config
         semaphore_tracker_fd = config['semaphore_tracker_fd']
         cmd = ('from multiprocessing.forkserver import main; ' +
                'main(%d, %d, %r, **%r)')
@@ -122,13 +108,20 @@
 
             # all client processes own the write end of the "alive" pipe;
             # when they all terminate the read end becomes ready.
-            alive_r, alive_w = os.pipe()
-            config['forkserver_info'] = (address, alive_w)
-            fds_to_pass = [listener.fileno(), alive_r, semaphore_tracker_fd]
-            cmd %= (listener.fileno(), alive_r, _preload_modules, data)
-            exe = spawn.get_executable()
-            args = [exe] + util._args_from_interpreter_flags() + ['-c', cmd]
-            pid = util.spawnv_passfds(exe, args, fds_to_pass)
+            alive_r, alive_w = util.pipe()
+            try:
+                fds_to_pass = [listener.fileno(), alive_r, semaphore_tracker_fd]
+                cmd %= (listener.fileno(), alive_r, _preload_modules, data)
+                exe = spawn.get_executable()
+                args = [exe] + util._args_from_interpreter_flags() + ['-c', cmd]
+                pid = util.spawnv_passfds(exe, args, fds_to_pass)
+            except:
+                os.close(alive_w)
+                raise
+            finally:
+                os.close(alive_r)
+            _forkserver_address = address
+            _forkserver_alive_fd = alive_w
 
 
 def main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
@@ -157,6 +150,8 @@
     # ignoring SIGCHLD means no need to reap zombie processes
     handler = signal.signal(signal.SIGCHLD, signal.SIG_IGN)
     with socket.socket(socket.AF_UNIX, fileno=listener_fd) as listener:
+        global _forkserver_address
+        _forkserver_address = listener.getsockname()
         readers = [listener, alive_r]
 
         while True:
@@ -191,7 +186,7 @@
 #
 
 def _serve_one(s, listener, alive_r, handler):
-    global _inherited_fds
+    global _inherited_fds, _forkserver_alive_fd
 
     # close unnecessary stuff and reset SIGCHLD handler
     listener.close()
@@ -202,7 +197,7 @@
     fds = reduction.recvfds(s, MAXFDS_TO_SEND + 1)
     s.close()
     assert len(fds) <= MAXFDS_TO_SEND
-    child_r, child_w, alive_w, *_inherited_fds = fds
+    child_r, child_w, _forkserver_alive_fd, *_inherited_fds = fds
 
     # send pid to client processes
     write_unsigned(child_w, os.getpid())

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list