[VM] Refactored console configuration out of platform_*.cc into console_config.h and reapplied c9700040c3 for POSIX platforms (Windows needs more work). We may also want to move code in bin/stdio.h.

Change-Id: Ic7cbc690f490e0127387d9a23866ea7eddbc84cf
Reviewed-on: https://dart-review.googlesource.com/45746
Commit-Queue: Ben Konyi <bkonyi@google.com>
Reviewed-by: Zach Anderson <zra@google.com>
This commit is contained in:
Ben Konyi
2018-03-12 20:31:09 +00:00
committed by commit-bot@chromium.org
parent 180866dc46
commit 3c8d3b6870
12 changed files with 287 additions and 121 deletions
+26
View File
@@ -0,0 +1,26 @@
// Copyright (c) 2018, 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.
#ifndef RUNTIME_BIN_CONSOLE_H_
#define RUNTIME_BIN_CONSOLE_H_
#include "platform/globals.h"
namespace dart {
namespace bin {
class Console {
public:
static void SaveConfig();
static void RestoreConfig();
private:
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Console);
};
} // namespace bin
} // namespace dart
#endif // RUNTIME_BIN_CONSOLE_H_
+92
View File
@@ -0,0 +1,92 @@
// Copyright (c) 2018, 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.
#include "platform/globals.h"
#if defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || \
defined(HOST_OS_ANDROID) || defined(HOST_OS_FUCHSIA)
#include "bin/console.h"
#include <errno.h>
#include <sys/ioctl.h>
#include <termios.h>
#include "bin/fdutils.h"
#include "platform/signal_blocker.h"
namespace dart {
namespace bin {
class PosixConsole {
public:
static const tcflag_t kInvalidFlag = -1;
static void Initialize() {
SaveMode(STDOUT_FILENO, &stdout_initial_c_lflag_);
SaveMode(STDERR_FILENO, &stderr_initial_c_lflag_);
SaveMode(STDIN_FILENO, &stdin_initial_c_lflag_);
}
static void Cleanup() {
RestoreMode(STDOUT_FILENO, stdout_initial_c_lflag_);
RestoreMode(STDERR_FILENO, stderr_initial_c_lflag_);
RestoreMode(STDIN_FILENO, stdin_initial_c_lflag_);
ClearLFlags();
}
private:
static tcflag_t stdout_initial_c_lflag_;
static tcflag_t stderr_initial_c_lflag_;
static tcflag_t stdin_initial_c_lflag_;
static void ClearLFlags() {
stdout_initial_c_lflag_ = kInvalidFlag;
stderr_initial_c_lflag_ = kInvalidFlag;
stdin_initial_c_lflag_ = kInvalidFlag;
}
static void SaveMode(intptr_t fd, tcflag_t* flag) {
ASSERT(flag != NULL);
struct termios term;
int status = NO_RETRY_EXPECTED(tcgetattr(fd, &term));
if (status != 0) {
return;
}
*flag = term.c_lflag;
}
static void RestoreMode(intptr_t fd, tcflag_t flag) {
if (flag == kInvalidFlag) {
return;
}
struct termios term;
int status = NO_RETRY_EXPECTED(tcgetattr(fd, &term));
if (status != 0) {
return;
}
term.c_lflag = flag;
NO_RETRY_EXPECTED(tcsetattr(fd, TCSANOW, &term));
}
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(PosixConsole);
};
tcflag_t PosixConsole::stdout_initial_c_lflag_ = PosixConsole::kInvalidFlag;
tcflag_t PosixConsole::stderr_initial_c_lflag_ = PosixConsole::kInvalidFlag;
tcflag_t PosixConsole::stdin_initial_c_lflag_ = PosixConsole::kInvalidFlag;
void Console::SaveConfig() {
PosixConsole::Initialize();
}
void Console::RestoreConfig() {
PosixConsole::Cleanup();
}
} // namespace bin
} // namespace dart
#endif // defined(HOST_OS_LINUX) || defined(HOST_OS_MACOS) || \
// defined(HOST_OS_ANDROID) || defined(HOST_OS_FUCHSIA)
+143
View File
@@ -0,0 +1,143 @@
// Copyright (c) 2018, 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.
#include "platform/globals.h"
#if defined(HOST_OS_WINDOWS)
#include "bin/console.h"
#include "bin/file.h"
#include "bin/lockers.h"
#include "bin/platform.h"
#include "bin/utils.h"
#include "bin/utils_win.h"
// These are not always defined in the header files. See:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
#endif
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
namespace dart {
namespace bin {
class ConsoleWin {
public:
static const int kInvalidFlag = -1;
static void Initialize() {
saved_output_cp_ = kInvalidFlag;
saved_input_cp_ = kInvalidFlag;
// Set up a signal handler that restores the console state on a
// CTRL_C_EVENT signal. This will only run when there is no signal handler
// registered for the CTRL_C_EVENT from Dart code.
SetConsoleCtrlHandler(SignalHandler, TRUE);
// Set both the input and output code pages to UTF8.
const int output_cp = GetConsoleOutputCP();
const int input_cp = GetConsoleCP();
if (output_cp != CP_UTF8) {
SetConsoleOutputCP(CP_UTF8);
saved_output_cp_ = output_cp;
}
if (input_cp != CP_UTF8) {
SetConsoleCP(CP_UTF8);
saved_input_cp_ = input_cp;
}
// Try to set the bits for ANSI support, but swallow any failures.
saved_stdout_mode_ =
ModifyMode(STD_OUTPUT_HANDLE, ENABLE_VIRTUAL_TERMINAL_PROCESSING);
// TODO(28984): Due to issue #29104, we cannot set
// ENABLE_VIRTUAL_TERMINAL_INPUT here, as it causes ENABLE_PROCESSED_INPUT
// to be ignored.
}
static void Cleanup() {
// STD_OUTPUT_HANDLE, may have been closed or redirected. Therefore, we
// explicitly open the CONOUT$, CONERR$ and CONIN$ devices, so that we can
// be sure that we are really restoring the console to its original state.
if (saved_stdout_mode_ != kInvalidFlag) {
CleanupDevices("CONOUT$", STD_OUTPUT_HANDLE, saved_stdout_mode_);
saved_stdout_mode_ = kInvalidFlag;
}
if (saved_output_cp_ != kInvalidFlag) {
SetConsoleOutputCP(saved_output_cp_);
saved_output_cp_ = kInvalidFlag;
}
if (saved_input_cp_ != kInvalidFlag) {
SetConsoleCP(saved_input_cp_);
saved_input_cp_ = kInvalidFlag;
}
}
private:
static int saved_output_cp_;
static int saved_input_cp_;
static DWORD saved_stdout_mode_;
static BOOL WINAPI SignalHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
Cleanup();
}
return FALSE;
}
static DWORD ModifyMode(DWORD handle, DWORD flags) {
HANDLE h = GetStdHandle(handle);
DWORD mode;
DWORD old_mode = 0;
if ((h != INVALID_HANDLE_VALUE) && GetConsoleMode(h, &mode)) {
old_mode = mode;
if (flags != 0) {
const DWORD request = mode | flags;
SetConsoleMode(h, request);
}
}
return old_mode;
}
static void CleanupDevices(const char* device,
DWORD handle,
DWORD orig_flags) {
const intptr_t kWideBufLen = 64;
wchar_t widebuf[kWideBufLen];
int result =
MultiByteToWideChar(CP_UTF8, 0, device, -1, widebuf, kWideBufLen);
ASSERT(result != 0);
HANDLE h = CreateFileW(widebuf, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (h != INVALID_HANDLE_VALUE) {
SetStdHandle(STD_OUTPUT_HANDLE, h);
if (orig_flags != kInvalidFlag) {
SetConsoleMode(h, orig_flags);
}
}
}
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(ConsoleWin);
};
int ConsoleWin::saved_output_cp_ = ConsoleWin::kInvalidFlag;
int ConsoleWin::saved_input_cp_ = ConsoleWin::kInvalidFlag;
DWORD ConsoleWin::saved_stdout_mode_ = ConsoleWin::kInvalidFlag;
void Console::SaveConfig() {
ConsoleWin::Initialize();
}
void Console::RestoreConfig() {
ConsoleWin::Cleanup();
}
} // namespace bin
} // namespace dart
#endif // defined(HOST_OS_WINDOWS)
+2
View File
@@ -12,6 +12,7 @@
#include <cstdarg>
#include "bin/builtin.h"
#include "bin/console.h"
#include "bin/dartutils.h"
#include "bin/dfe.h"
#include "bin/eventhandler.h"
@@ -1489,6 +1490,7 @@ int main(int argc, char** argv) {
Log::PrintErr("Initialization failed\n");
return kErrorExitCode;
}
Console::SaveConfig();
Thread::InitOnce();
Loader::InitOnce();
DartUtils::SetOriginalWorkingDirectory();
+3
View File
@@ -5,6 +5,9 @@
# This file contains some C++ sources for the dart:io library. The other
# implementation files are in builtin_impl_sources.gypi.
io_impl_sources = [
"console.h",
"console_posix.cc",
"console_win.cc",
"eventhandler.cc",
"eventhandler.h",
"eventhandler_android.cc",
+4
View File
@@ -10,6 +10,7 @@
#include "include/dart_tools_api.h"
#include "bin/builtin.h"
#include "bin/console.h"
#include "bin/dartutils.h"
#include "bin/dfe.h"
#include "bin/directory.h"
@@ -1008,6 +1009,9 @@ void main(int argc, char** argv) {
Platform::Exit(kErrorExitCode);
}
// Save the console state so we can restore it at shutdown.
Console::SaveConfig();
// On Windows, the argv strings are code page encoded and not
// utf8. We need to convert them to utf8.
bool argv_converted = ShellUtils::GetUtf8Argv(argc, argv);
+3 -2
View File
@@ -7,14 +7,14 @@
#include "bin/platform.h"
#include <errno.h> // NOLINT
#include <signal.h> // NOLINT
#include <string.h> // NOLINT
#include <sys/utsname.h> // NOLINT
#include <unistd.h> // NOLINT
#include "bin/fdutils.h"
#include "bin/console.h"
#include "bin/file.h"
#include "bin/log.h"
namespace dart {
namespace bin {
@@ -152,6 +152,7 @@ const char* Platform::ResolveExecutablePath() {
}
void Platform::Exit(int exit_code) {
Console::RestoreConfig();
exit(exit_code);
}
+2
View File
@@ -14,6 +14,7 @@
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include "bin/console.h"
#include "bin/dartutils.h"
#include "bin/fdutils.h"
#include "bin/file.h"
@@ -147,6 +148,7 @@ const char* Platform::ResolveExecutablePath() {
}
void Platform::Exit(int exit_code) {
Console::RestoreConfig();
exit(exit_code);
}
+3 -2
View File
@@ -7,14 +7,14 @@
#include "bin/platform.h"
#include <errno.h> // NOLINT
#include <signal.h> // NOLINT
#include <string.h> // NOLINT
#include <sys/utsname.h> // NOLINT
#include <unistd.h> // NOLINT
#include "bin/fdutils.h"
#include "bin/console.h"
#include "bin/file.h"
#include "bin/log.h"
namespace dart {
namespace bin {
@@ -152,6 +152,7 @@ const char* Platform::ResolveExecutablePath() {
}
void Platform::Exit(int exit_code) {
Console::RestoreConfig();
exit(exit_code);
}
+3 -2
View File
@@ -12,6 +12,7 @@
#if !HOST_OS_IOS
#include <crt_externs.h> // NOLINT
#endif // !HOST_OS_IOS
#include <errno.h> // NOLINT
#include <mach-o/dyld.h>
#include <signal.h> // NOLINT
#include <string.h> // NOLINT
@@ -20,9 +21,8 @@
#include <sys/utsname.h> // NOLINT
#include <unistd.h> // NOLINT
#include "bin/fdutils.h"
#include "bin/console.h"
#include "bin/file.h"
#include "bin/log.h"
namespace dart {
namespace bin {
@@ -240,6 +240,7 @@ const char* Platform::ResolveExecutablePath() {
}
void Platform::Exit(int exit_code) {
Console::RestoreConfig();
exit(exit_code);
}
+2 -115
View File
@@ -9,6 +9,7 @@
#include <crtdbg.h>
#include "bin/console.h"
#include "bin/file.h"
#include "bin/lockers.h"
#include "bin/log.h"
@@ -19,15 +20,6 @@
#include "bin/utils.h"
#include "bin/utils_win.h"
// These are not always defined in the header files. See:
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms686033(v=vs.85).aspx
#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT
#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200
#endif
#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#endif
namespace dart {
@@ -44,9 +36,6 @@ char** Platform::argv_ = NULL;
class PlatformWin {
public:
static void InitOnce() {
platform_win_mutex_ = new Mutex();
saved_output_cp_ = -1;
saved_input_cp_ = -1;
// Set up a no-op handler so that CRT functions return an error instead of
// hitting an assertion failure.
// See: https://msdn.microsoft.com/en-us/library/a9yf33zb.aspx
@@ -59,58 +48,12 @@ class PlatformWin {
// See: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx
SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX |
SEM_NOGPFAULTERRORBOX);
// Set up a signal handler that restores the console state on a
// CTRL_C_EVENT signal. This will only run when there is no signal handler
// registered for the CTRL_C_EVENT from Dart code.
SetConsoleCtrlHandler(SignalHandler, TRUE);
#ifndef PRODUCT
// Set up global exception handler to be able to dump stack trace on crash.
SetExceptionHandler();
#endif
}
static BOOL WINAPI SignalHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) {
// We call this without taking the lock because this is a signal
// handler, and because the process is about to go down.
RestoreConsoleLocked();
}
return FALSE;
}
static void SaveAndConfigureConsole() {
MutexLocker ml(platform_win_mutex_);
// Set both the input and output code pages to UTF8.
ASSERT(saved_output_cp_ == -1);
ASSERT(saved_input_cp_ == -1);
const int output_cp = GetConsoleOutputCP();
const int input_cp = GetConsoleCP();
if (output_cp != CP_UTF8) {
SetConsoleOutputCP(CP_UTF8);
saved_output_cp_ = output_cp;
}
if (input_cp != CP_UTF8) {
SetConsoleCP(CP_UTF8);
saved_input_cp_ = input_cp;
}
// Try to set the bits for ANSI support, but swallow any failures.
HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);
DWORD out_mode;
if ((out != INVALID_HANDLE_VALUE) && GetConsoleMode(out, &out_mode)) {
const DWORD request = out_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(out, request);
}
// TODO(28984): Due to issue #29104, we cannot set
// ENABLE_VIRTUAL_TERMINAL_INPUT here, as it causes ENABLE_PROCESSED_INPUT
// to be ignored.
}
static void RestoreConsole() {
MutexLocker ml(platform_win_mutex_);
RestoreConsoleLocked();
}
// Windows top-level unhandled exception handler function.
// See MSDN documentation for UnhandledExceptionFilter.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms681401(v=vs.85).aspx
@@ -139,57 +82,6 @@ class PlatformWin {
}
private:
static Mutex* platform_win_mutex_;
static int saved_output_cp_;
static int saved_input_cp_;
static void RestoreConsoleLocked() {
// STD_OUTPUT_HANDLE and STD_INPUT_HANDLE may have been closed or
// redirected. Therefore, we explicitly open the CONOUT$ and CONIN$
// devices, so that we can be sure that we are really unsetting
// ENABLE_VIRTUAL_TERMINAL_PROCESSING and ENABLE_VIRTUAL_TERMINAL_INPUT
// respectively.
const intptr_t kWideBufLen = 64;
const char* conout = "CONOUT$";
wchar_t widebuf[kWideBufLen];
int result =
MultiByteToWideChar(CP_UTF8, 0, conout, -1, widebuf, kWideBufLen);
ASSERT(result != 0);
HANDLE out = CreateFileW(widebuf, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (out != INVALID_HANDLE_VALUE) {
SetStdHandle(STD_OUTPUT_HANDLE, out);
}
DWORD out_mode;
if ((out != INVALID_HANDLE_VALUE) && GetConsoleMode(out, &out_mode)) {
DWORD request = out_mode & ~ENABLE_VIRTUAL_TERMINAL_INPUT;
SetConsoleMode(out, request);
}
const char* conin = "CONIN$";
result = MultiByteToWideChar(CP_UTF8, 0, conin, -1, widebuf, kWideBufLen);
ASSERT(result != 0);
HANDLE in = CreateFileW(widebuf, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (in != INVALID_HANDLE_VALUE) {
SetStdHandle(STD_INPUT_HANDLE, in);
}
DWORD in_mode;
if ((in != INVALID_HANDLE_VALUE) && GetConsoleMode(in, &in_mode)) {
DWORD request = in_mode & ~ENABLE_VIRTUAL_TERMINAL_INPUT;
SetConsoleMode(in, request);
}
if (saved_output_cp_ != -1) {
SetConsoleOutputCP(saved_output_cp_);
saved_output_cp_ = -1;
}
if (saved_input_cp_ != -1) {
SetConsoleCP(saved_input_cp_);
saved_input_cp_ = -1;
}
}
static void InvalidParameterHandler(const wchar_t* expression,
const wchar_t* function,
const wchar_t* file,
@@ -203,13 +95,8 @@ class PlatformWin {
DISALLOW_IMPLICIT_CONSTRUCTORS(PlatformWin);
};
int PlatformWin::saved_output_cp_ = -1;
int PlatformWin::saved_input_cp_ = -1;
Mutex* PlatformWin::platform_win_mutex_ = NULL;
bool Platform::Initialize() {
PlatformWin::InitOnce();
PlatformWin::SaveAndConfigureConsole();
return true;
}
@@ -394,7 +281,7 @@ void Platform::Exit(int exit_code) {
// TODO(zra): Remove once VM shuts down cleanly.
::dart::private_flag_windows_run_tls_destructors = false;
// Restore the console's output code page
PlatformWin::RestoreConsole();
Console::RestoreConfig();
// On Windows we use ExitProcess so that threads can't clobber the exit_code.
// See: https://code.google.com/p/nativeclient/issues/detail?id=2870
::ExitProcess(exit_code);
+4
View File
@@ -4,6 +4,7 @@
#include <stdio.h>
#include "bin/console.h"
#include "bin/dartutils.h"
#include "bin/dfe.h"
#include "bin/eventhandler.h"
@@ -212,6 +213,9 @@ static int Main(int argc, const char** argv) {
return 1;
}
// Save the console state so we can restore it later.
dart::bin::Console::SaveConfig();
if (argc < 2) {
// Bad parameter count.
PrintUsage();