Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c1eb5ba0 authored by Josh Gao's avatar Josh Gao Committed by Gerrit Code Review
Browse files

Merge "adb: SIGWINCH support for Windows"

parents 4602f2b7 2e02dc63
Loading
Loading
Loading
Loading
+39 −13
Original line number Diff line number Diff line
@@ -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
+11 −1
Original line number Diff line number Diff line
@@ -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

+21 −5
Original line number Diff line number Diff line
@@ -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 |
    DWORD new_console_mode = _old_console_mode & ~(ENABLE_PROCESSED_INPUT |
                                                   ENABLE_LINE_INPUT |
                                                  ENABLE_ECHO_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