Skip to content

Commit

Permalink
tty: set the handle to blocking mode
Browse files Browse the repository at this point in the history
Refs: #1771
Refs: #6456
Refs: #6773
Refs: #7743
PR-URL: #6816
Reviewed-By: Fedor Indutny <fedor.indutny@gmail.com>
Reviewed-By: Saúl Ibarra Corretgé <saghul@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rod Vagg <rod@vagg.org>
Reviewed-By: Michaël Zasso <mic.besace@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
Fishrock123 authored and addaleax committed Aug 10, 2016
1 parent 4878e1c commit ab3306a
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 19 deletions.
11 changes: 11 additions & 0 deletions doc/api/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,17 @@ Path to the file used to store the persistent REPL history. The default path is
to an empty string (`""` or `" "`) disables persistent REPL history.


### `NODE_TTY_UNSAFE_ASYNC=1`
<!-- YAML
added: REPLACEME
-->

When set to `1`, writes to `stdout` and `stderr` will be non-blocking and
asynchronous when outputting to a TTY on platforms which support async stdio.
Setting this will void any guarantee that stdio will not be interleaved or
dropped at program exit. **Use of this mode is not recommended.**


[Buffer]: buffer.html#buffer_buffer
[debugger]: debugger.html
[REPL]: repl.html
Expand Down
44 changes: 27 additions & 17 deletions doc/api/process.md
Original file line number Diff line number Diff line change
Expand Up @@ -880,10 +880,9 @@ if (someConditionNotMet()) {
```

The reason this is problematic is because writes to `process.stdout` in Node.js
are usually *non-blocking* and may occur over multiple ticks of the Node.js
event loop.
Calling `process.exit()`, however, forces the process to exit *before* those
additional writes to `stdout` can be performed.
are sometimes *non-blocking* and may occur over multiple ticks of the Node.js
event loop. Calling `process.exit()`, however, forces the process to exit
*before* those additional writes to `stdout` can be performed.

Rather than calling `process.exit()` directly, the code *should* set the
`process.exitCode` and allow the process to exit naturally by avoiding
Expand Down Expand Up @@ -1451,15 +1450,20 @@ Android)
The `process.stderr` property returns a [Writable][] stream equivalent to or
associated with `stderr` (fd `2`).

`process.stderr` and `process.stdout` are unlike other streams in Node.js in
that they cannot be closed (calling [`end()`][] will throw an Error), they never
emit the [`'finish'`][] event, and writes can block when output is redirected to
a file (although disks are fast and operating systems normally employ write-back
caching so it should be a very rare occurrence indeed.)
Note: `process.stderr` and `process.stdout` differ from other Node.js streams
in several ways:
1. They cannot be closed ([`end()`][] will throw).
2. They never emit the [`'finish'`][] event.
3. Writes _can_ block when output is redirected to a file.
- Note that disks are fast and operating systems normally employ write-back
caching so this is very uncommon.
4. Writes on UNIX __will__ block by default if output is going to a TTY
(a terminal).
5. Windows functionality differs. Writes block except when output is going to a
TTY.

Additionally, `process.stderr` and `process.stdout` are blocking when outputting
to TTYs (terminals) on OS X as a workaround for the OS's very small, 1kb
buffer size. This is to prevent interleaving between `stdout` and `stderr`.
To check if Node.js is being run in a TTY context, read the `isTTY` property
on `process.stderr`, `process.stdout`, or `process.stdin`:

## process.stdin

Expand Down Expand Up @@ -1504,11 +1508,17 @@ console.log = (msg) => {
};
```

`process.stderr` and `process.stdout` are unlike other streams in Node.js in
that they cannot be closed (calling [`end()`][] will throw an Error), they never
emit the [`'finish'`][] event and that writes can block when output is
redirected to a file (although disks are fast and operating systems normally
employ write-back caching so it should be a very rare occurrence indeed.)
Note: `process.stderr` and `process.stdout` differ from other Node.js streams
in several ways:
1. They cannot be closed ([`end()`][] will throw).
2. They never emit the [`'finish'`][] event.
3. Writes _can_ block when output is redirected to a file.
- Note that disks are fast and operating systems normally employ write-back
caching so this is very uncommon.
4. Writes on UNIX __will__ block by default if output is going to a TTY
(a terminal).
5. Windows functionality differs. Writes block except when output is going to a
TTY.

To check if Node.js is being run in a TTY context, read the `isTTY` property
on `process.stderr`, `process.stdout`, or `process.stdin`:
Expand Down
7 changes: 7 additions & 0 deletions doc/node.1
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,13 @@ Path to the file used to store the persistent REPL history. The default path
is ~/.node_repl_history, which is overridden by this variable. Setting the
value to an empty string ("" or " ") disables persistent REPL history.

.TP
.BR NODE_TTY_UNSAFE_ASYNC=1
When set to 1, writes to stdout and stderr will be non-blocking and asynchronous
when outputting to a TTY on platforms which support async stdio.
Setting this will void any guarantee that stdio will not be interleaved or
dropped at program exit. \fBAvoid use.\fR


.SH RESOURCES AND DOCUMENTATION

Expand Down
4 changes: 2 additions & 2 deletions lib/tty.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ function WriteStream(fd) {
writable: true
});

// Prevents interleaved stdout/stderr output in OS X terminals.
// Prevents interleaved or dropped stdout/stderr output for terminals.
// As noted in the following reference, local TTYs tend to be quite fast and
// this behaviour has become expected due historical functionality on OS X,
// 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
if (process.platform === 'darwin') this._handle.setBlocking(true);
this._handle.setBlocking(process.env.NODE_TTY_UNSAFE_ASYNC !== '1');

var winSize = [];
var err = this._handle.getWindowSize(winSize);
Expand Down

0 comments on commit ab3306a

Please sign in to comment.