process: use more direct sync I/O for stdio
This avoids routing writes through the full LibuvStreamWrap write machinery. In particular, it enables the next commit, because otherwise the callback passed to `_write()` would not be called synchronously for pipes on Windows (because the latter does not support `uv_try_write()`, even for blocking I/O). PR-URL: https://github.com/nodejs/node/pull/18019 Reviewed-By: Anatoli Papirovski <apapirovski@mac.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
This commit is contained in:
parent
c84582cbb6
commit
8b751f7eb7
@ -1,5 +1,8 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
const Buffer = require('buffer').Buffer;
|
||||||
|
const { writeBuffer } = process.binding('fs');
|
||||||
|
|
||||||
// Check that the port number is not NaN when coerced to a number,
|
// Check that the port number is not NaN when coerced to a number,
|
||||||
// is an integer and that it falls within the legal range of port numbers.
|
// is an integer and that it falls within the legal range of port numbers.
|
||||||
function isLegalPort(port) {
|
function isLegalPort(port) {
|
||||||
@ -9,7 +12,28 @@ function isLegalPort(port) {
|
|||||||
return +port === (+port >>> 0) && port <= 0xFFFF;
|
return +port === (+port >>> 0) && port <= 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeSyncWrite(fd) {
|
||||||
|
return function(chunk, enc, cb) {
|
||||||
|
if (enc !== 'buffer')
|
||||||
|
chunk = Buffer.from(chunk, enc);
|
||||||
|
|
||||||
|
this._bytesDispatched += chunk.length;
|
||||||
|
|
||||||
|
try {
|
||||||
|
writeBuffer(fd, chunk, 0, chunk.length, null);
|
||||||
|
} catch (ex) {
|
||||||
|
// Legacy: net writes have .code === .errno, whereas writeBuffer gives the
|
||||||
|
// raw errno number in .errno.
|
||||||
|
if (typeof ex.code === 'string')
|
||||||
|
ex.errno = ex.code;
|
||||||
|
return cb(ex);
|
||||||
|
}
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
isLegalPort,
|
isLegalPort,
|
||||||
|
makeSyncWrite,
|
||||||
normalizedArgsSymbol: Symbol('normalizedArgs')
|
normalizedArgsSymbol: Symbol('normalizedArgs')
|
||||||
};
|
};
|
||||||
|
16
lib/net.js
16
lib/net.js
@ -26,7 +26,11 @@ const stream = require('stream');
|
|||||||
const timers = require('timers');
|
const timers = require('timers');
|
||||||
const util = require('util');
|
const util = require('util');
|
||||||
const internalUtil = require('internal/util');
|
const internalUtil = require('internal/util');
|
||||||
const { isLegalPort, normalizedArgsSymbol } = require('internal/net');
|
const {
|
||||||
|
isLegalPort,
|
||||||
|
normalizedArgsSymbol,
|
||||||
|
makeSyncWrite
|
||||||
|
} = require('internal/net');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const cares = process.binding('cares_wrap');
|
const cares = process.binding('cares_wrap');
|
||||||
const {
|
const {
|
||||||
@ -220,20 +224,24 @@ function Socket(options) {
|
|||||||
this._handle = options.handle; // private
|
this._handle = options.handle; // private
|
||||||
this[async_id_symbol] = getNewAsyncId(this._handle);
|
this[async_id_symbol] = getNewAsyncId(this._handle);
|
||||||
} else if (options.fd !== undefined) {
|
} else if (options.fd !== undefined) {
|
||||||
this._handle = createHandle(options.fd, false);
|
const fd = options.fd;
|
||||||
this._handle.open(options.fd);
|
this._handle = createHandle(fd, false);
|
||||||
|
this._handle.open(fd);
|
||||||
this[async_id_symbol] = this._handle.getAsyncId();
|
this[async_id_symbol] = this._handle.getAsyncId();
|
||||||
// options.fd can be string (since it is user-defined),
|
// options.fd can be string (since it is user-defined),
|
||||||
// so changing this to === would be semver-major
|
// so changing this to === would be semver-major
|
||||||
// See: https://github.com/nodejs/node/pull/11513
|
// See: https://github.com/nodejs/node/pull/11513
|
||||||
// eslint-disable-next-line eqeqeq
|
// eslint-disable-next-line eqeqeq
|
||||||
if ((options.fd == 1 || options.fd == 2) &&
|
if ((fd == 1 || fd == 2) &&
|
||||||
(this._handle instanceof Pipe) &&
|
(this._handle instanceof Pipe) &&
|
||||||
process.platform === 'win32') {
|
process.platform === 'win32') {
|
||||||
// Make stdout and stderr blocking on Windows
|
// Make stdout and stderr blocking on Windows
|
||||||
var err = this._handle.setBlocking(true);
|
var err = this._handle.setBlocking(true);
|
||||||
if (err)
|
if (err)
|
||||||
throw errnoException(err, 'setBlocking');
|
throw errnoException(err, 'setBlocking');
|
||||||
|
|
||||||
|
this._writev = null;
|
||||||
|
this._write = makeSyncWrite(fd);
|
||||||
}
|
}
|
||||||
this.readable = options.readable !== false;
|
this.readable = options.readable !== false;
|
||||||
this.writable = options.writable !== false;
|
this.writable = options.writable !== false;
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
const util = require('util');
|
const util = require('util');
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
const { TTY, isTTY } = process.binding('tty_wrap');
|
const { TTY, isTTY } = process.binding('tty_wrap');
|
||||||
|
const { makeSyncWrite } = require('internal/net');
|
||||||
const { inherits } = util;
|
const { inherits } = util;
|
||||||
const errnoException = util._errnoException;
|
const errnoException = util._errnoException;
|
||||||
const errors = require('internal/errors');
|
const errors = require('internal/errors');
|
||||||
@ -91,6 +92,8 @@ function WriteStream(fd) {
|
|||||||
// even though it was originally intended to change in v1.0.2 (Libuv 1.2.1).
|
// even though it was originally intended to change in v1.0.2 (Libuv 1.2.1).
|
||||||
// Ref: https://github.com/nodejs/node/pull/1771#issuecomment-119351671
|
// Ref: https://github.com/nodejs/node/pull/1771#issuecomment-119351671
|
||||||
this._handle.setBlocking(true);
|
this._handle.setBlocking(true);
|
||||||
|
this._writev = null;
|
||||||
|
this._write = makeSyncWrite(fd);
|
||||||
|
|
||||||
var winSize = new Array(2);
|
var winSize = new Array(2);
|
||||||
var err = this._handle.getWindowSize(winSize);
|
var err = this._handle.getWindowSize(winSize);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user