Fix a bug where an ExecFuture might hang on __destruct() if its process holds pipes
Summary:
I don't have a complete understanding of exactly what's going on here, but here's what I have been able to determine:
- ExecFuture has a long-standing bug where it may hang indefinitely in __destruct() if the other process holds pipes open, even though ExecFuture has closed the pipes.
- The new unit test reproduces this behavior.
- Mystery: I don't know why closing the pipes from our side isn't good enough.
- D4228 changed PhutilSocketChannel, which would previously tear down both pipes when either closed. Now it tears down only one pipe.
- Mystery: I'm not sure which pipe dies and which stays alive.
- This exposed T2248, where the remaining pipe kept the parent open and hanging in ExecFuture::__destruct().
Test Plan:
Added unit test, which failed. Made patch. Ran unit tests; tests passed.
Reproduced T2248 and ran "arc unit"; worked properly after this patch.
Reviewers: btrahan, vrana, ender, nh
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2248
Differential Revision: https://secure.phabricator.com/D4292