8c9c54d833
If an Isolate touches the 'stdio' getter, a _NativeSocket with attached finalizer is created for it. Previously, when such an Isolate exited, the finalizer would close the underlying file descriptor. This CL changes the finalizer for stdin such that the native objects will be cleaned up, but the underlying file descriptor will not be closed. The underlying file descriptor will now only be closed if the stdin stream subscription is explicitly canceled. Accessing the stdin getter after the stream is explicitly canceled will result in a FileSystemException. See also: https://github.com/dart-lang/test/issues/583 fixes #29229 R=rmacnak@google.com Review-Url: https://codereview.chromium.org/2791423002 .
156 lines
4.1 KiB
Dart
156 lines
4.1 KiB
Dart
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
@patch
|
|
class _StdIOUtils {
|
|
@patch
|
|
static Stdin _getStdioInputStream() {
|
|
switch (_getStdioHandleType(0)) {
|
|
case _STDIO_HANDLE_TYPE_TERMINAL:
|
|
case _STDIO_HANDLE_TYPE_PIPE:
|
|
case _STDIO_HANDLE_TYPE_SOCKET:
|
|
return new Stdin._(new _Socket._readPipe(0));
|
|
case _STDIO_HANDLE_TYPE_FILE:
|
|
return new Stdin._(new _FileStream.forStdin());
|
|
default:
|
|
throw new FileSystemException(
|
|
"Couldn't determine file type of stdin (fd 0)");
|
|
}
|
|
}
|
|
|
|
@patch
|
|
static _getStdioOutputStream(int fd) {
|
|
assert(fd == 1 || fd == 2);
|
|
switch (_getStdioHandleType(fd)) {
|
|
case _STDIO_HANDLE_TYPE_TERMINAL:
|
|
case _STDIO_HANDLE_TYPE_PIPE:
|
|
case _STDIO_HANDLE_TYPE_SOCKET:
|
|
case _STDIO_HANDLE_TYPE_FILE:
|
|
return new Stdout._(new IOSink(new _StdConsumer(fd)), fd);
|
|
default:
|
|
throw new FileSystemException(
|
|
"Couldn't determine file type of stdio handle (fd $fd)");
|
|
}
|
|
}
|
|
|
|
@patch
|
|
static int _socketType(Socket socket) {
|
|
if (socket is _Socket) return _nativeSocketType(socket._nativeSocket);
|
|
return null;
|
|
}
|
|
|
|
static int _nativeSocketType(_NativeSocket nativeSocket) {
|
|
var result = _getSocketType(nativeSocket);
|
|
if (result is OSError) {
|
|
throw new FileSystemException("Error retrieving socket type", "", result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@patch
|
|
static _getStdioHandleType(int fd) native "File_GetStdioHandleType";
|
|
}
|
|
|
|
@patch
|
|
class Stdin {
|
|
@patch
|
|
int readByteSync() {
|
|
var result = _readByte();
|
|
if (result is OSError) {
|
|
throw new StdinException("Error reading byte from stdin", result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@patch
|
|
bool get echoMode {
|
|
var result = _echoMode();
|
|
if (result is OSError) {
|
|
throw new StdinException("Error getting terminal echo mode", result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@patch
|
|
void set echoMode(bool enabled) {
|
|
var result = _setEchoMode(enabled);
|
|
if (result is OSError) {
|
|
throw new StdinException("Error setting terminal echo mode", result);
|
|
}
|
|
}
|
|
|
|
@patch
|
|
bool get lineMode {
|
|
var result = _lineMode();
|
|
if (result is OSError) {
|
|
throw new StdinException("Error getting terminal line mode", result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
@patch
|
|
void set lineMode(bool enabled) {
|
|
var result = _setLineMode(enabled);
|
|
if (result is OSError) {
|
|
throw new StdinException("Error setting terminal line mode", result);
|
|
}
|
|
}
|
|
|
|
@patch bool get supportsAnsiEscapes {
|
|
var result = _supportsAnsiEscapes();
|
|
if (result is OSError) {
|
|
throw new StdinException("Error determining ANSI support", result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static _echoMode() native "Stdin_GetEchoMode";
|
|
static _setEchoMode(bool enabled) native "Stdin_SetEchoMode";
|
|
static _lineMode() native "Stdin_GetLineMode";
|
|
static _setLineMode(bool enabled) native "Stdin_SetLineMode";
|
|
static _readByte() native "Stdin_ReadByte";
|
|
static _supportsAnsiEscapes() native "Stdin_AnsiSupported";
|
|
}
|
|
|
|
@patch
|
|
class Stdout {
|
|
@patch
|
|
bool _hasTerminal(int fd) {
|
|
try {
|
|
_terminalSize(fd);
|
|
return true;
|
|
} catch (_) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@patch
|
|
int _terminalColumns(int fd) => _terminalSize(fd)[0];
|
|
@patch
|
|
int _terminalLines(int fd) => _terminalSize(fd)[1];
|
|
|
|
static List _terminalSize(int fd) {
|
|
var size = _getTerminalSize(fd);
|
|
if (size is! List) {
|
|
throw new StdoutException("Could not get terminal size", size);
|
|
}
|
|
return size;
|
|
}
|
|
|
|
static _getTerminalSize(int fd) native "Stdout_GetTerminalSize";
|
|
|
|
@patch static bool _supportsAnsiEscapes(int fd) {
|
|
var result = _getAnsiSupported(fd);
|
|
if (result is! bool) {
|
|
throw new StdoutException("Error determining ANSI support", result);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static _getAnsiSupported(int fd) native "Stdout_AnsiSupported";
|
|
}
|
|
|
|
_getStdioHandle(_NativeSocket socket, int num) native "Socket_GetStdioHandle";
|
|
_getSocketType(_NativeSocket nativeSocket) native "Socket_GetType";
|