Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
src: make stdout/sterr pipes blocking
Browse files Browse the repository at this point in the history
Expose `setBlocking` on Pipe's and if a pipe is being created for stdio
on windows then make the pipes blocking.

This fixes test-stream2-stderr-sync.js on Windows.

Fixes #3584
  • Loading branch information
orangemocha authored and tjfontaine committed Feb 26, 2014
1 parent c1bb886 commit 20176a9
Show file tree
Hide file tree
Showing 6 changed files with 98 additions and 3 deletions.
11 changes: 10 additions & 1 deletion lib/net.js
Expand Up @@ -26,6 +26,8 @@ var util = require('util');
var assert = require('assert'); var assert = require('assert');
var cares = process.binding('cares_wrap'); var cares = process.binding('cares_wrap');
var uv = process.binding('uv'); var uv = process.binding('uv');
var Pipe = process.binding('pipe_wrap').Pipe;



var cluster; var cluster;
var errnoException = util._errnoException; var errnoException = util._errnoException;
Expand All @@ -34,7 +36,6 @@ function noop() {}


// constructor for lazy loading // constructor for lazy loading
function createPipe() { function createPipe() {
var Pipe = process.binding('pipe_wrap').Pipe;
return new Pipe(); return new Pipe();
} }


Expand Down Expand Up @@ -147,6 +148,14 @@ function Socket(options) {
} else if (!util.isUndefined(options.fd)) { } else if (!util.isUndefined(options.fd)) {
this._handle = createHandle(options.fd); this._handle = createHandle(options.fd);
this._handle.open(options.fd); this._handle.open(options.fd);
if ((options.fd == 1 || options.fd == 2) &&
(this._handle instanceof Pipe) &&
process.platform === 'win32') {
// Make stdout and stderr blocking on Windows
var err = this._handle.setBlocking(true);
if (err)
throw errnoException(err, 'setBlocking');
}
this.readable = options.readable !== false; this.readable = options.readable !== false;
this.writable = options.writable !== false; this.writable = options.writable !== false;
} else { } else {
Expand Down
2 changes: 2 additions & 0 deletions src/pipe_wrap.cc
Expand Up @@ -91,6 +91,8 @@ void PipeWrap::Initialize(Handle<Object> target,
NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref); NODE_SET_PROTOTYPE_METHOD(t, "unref", HandleWrap::Unref);
NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref); NODE_SET_PROTOTYPE_METHOD(t, "ref", HandleWrap::Ref);


NODE_SET_PROTOTYPE_METHOD(t, "setBlocking", StreamWrap::SetBlocking);

NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart); NODE_SET_PROTOTYPE_METHOD(t, "readStart", StreamWrap::ReadStart);
NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop); NODE_SET_PROTOTYPE_METHOD(t, "readStop", StreamWrap::ReadStop);
NODE_SET_PROTOTYPE_METHOD(t, "shutdown", StreamWrap::Shutdown); NODE_SET_PROTOTYPE_METHOD(t, "shutdown", StreamWrap::Shutdown);
Expand Down
12 changes: 11 additions & 1 deletion src/stream_wrap.cc
Expand Up @@ -87,7 +87,6 @@ void StreamWrap::UpdateWriteQueueSize() {
object()->Set(env()->write_queue_size_string(), write_queue_size); object()->Set(env()->write_queue_size_string(), write_queue_size);
} }



void StreamWrap::ReadStart(const FunctionCallbackInfo<Value>& args) { void StreamWrap::ReadStart(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate()); Environment* env = Environment::GetCurrent(args.GetIsolate());
HandleScope scope(env->isolate()); HandleScope scope(env->isolate());
Expand Down Expand Up @@ -496,6 +495,17 @@ void StreamWrap::WriteUcs2String(const FunctionCallbackInfo<Value>& args) {
WriteStringImpl<UCS2>(args); WriteStringImpl<UCS2>(args);
} }


void StreamWrap::SetBlocking(const FunctionCallbackInfo<Value>& args) {
Environment* env = Environment::GetCurrent(args.GetIsolate());
HandleScope scope(env->isolate());

StreamWrap* wrap = Unwrap<StreamWrap>(args.This());

assert(args.Length() > 0);
int err = uv_stream_set_blocking(wrap->stream(), args[0]->IsTrue());

args.GetReturnValue().Set(err);
}


void StreamWrap::AfterWrite(uv_write_t* req, int status) { void StreamWrap::AfterWrite(uv_write_t* req, int status) {
WriteWrap* req_wrap = CONTAINER_OF(req, WriteWrap, req_); WriteWrap* req_wrap = CONTAINER_OF(req, WriteWrap, req_);
Expand Down
2 changes: 2 additions & 0 deletions src/stream_wrap.h
Expand Up @@ -126,6 +126,8 @@ class StreamWrap : public HandleWrap {
static void WriteUtf8String(const v8::FunctionCallbackInfo<v8::Value>& args); static void WriteUtf8String(const v8::FunctionCallbackInfo<v8::Value>& args);
static void WriteUcs2String(const v8::FunctionCallbackInfo<v8::Value>& args); static void WriteUcs2String(const v8::FunctionCallbackInfo<v8::Value>& args);


static void SetBlocking(const v8::FunctionCallbackInfo<v8::Value>& args);

inline StreamWrapCallbacks* callbacks() const { inline StreamWrapCallbacks* callbacks() const {
return callbacks_; return callbacks_;
} }
Expand Down
69 changes: 69 additions & 0 deletions test/simple/test-child-process-stdout-flush-exit.js
@@ -0,0 +1,69 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.




var common = require('../common');
var assert = require('assert');
var path = require('path');

// if child process output to console and exit
if (process.argv[2] === 'child') {
console.log('hello');
for (var i = 0; i < 200; i++) {
console.log('filler');
}
console.log('goodbye');
process.exit(0);
} else {
// parent process
var spawn = require('child_process').spawn;

// spawn self as child
var child = spawn(process.argv[0], [process.argv[1], 'child']);

var gotHello = false;
var gotBye = false;

child.stderr.setEncoding('utf8');
child.stderr.on('data', function (data) {
console.log('parent stderr: ' + data);
assert.ok(false);
});

// check if we receive both 'hello' at start and 'goodbye' at end
child.stdout.setEncoding('utf8');
child.stdout.on('data', function (data) {
if (data.slice(0, 6) == 'hello\n') {
gotHello = true;
} else if (data.slice(data.length - 8) == 'goodbye\n') {
gotBye = true;
} else {
gotBye = false;
}
});

child.on('close', function (data) {
assert(gotHello);
assert(gotBye);
});
}
5 changes: 4 additions & 1 deletion test/simple/test-stream2-stderr-sync.js
Expand Up @@ -67,7 +67,10 @@ function child1() {
// using a net socket // using a net socket
function child2() { function child2() {
var net = require('net'); var net = require('net');
var socket = new net.Socket({ fd: 2 }); var socket = new net.Socket({
fd: 2,
readable: false,
writable: true});
socket.write('child 2\n'); socket.write('child 2\n');
socket.write('foo\n'); socket.write('foo\n');
socket.write('bar\n'); socket.write('bar\n');
Expand Down

0 comments on commit 20176a9

Please sign in to comment.