From adba85c00016d40383a5991854916c63b2ecc03f 2011-08-19 16:48:25 From: epatters Date: 2011-08-19 16:48:25 Subject: [PATCH] BUG: Ensure that kernel can be spawned from a backgrounded process. --- diff --git a/IPython/zmq/entry_point.py b/IPython/zmq/entry_point.py index 5811ff0..dcb3f70 100644 --- a/IPython/zmq/entry_point.py +++ b/IPython/zmq/entry_point.py @@ -85,30 +85,37 @@ def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0 executable = sys.executable arguments = [ executable, '-c', code, '--shell=%i'%shell_port, '--iopub=%i'%iopub_port, '--stdin=%i'%stdin_port, - '--hb=%i'%hb_port - ] + '--hb=%i'%hb_port ] if ip is not None: arguments.append('--ip=%s'%ip) arguments.extend(extra_arguments) + # Popen will fail (sometimes with a deadlock) if stdin, stdout, and stderr + # are invalid. Unfortunately, there is in general no way to detect whether + # they are valid. The following two blocks redirect them to (temporary) + # pipes in certain important cases. + + # If this process has been backgrounded, our stdin is invalid. Since there + # is no compelling reason for the kernel to inherit our stdin anyway, we'll + # place this one safe and always redirect. + redirect_in = True + _stdin = PIPE if stdin is None else stdin + + # If this process in running on pythonw, we know that stdin, stdout, and + # stderr are all invalid. + redirect_out = sys.executable.endswith('pythonw.exe') + if redirect_out: + _stdout = PIPE if stdout is None else stdout + _stderr = PIPE if stderr is None else stderr + else: + _stdout, _stderr = stdout, stderr + # Spawn a kernel. if sys.platform == 'win32': # Create a Win32 event for interrupting the kernel. interrupt_event = ParentPollerWindows.create_interrupt_event() arguments += [ '--interrupt=%i'%interrupt_event ] - # If this process in running on pythonw, stdin, stdout, and stderr are - # invalid. Popen will fail unless they are suitably redirected. We don't - # read from the pipes, but they must exist. - if sys.executable.endswith('pythonw.exe'): - redirect = True - _stdin = PIPE if stdin is None else stdin - _stdout = PIPE if stdout is None else stdout - _stderr = PIPE if stderr is None else stderr - else: - redirect = False - _stdin, _stdout, _stderr = stdin, stdout, stderr - # If the kernel is running on pythonw and stdout/stderr are not been # re-directed, it will crash when more than 4KB of data is written to # stdout or stderr. This is a bug that has been with Python for a very @@ -139,20 +146,22 @@ def base_launch_kernel(code, shell_port=0, iopub_port=0, stdin_port=0, hb_port=0 # Attach the interrupt event to the Popen objet so it can be used later. proc.win32_interrupt_event = interrupt_event - # Clean up pipes created to work around Popen bug. - if redirect: - if stdin is None: - proc.stdin.close() - if stdout is None: - proc.stdout.close() - if stderr is None: - proc.stderr.close() - else: if independent: proc = Popen(arguments, preexec_fn=lambda: os.setsid(), - stdin=stdin, stdout=stdout, stderr=stderr) + stdin=_stdin, stdout=_stdout, stderr=_stderr) else: proc = Popen(arguments + ['--parent=1'], - stdin=stdin, stdout=stdout, stderr=stderr) + stdin=_stdin, stdout=_stdout, stderr=_stderr) + + # Clean up pipes created to work around Popen bug. + if redirect_in: + if stdin is None: + proc.stdin.close() + if redirect_out: + if stdout is None: + proc.stdout.close() + if stderr is None: + proc.stderr.close() + return proc, shell_port, iopub_port, stdin_port, hb_port