summaryrefslogtreecommitdiffstats
path: root/Utilities/cmlibuv/src/win/tty.c
diff options
context:
space:
mode:
authorBrad King <brad.king@kitware.com>2016-09-29 18:19:51 (GMT)
committerBrad King <brad.king@kitware.com>2016-09-29 18:19:51 (GMT)
commitf9cab9e38df8adeac5f83f80722dedff25affdcd (patch)
treeedb096f74dd246dc2fc7787bcecbbbbb1437e06a /Utilities/cmlibuv/src/win/tty.c
parent5d29506811c5b75ae48e12de6c317f6440874215 (diff)
parent66ac1febc41967599d5bdaab912d786879ce6813 (diff)
downloadCMake-f9cab9e38df8adeac5f83f80722dedff25affdcd.zip
CMake-f9cab9e38df8adeac5f83f80722dedff25affdcd.tar.gz
CMake-f9cab9e38df8adeac5f83f80722dedff25affdcd.tar.bz2
Merge branch 'upstream-libuv' into update-libuv
* upstream-libuv: libuv 2016-09-27 (8221f9b3)
Diffstat (limited to 'Utilities/cmlibuv/src/win/tty.c')
-rw-r--r--Utilities/cmlibuv/src/win/tty.c94
1 files changed, 57 insertions, 37 deletions
diff --git a/Utilities/cmlibuv/src/win/tty.c b/Utilities/cmlibuv/src/win/tty.c
index 0975b33..18d68d0 100644
--- a/Utilities/cmlibuv/src/win/tty.c
+++ b/Utilities/cmlibuv/src/win/tty.c
@@ -111,7 +111,11 @@ static int uv_tty_virtual_offset = -1;
static int uv_tty_virtual_height = -1;
static int uv_tty_virtual_width = -1;
-static CRITICAL_SECTION uv_tty_output_lock;
+/* We use a semaphore rather than a mutex or critical section because in some
+ cases (uv__cancel_read_console) we need take the lock in the main thread and
+ release it in another thread. Using a semaphore ensures that in such
+ scenario the main thread will still block when trying to acquire the lock. */
+static uv_sem_t uv_tty_output_lock;
static HANDLE uv_tty_output_handle = INVALID_HANDLE_VALUE;
@@ -134,7 +138,8 @@ static uv_vtermstate_t uv__vterm_state = UV_UNCHECKED;
static void uv__determine_vterm_state(HANDLE handle);
void uv_console_init() {
- InitializeCriticalSection(&uv_tty_output_lock);
+ if (uv_sem_init(&uv_tty_output_lock, 1))
+ abort();
}
@@ -172,7 +177,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
/* Obtain the the tty_output_lock because the virtual window state is */
/* shared between all uv_tty_t handles. */
- EnterCriticalSection(&uv_tty_output_lock);
+ uv_sem_wait(&uv_tty_output_lock);
if (uv__vterm_state == UV_UNCHECKED)
uv__determine_vterm_state(handle);
@@ -187,7 +192,7 @@ int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
uv_tty_update_virtual_window(&screen_buffer_info);
- LeaveCriticalSection(&uv_tty_output_lock);
+ uv_sem_post(&uv_tty_output_lock);
}
@@ -315,10 +320,6 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
return UV_EINVAL;
}
- if (!SetConsoleMode(tty->handle, flags)) {
- return uv_translate_sys_error(GetLastError());
- }
-
/* If currently reading, stop, and restart reading. */
if (tty->flags & UV_HANDLE_READING) {
was_reading = 1;
@@ -332,6 +333,14 @@ int uv_tty_set_mode(uv_tty_t* tty, uv_tty_mode_t mode) {
was_reading = 0;
}
+ uv_sem_wait(&uv_tty_output_lock);
+ if (!SetConsoleMode(tty->handle, flags)) {
+ err = uv_translate_sys_error(GetLastError());
+ uv_sem_post(&uv_tty_output_lock);
+ return err;
+ }
+ uv_sem_post(&uv_tty_output_lock);
+
/* Update flag. */
tty->flags &= ~UV_HANDLE_TTY_RAW;
tty->flags |= mode ? UV_HANDLE_TTY_RAW : 0;
@@ -361,9 +370,9 @@ int uv_tty_get_winsize(uv_tty_t* tty, int* width, int* height) {
return uv_translate_sys_error(GetLastError());
}
- EnterCriticalSection(&uv_tty_output_lock);
+ uv_sem_wait(&uv_tty_output_lock);
uv_tty_update_virtual_window(&info);
- LeaveCriticalSection(&uv_tty_output_lock);
+ uv_sem_post(&uv_tty_output_lock);
*width = uv_tty_virtual_width;
*height = uv_tty_virtual_height;
@@ -432,6 +441,7 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
DWORD chars, read_chars;
LONG status;
COORD pos;
+ BOOL read_console_success;
assert(data);
@@ -461,11 +471,13 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
return 0;
}
- if (ReadConsoleW(handle->handle,
- (void*) utf16,
- chars,
- &read_chars,
- NULL)) {
+ read_console_success = ReadConsoleW(handle->handle,
+ (void*) utf16,
+ chars,
+ &read_chars,
+ NULL);
+
+ if (read_console_success) {
read_bytes = WideCharToMultiByte(CP_UTF8,
0,
utf16,
@@ -480,33 +492,36 @@ static DWORD CALLBACK uv_tty_line_read_thread(void* data) {
SET_REQ_ERROR(req, GetLastError());
}
- InterlockedExchange(&uv__read_console_status, COMPLETED);
+ status = InterlockedExchange(&uv__read_console_status, COMPLETED);
- /* If we canceled the read by sending a VK_RETURN event, restore the screen
- state to undo the visual effect of the VK_RETURN*/
- if (InterlockedOr(&uv__restore_screen_state, 0)) {
- HANDLE active_screen_buffer = CreateFileA("conout$",
+ if (status == TRAP_REQUESTED) {
+ /* If we canceled the read by sending a VK_RETURN event, restore the
+ screen state to undo the visual effect of the VK_RETURN */
+ if (read_console_success && InterlockedOr(&uv__restore_screen_state, 0)) {
+ HANDLE active_screen_buffer;
+ active_screen_buffer = CreateFileA("conout$",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
- if (active_screen_buffer != INVALID_HANDLE_VALUE) {
- pos = uv__saved_screen_state.dwCursorPosition;
-
- /* If the cursor was at the bottom line of the screen buffer, the
- VK_RETURN would have caused the buffer contents to scroll up by
- one line. The right position to reset the cursor to is therefore one
- line higher */
- if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
- pos.Y--;
-
- SetConsoleCursorPosition(active_screen_buffer, pos);
- CloseHandle(active_screen_buffer);
+ if (active_screen_buffer != INVALID_HANDLE_VALUE) {
+ pos = uv__saved_screen_state.dwCursorPosition;
+
+ /* If the cursor was at the bottom line of the screen buffer, the
+ VK_RETURN would have caused the buffer contents to scroll up by one
+ line. The right position to reset the cursor to is therefore one line
+ higher */
+ if (pos.Y == uv__saved_screen_state.dwSize.Y - 1)
+ pos.Y--;
+
+ SetConsoleCursorPosition(active_screen_buffer, pos);
+ CloseHandle(active_screen_buffer);
+ }
}
+ uv_sem_post(&uv_tty_output_lock);
}
-
POST_COMPLETION_FOR_REQ(loop, req);
return 0;
}
@@ -694,14 +709,14 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
if (handle->tty.rd.last_input_record.EventType == WINDOW_BUFFER_SIZE_EVENT) {
CONSOLE_SCREEN_BUFFER_INFO info;
- EnterCriticalSection(&uv_tty_output_lock);
+ uv_sem_wait(&uv_tty_output_lock);
if (uv_tty_output_handle != INVALID_HANDLE_VALUE &&
GetConsoleScreenBufferInfo(uv_tty_output_handle, &info)) {
uv_tty_update_virtual_window(&info);
}
- LeaveCriticalSection(&uv_tty_output_lock);
+ uv_sem_post(&uv_tty_output_lock);
continue;
}
@@ -1035,11 +1050,16 @@ static int uv__cancel_read_console(uv_tty_t* handle) {
assert(!(handle->flags & UV_HANDLE_CANCELLATION_PENDING));
+ /* Hold the output lock during the cancellation, to ensure that further
+ writes don't interfere with the screen state. It will be the ReadConsole
+ thread's responsibility to release the lock. */
+ uv_sem_wait(&uv_tty_output_lock);
status = InterlockedExchange(&uv__read_console_status, TRAP_REQUESTED);
if (status != IN_PROGRESS) {
/* Either we have managed to set a trap for the other thread before
ReadConsole is called, or ReadConsole has returned because the user
has pressed ENTER. In either case, there is nothing else to do. */
+ uv_sem_post(&uv_tty_output_lock);
return 0;
}
@@ -1624,7 +1644,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
/* state. */
*error = ERROR_SUCCESS;
- EnterCriticalSection(&uv_tty_output_lock);
+ uv_sem_wait(&uv_tty_output_lock);
for (i = 0; i < nbufs; i++) {
uv_buf_t buf = bufs[i];
@@ -2061,7 +2081,7 @@ static int uv_tty_write_bufs(uv_tty_t* handle,
handle->tty.wr.previous_eol = previous_eol;
handle->tty.wr.ansi_parser_state = ansi_parser_state;
- LeaveCriticalSection(&uv_tty_output_lock);
+ uv_sem_post(&uv_tty_output_lock);
if (*error == STATUS_SUCCESS) {
return 0;