joyent/libuv — pull request #343 by eladb (2012-03-12 18:02:31+00:00)
Title: win: Close child pipes when child exits (+ test)

The reason this is needed on Windows is that the pipe handles that are
passed to the child process via `CreateProcess` must be inheritable and
therefore automatically passed to grandchildren (and further). This causes
the pipes to remain open even if the child process exits, because there are
open file handles on that pipe.

The impact on users is that they cannot trust that the streams will be
closed when the child process exits. node.js for example, waits for these
`close` events before emitting the `exit` event on the child process (see
joyent/node#2914).

On unix systems, the file descriptors of the pipes are not inherited by
descendents of the child process and therefore, when the child dies, the pipes
are closed automatically.

There doesn't seem to be a way to tell Windows either to destroy the pipes
or not to inherit the handles. This could be done from the child process but
the child process cannot be trusted to do it.

Some alternatives we tried:

* Reverse the roles of the named pipe (sending the server handle to the
child process as stdio instead of the client handle) -- same behavior.
* Try to use a different way to identify that a client was closed (since
we use async I/O, we don't get a 0-bytes read indication on child closed
(seems like this could have worked but obviously we can't do synchronous
read from the pipe).
* Many more variations of `DuplicateHandle`, `SetHandleInformation`,
`Get|SetStdHandle` and more.

This also reproduces on a stand-alone Windows program.

PS. another side effect of the handle inheritence is that each level in the
child process hierarchy has 3 more open file handles (first level has 3,
second has 6, third has 9, etc). Could have some perf impact on deep process
trees.

Contributed: @yosefd @saary