Nested child_processes piping to stdout cause freeze #1726

isaacs opened this Issue Sep 17, 2011 · 6 comments


None yet

4 participants

isaacs commented Sep 17, 2011

Test script:

;(function () {

var gen = +(process.argv[2] || 0);
var maxGen = 5;

if (gen === maxGen) {
  console.log("hit maxGen, exiting", maxGen);

var ch = require("child_process");
var cp = ch.spawn("node", [__filename, gen + 1]);

console.log("gen=%d", gen);

var timer = setTimeout(function () {
  throw new Error("timeout! gen="+gen);
}, 1000);

cp.on("exit", function (code) {
  console.error("exit %d from gen %d", code, gen + 1);




$ node no-exit.js 
hit maxGen, exiting 5
exit 0 from gen 5
exit 0 from gen 4

  throw new Error("timeout! gen="+gen);
Error: timeout! gen=0
    at Object._onTimeout (/Users/isaacs/dev-src/js/semver/no-exit.js:19:9)
    at Timer.ontimeout (timers_uv.js:84:39)
felixge commented Sep 19, 2011

Which node version is this?

isaacs commented Sep 19, 2011

Sorry, forgot that. Master branch, 0.5.8-pre, 243c218.

@isaacs isaacs added a commit that referenced this issue Sep 23, 2011
@isaacs @ry isaacs + ry Add broken test for #1726. 74c0206
ry commented Sep 26, 2011

definitely a bug. the test has been landed in master but is broken.

works in windows!

ry commented Sep 27, 2011

Root cause:

This is decreasing the libev loop reference count, uv_default_loop()->ev->activecnt, below zero. libev keeps looping on non-zero activecnt see

libev has asserts to check for this (at least when the activecnt is below -1, which wouldn't have caught it in this case) but they are compiled out by default. I changed the uv gyp build to use EV_VERIFY=2 which should avoid this sort of problem in the future here joyent/libuv@2c01791
deps/uv/src/win/core.c has a similar assert.

This example is illustrative:

console.error("process.stdout._type = " + process.stdout._type);
process.stdout.write('hello world\n');

After process.stdout is closed, the reference count in the loop is -1. There is another bug I had to first uncover which is that half-duplex streams are having uv_shutdown() called on them. fixes this.

Probably we need to stop using libev's reference counter. This has been a long time in the coming. I landed some tests in libuv in preparation for this switch

@ry ry closed this in 0f8f863 Sep 27, 2011
ry commented Sep 27, 2011

The above hack is pretty awful. It would be nice have the ability to "unref" a whole handle in libuv.

@ry ry added a commit that referenced this issue Sep 27, 2011
@ry ry Move process.stdout unref hack to
See #1726
koichik commented Sep 28, 2011

@ry - process.stdout is not defined with legacy backend.

$ ./node --use-legacy -e 'process.stdout.write("a")'

TypeError: Cannot call method 'unref' of undefined
    at EventEmitter.stdout (node.js:238:26)
    at Object.<anonymous> (eval at <anonymous> (eval:1:75))
    at Object.<anonymous> (eval:1:63)
    at Module._compile (module.js:432:26)
    at startup (node.js:96:14)
    at node.js:559:3
@indutny indutny added a commit that referenced this issue Jul 13, 2014
@indutny indutny test: fix regress-GH-1726 b692493
@sam-github sam-github pushed a commit to sam-github/node-v0.x-archive that referenced this issue Jul 18, 2015
@brendanashworth brendanashworth src: remove old code
The Socket writable only change was added and implemented in the
constructor around 5885f46, but this was never removed.

The libev counter issue is no longer prudent; the test remains in

PR-URL: nodejs/node#1819
Reviewed-By: Ben Noordhuis <>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment