Issue 12044: subprocess.Popen.exit doesn't wait for process end (original) (raw)

Created on 2011-05-09 19:24 by pitrou, last changed 2022-04-11 14:57 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
subprocess_zombie.diff neologix,2011-05-11 16:44 review
Messages (17)
msg135635 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-05-09 19:24
I find it a bit strange that Popen.__exit__ closes all standard file descriptors leading to the child process, but doesn't wait for process end afterwards. (context management support was added in )
msg135641 - (view) Author: Brian Curtin (brian.curtin) * (Python committer) Date: 2011-05-09 20:41
Seems like it would be enough to add a wait() at the end? diff -r 9e473917cbfb Lib/subprocess.py --- a/Lib/subprocess.py Mon May 09 21:17:02 2011 +0200 +++ b/Lib/subprocess.py Mon May 09 15:30:02 2011 -0500 @@ -796,6 +796,7 @@ self.stderr.close() if self.stdin: self.stdin.close() + self.wait() def __del__(self, _maxsize=sys.maxsize, _active=_active): if not self._child_created:
msg135642 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-05-09 20:42
> Seems like it would be enough to add a wait() at the end? Probably, perhaps with a try/finally? I'm not entirely sure this is a good idea, by the way. May there be some drawbacks?
msg135648 - (view) Author: Brian Curtin (brian.curtin) * (Python committer) Date: 2011-05-09 21:02
Actually, I don't think the wait() is a good idea. If you want to block and infinitely wait on the process to close, you should do so explicitly. It's probably better that we try to use terminate() or kill() and raise if that fails.
msg135649 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-05-09 21:05
> Actually, I don't think the wait() is a good idea. If you want to > block and infinitely wait on the process to close, you should do so > explicitly. Ok. > It's probably better that we try to use terminate() or kill() and raise if that fails. Uh, I think it's worse. Using a context manager shouldn't do something potentially destructive like killing a process.
msg135652 - (view) Author: Brian Curtin (brian.curtin) * (Python committer) Date: 2011-05-09 21:11
Hm, yeah, not sure what I was thinking there. I'm thinking there's not a lot we can do here, but also not a lot that we should do here. We don't want to wait, and we don't want to close, so maybe we should just document that the usage should be limited only to expecting the open handles to be closed?
msg135658 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-05-09 22:00
> I'm thinking there's not a lot we can do here, but also not a lot that > we should do here. We don't want to wait, and we don't want to close, > so maybe we should just document that the usage should be limited only > to expecting the open handles to be closed? Sounds good indeed :)
msg135675 - (view) Author: Brian Curtin (brian.curtin) * (Python committer) Date: 2011-05-10 02:28
Looks like we already mention that. """ Popen objects are supported as context managers via the with statement, closing any open file descriptors on exit. """ Antoine, do you think this should be more strongly worded?
msg135690 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2011-05-10 09:11
Well, no, looks ok for me then :)
msg135715 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2011-05-10 16:08
There's just one thing I'm concerned with. People using context managers tend to expect the __exit__ method to perform cleanup actions and release corresponding resources if necessary, for example closing the underlying file or socket. So my guess is that most people won't explicitly wait for the process termination. You can already find such examples inside test_subprocess.py, Lib/ctypes/util.py (to parse ldconfig's output), and even in subprocess' documentation: """ with Popen(["ifconfig"], stdout=PIPE) as proc: log.write(proc.stdout.read()) """ The problem is that until a child process is wait()ed on or its parent process terminates (so that the child gets re-parented to init), the child remains a zombie/defunct process. So if you have long-running process spawning many subprocesses, you could end up having many zombie processes, potentially filling up your process table at some point. And this really sucks. So I think it could be worth mentioning this somewhere in the documentation (I mean, if we can find find such leaks inside CPython code base, then it's definitely something that should be documented).
msg135765 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2011-05-11 08:57
I didn't initially like the idea of __exit__ blocking on another process... but the zombie issue is real does make me think we should reconsider this and have it wait(). It is a backwards incompatible change if anyone has started using the Popen context manager to launch a long running subprocess that they did not want to wait for. That should be exceedingly rare. I say change the behavior to wait() in 3.3, 3.2.1 and 2.7.2. Keep the note in the documentation and turn it into something that stands out better like a note or a warning suggesting that people always call wait() after the Popen context manager exits if they need to be compatible with 2.7.1 or earlier.
msg135783 - (view) Author: Charles-François Natali (neologix) * (Python committer) Date: 2011-05-11 16:44
I'm re-opening this issue, since Gregory agrees to change the current behaviour. Patch attached (along with test and documentation update).
msg135814 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2011-05-12 04:42
New changeset 7a3f3ad83676 by Gregory P. Smith in branch 'default': - Issue #12044: Fixed subprocess.Popen when used as a context manager to http://hg.python.org/cpython/rev/7a3f3ad83676
msg135815 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2011-05-12 05:20
New changeset b00a64a5cb93 by Gregory P. Smith in branch '3.2': merge - 7a3f3ad83676 Fixes Issue #12044. http://hg.python.org/cpython/rev/b00a64a5cb93
msg135816 - (view) Author: Gregory P. Smith (gregory.p.smith) * (Python committer) Date: 2011-05-12 05:23
did my commits in the reverse order (default before 3.2), oops. this is fixed. this wasn't ever in 2.7 so no need for the documentation note. i'm not worried about adding a note about 3.2.0 vs 3.2.1 beyond the mention in Misc/NEWS as this was new in 3.2.0 and fixing this behavior is a pretty clear bug fix.
msg135841 - (view) Author: Roundup Robot (python-dev) (Python triager) Date: 2011-05-12 14:48
New changeset 361f87c8f36a by Łukasz Langa in branch 'default': Cleaned up a backward merge after fixes issue #12044. http://hg.python.org/cpython/rev/361f87c8f36a
msg139904 - (view) Author: STINNER Victor (vstinner) * (Python committer) Date: 2011-07-05 20:36
See also issue #12494: "subprocess: check_output() doesn't close pipes on error".
History
Date User Action Args
2022-04-11 14:57:17 admin set github: 56253
2011-07-05 20:36:58 vstinner set nosy: + vstinnermessages: +
2011-05-12 14:48:27 python-dev set messages: +
2011-05-12 05:23:31 gregory.p.smith set status: open -> closedresolution: acceptedmessages: +
2011-05-12 05:20:58 python-dev set messages: +
2011-05-12 04:42:23 python-dev set nosy: + python-devmessages: +
2011-05-11 20:12:57 gregory.p.smith set assignee: gregory.p.smith
2011-05-11 16:44:29 neologix set status: closed -> openfiles: + subprocess_zombie.diffmessages: + components: + Library (Lib)keywords: + patchresolution: rejected -> (no value)
2011-05-11 08:57:51 gregory.p.smith set messages: +
2011-05-10 16:08:26 neologix set messages: +
2011-05-10 09:11:45 pitrou set status: pending -> closedresolution: rejectedmessages: +
2011-05-10 02:28:20 brian.curtin set status: open -> pendingmessages: +
2011-05-09 22:00:40 pitrou set messages: +
2011-05-09 21:11:27 brian.curtin set messages: +
2011-05-09 21:05:14 pitrou set messages: +
2011-05-09 21:02:25 brian.curtin set messages: +
2011-05-09 20:42:15 pitrou set messages: +
2011-05-09 20:41:02 brian.curtin set messages: +
2011-05-09 19:24:14 pitrou create