Merge "adb: SIGWINCH support for Windows" am: c1eb5ba0fb
am: 41b04cf896
* commit '41b04cf89677836dba14903226df5c7a3d39adcd':
adb: SIGWINCH support for Windows
This commit is contained in:
commit
f74da513c8
3 changed files with 71 additions and 19 deletions
|
|
@ -472,18 +472,46 @@ static bool GetFeatureSet(TransportType transport_type, const char* serial, Feat
|
|||
}
|
||||
|
||||
static void send_window_size_change(int fd, std::unique_ptr<ShellProtocol>& shell) {
|
||||
#if !defined(_WIN32)
|
||||
// Old devices can't handle window size changes.
|
||||
if (shell == nullptr) return;
|
||||
|
||||
#if defined(_WIN32)
|
||||
struct winsize {
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_col;
|
||||
unsigned short ws_xpixel;
|
||||
unsigned short ws_ypixel;
|
||||
};
|
||||
#endif
|
||||
|
||||
winsize ws;
|
||||
|
||||
#if defined(_WIN32)
|
||||
// If stdout is redirected to a non-console, we won't be able to get the
|
||||
// console size, but that makes sense.
|
||||
const intptr_t intptr_handle = _get_osfhandle(STDOUT_FILENO);
|
||||
if (intptr_handle == -1) return;
|
||||
|
||||
const HANDLE handle = reinterpret_cast<const HANDLE>(intptr_handle);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (!GetConsoleScreenBufferInfo(handle, &info)) return;
|
||||
|
||||
memset(&ws, 0, sizeof(ws));
|
||||
// The number of visible rows, excluding offscreen scroll-back rows which are in info.dwSize.Y.
|
||||
ws.ws_row = info.srWindow.Bottom - info.srWindow.Top + 1;
|
||||
// If the user has disabled "Wrap text output on resize", they can make the screen buffer wider
|
||||
// than the window, in which case we should use the width of the buffer.
|
||||
ws.ws_col = info.dwSize.X;
|
||||
#else
|
||||
if (ioctl(fd, TIOCGWINSZ, &ws) == -1) return;
|
||||
#endif
|
||||
|
||||
// Send the new window size as human-readable ASCII for debugging convenience.
|
||||
size_t l = snprintf(shell->data(), shell->data_capacity(), "%dx%d,%dx%d",
|
||||
ws.ws_row, ws.ws_col, ws.ws_xpixel, ws.ws_ypixel);
|
||||
shell->Write(ShellProtocol::kIdWindowSizeChange, l + 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Used to pass multiple values to the stdin read thread.
|
||||
|
|
@ -508,7 +536,10 @@ static void* stdin_read_thread_loop(void* x) {
|
|||
pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
// _get_interesting_input_record_uncached() causes unix_read_interruptible()
|
||||
// to return -1 with errno == EINTR if the window size changes.
|
||||
#else
|
||||
// Unblock SIGWINCH for this thread, so our read(2) below will be
|
||||
// interrupted if the window size changes.
|
||||
sigset_t mask;
|
||||
|
|
@ -537,20 +568,15 @@ static void* stdin_read_thread_loop(void* x) {
|
|||
EscapeState state = kStartOfLine;
|
||||
|
||||
while (true) {
|
||||
// Use unix_read() rather than adb_read() for stdin.
|
||||
D("stdin_read_thread_loop(): pre unix_read(fdi=%d,...)", args->stdin_fd);
|
||||
#if !defined(_WIN32)
|
||||
#undef read
|
||||
int r = read(args->stdin_fd, buffer_ptr, buffer_size);
|
||||
// Use unix_read_interruptible() rather than adb_read() for stdin.
|
||||
D("stdin_read_thread_loop(): pre unix_read_interruptible(fdi=%d,...)", args->stdin_fd);
|
||||
int r = unix_read_interruptible(args->stdin_fd, buffer_ptr,
|
||||
buffer_size);
|
||||
if (r == -1 && errno == EINTR) {
|
||||
send_window_size_change(args->stdin_fd, args->protocol);
|
||||
continue;
|
||||
}
|
||||
#define read ___xxx_read
|
||||
#else
|
||||
int r = unix_read(args->stdin_fd, buffer_ptr, buffer_size);
|
||||
#endif
|
||||
D("stdin_read_thread_loop(): post unix_read(fdi=%d,...)", args->stdin_fd);
|
||||
D("stdin_read_thread_loop(): post unix_read_interruptible(fdi=%d,...)", args->stdin_fd);
|
||||
if (r <= 0) {
|
||||
// Only devices using the shell protocol know to close subprocess
|
||||
// stdin. For older devices we want to just leave the connection
|
||||
|
|
|
|||
|
|
@ -164,8 +164,13 @@ static __inline__ int unix_close(int fd)
|
|||
#undef close
|
||||
#define close ____xxx_close
|
||||
|
||||
// Like unix_read(), but may return EINTR.
|
||||
extern int unix_read_interruptible(int fd, void* buf, size_t len);
|
||||
|
||||
// See the comments for the !defined(_WIN32) version of unix_read().
|
||||
extern int unix_read(int fd, void* buf, size_t len);
|
||||
static __inline__ int unix_read(int fd, void* buf, size_t len) {
|
||||
return TEMP_FAILURE_RETRY(unix_read_interruptible(fd, buf, len));
|
||||
}
|
||||
|
||||
#undef read
|
||||
#define read ___xxx_read
|
||||
|
|
@ -517,6 +522,11 @@ static __inline__ int adb_read(int fd, void* buf, size_t len)
|
|||
return TEMP_FAILURE_RETRY( read( fd, buf, len ) );
|
||||
}
|
||||
|
||||
// Like unix_read(), but does not handle EINTR.
|
||||
static __inline__ int unix_read_interruptible(int fd, void* buf, size_t len) {
|
||||
return read(fd, buf, len);
|
||||
}
|
||||
|
||||
#undef read
|
||||
#define read ___xxx_read
|
||||
|
||||
|
|
|
|||
|
|
@ -2588,6 +2588,18 @@ static bool _get_key_event_record(const HANDLE console, INPUT_RECORD* const inpu
|
|||
fatal("ReadConsoleInputA did not return one input record");
|
||||
}
|
||||
|
||||
// If the console window is resized, emulate SIGWINCH by breaking out
|
||||
// of read() with errno == EINTR. Note that there is no event on
|
||||
// vertical resize because we don't give the console our own custom
|
||||
// screen buffer (with CreateConsoleScreenBuffer() +
|
||||
// SetConsoleActiveScreenBuffer()). Instead, we use the default which
|
||||
// supports scrollback, but doesn't seem to raise an event for vertical
|
||||
// window resize.
|
||||
if (input_record->EventType == WINDOW_BUFFER_SIZE_EVENT) {
|
||||
errno = EINTR;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((input_record->EventType == KEY_EVENT) &&
|
||||
(input_record->Event.KeyEvent.bKeyDown)) {
|
||||
if (input_record->Event.KeyEvent.wRepeatCount == 0) {
|
||||
|
|
@ -3323,9 +3335,13 @@ void stdin_raw_init() {
|
|||
// Disable ENABLE_LINE_INPUT so that input is immediately sent.
|
||||
// Disable ENABLE_ECHO_INPUT to disable local echo. Disabling this
|
||||
// flag also seems necessary to have proper line-ending processing.
|
||||
if (!SetConsoleMode(in, _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
|
||||
ENABLE_LINE_INPUT |
|
||||
ENABLE_ECHO_INPUT))) {
|
||||
DWORD new_console_mode = _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
|
||||
ENABLE_LINE_INPUT |
|
||||
ENABLE_ECHO_INPUT);
|
||||
// Enable ENABLE_WINDOW_INPUT to get window resizes.
|
||||
new_console_mode |= ENABLE_WINDOW_INPUT;
|
||||
|
||||
if (!SetConsoleMode(in, new_console_mode)) {
|
||||
// This really should not fail.
|
||||
D("stdin_raw_init: SetConsoleMode() failed: %s",
|
||||
SystemErrorCodeToString(GetLastError()).c_str());
|
||||
|
|
@ -3353,8 +3369,8 @@ void stdin_raw_restore() {
|
|||
}
|
||||
}
|
||||
|
||||
// Called by 'adb shell' and 'adb exec-in' to read from stdin.
|
||||
int unix_read(int fd, void* buf, size_t len) {
|
||||
// Called by 'adb shell' and 'adb exec-in' (via unix_read()) to read from stdin.
|
||||
int unix_read_interruptible(int fd, void* buf, size_t len) {
|
||||
if ((fd == STDIN_FILENO) && (_console_handle != NULL)) {
|
||||
// If it is a request to read from stdin, and stdin_raw_init() has been
|
||||
// called, and it successfully configured the console, then read from
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue