windows: separate uv_tty_t read state from write state
This commit is contained in:
parent
7cf1b67594
commit
88634c1405
@ -380,28 +380,35 @@ RB_HEAD(uv_timer_tree_s, uv_timer_s);
|
||||
/* half-duplex so read-state can safely overlap write-state. */
|
||||
#define UV_TTY_PRIVATE_FIELDS \
|
||||
HANDLE handle; \
|
||||
HANDLE read_line_handle; \
|
||||
uv_buf_t read_line_buffer; \
|
||||
HANDLE read_raw_wait; \
|
||||
DWORD original_console_mode; \
|
||||
/* Fields used for translating win */ \
|
||||
/* keystrokes into vt100 characters */ \
|
||||
char last_key[8]; \
|
||||
unsigned char last_key_offset; \
|
||||
unsigned char last_key_len; \
|
||||
INPUT_RECORD last_input_record; \
|
||||
WCHAR last_utf16_high_surrogate; \
|
||||
/* utf8-to-utf16 conversion state */ \
|
||||
unsigned char utf8_bytes_left; \
|
||||
unsigned int utf8_codepoint; \
|
||||
/* eol conversion state */ \
|
||||
unsigned char previous_eol; \
|
||||
/* ansi parser state */ \
|
||||
unsigned char ansi_parser_state; \
|
||||
unsigned char ansi_csi_argc; \
|
||||
unsigned short ansi_csi_argv[4]; \
|
||||
COORD saved_position; \
|
||||
WORD saved_attributes;
|
||||
union { \
|
||||
struct { \
|
||||
/* Used for readable TTY handles */ \
|
||||
HANDLE read_line_handle; \
|
||||
uv_buf_t read_line_buffer; \
|
||||
HANDLE read_raw_wait; \
|
||||
DWORD original_console_mode; \
|
||||
/* Fields used for translating win keystrokes into vt100 characters */ \
|
||||
char last_key[8]; \
|
||||
unsigned char last_key_offset; \
|
||||
unsigned char last_key_len; \
|
||||
WCHAR last_utf16_high_surrogate; \
|
||||
INPUT_RECORD last_input_record; \
|
||||
}; \
|
||||
struct { \
|
||||
/* Used for writable TTY handles */ \
|
||||
/* utf8-to-utf16 conversion state */ \
|
||||
unsigned int utf8_codepoint; \
|
||||
unsigned char utf8_bytes_left; \
|
||||
/* eol conversion state */ \
|
||||
unsigned char previous_eol; \
|
||||
/* ansi parser state */ \
|
||||
unsigned char ansi_parser_state; \
|
||||
unsigned char ansi_csi_argc; \
|
||||
unsigned short ansi_csi_argv[4]; \
|
||||
COORD saved_position; \
|
||||
WORD saved_attributes; \
|
||||
}; \
|
||||
};
|
||||
|
||||
#define UV_POLL_PRIVATE_FIELDS \
|
||||
SOCKET socket; \
|
||||
|
||||
@ -74,9 +74,10 @@
|
||||
#define UV_HANDLE_PIPESERVER 0x02000000
|
||||
|
||||
/* Only used by uv_tty_t handles. */
|
||||
#define UV_HANDLE_TTY_RAW 0x01000000
|
||||
#define UV_HANDLE_TTY_SAVED_POSITION 0x02000000
|
||||
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x04000000
|
||||
#define UV_HANDLE_TTY_READABLE 0x01000000
|
||||
#define UV_HANDLE_TTY_RAW 0x02000000
|
||||
#define UV_HANDLE_TTY_SAVED_POSITION 0x04000000
|
||||
#define UV_HANDLE_TTY_SAVED_ATTRIBUTES 0x08000000
|
||||
|
||||
/* Only used by uv_poll_t handles. */
|
||||
#define UV_HANDLE_POLL_SLOW 0x02000000
|
||||
|
||||
116
src/win/tty.c
116
src/win/tty.c
@ -89,52 +89,70 @@ void uv_console_init() {
|
||||
|
||||
|
||||
int uv_tty_init(uv_loop_t* loop, uv_tty_t* tty, uv_file fd, int readable) {
|
||||
HANDLE win_handle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
HANDLE handle = INVALID_HANDLE_VALUE;
|
||||
DWORD original_console_mode = 0;
|
||||
CONSOLE_SCREEN_BUFFER_INFO screen_buffer_info;
|
||||
|
||||
win_handle = (HANDLE) _get_osfhandle(fd);
|
||||
if (win_handle == INVALID_HANDLE_VALUE) {
|
||||
uv__set_sys_error(loop, ERROR_INVALID_HANDLE);
|
||||
handle = (HANDLE) _get_osfhandle(fd);
|
||||
if (handle == INVALID_HANDLE_VALUE) {
|
||||
uv__set_artificial_error(loop, UV_EBADF);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!GetConsoleMode(win_handle, &tty->original_console_mode)) {
|
||||
uv__set_sys_error(loop, GetLastError());
|
||||
return -1;
|
||||
}
|
||||
if (readable) {
|
||||
/* Try to obtain the original console mode fromt he input handle. */
|
||||
if (!GetConsoleMode(handle, &original_console_mode)) {
|
||||
uv__set_sys_error(loop, GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Initialize virtual window size; if it fails, assume that this is stdin. */
|
||||
if (GetConsoleScreenBufferInfo(win_handle, &info)) {
|
||||
} else {
|
||||
/* Obtain the screen buffer info with the output handle. */
|
||||
if (!GetConsoleScreenBufferInfo(handle, &screen_buffer_info)) {
|
||||
uv__set_sys_error(loop, GetLastError());
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Update the virtual window. We must hold the tty_output_lock because the */
|
||||
/* virtual window state is shared between all uv_tty handles. */
|
||||
EnterCriticalSection(&uv_tty_output_lock);
|
||||
uv_tty_update_virtual_window(&info);
|
||||
uv_tty_update_virtual_window(&screen_buffer_info);
|
||||
LeaveCriticalSection(&uv_tty_output_lock);
|
||||
}
|
||||
|
||||
|
||||
uv_stream_init(loop, (uv_stream_t*) tty, UV_TTY);
|
||||
uv_connection_init((uv_stream_t*) tty);
|
||||
|
||||
tty->handle = win_handle;
|
||||
tty->read_line_handle = NULL;
|
||||
tty->read_line_buffer = uv_null_buf_;
|
||||
tty->read_raw_wait = NULL;
|
||||
tty->handle = handle;
|
||||
tty->reqs_pending = 0;
|
||||
tty->flags |= UV_HANDLE_BOUND;
|
||||
|
||||
/* Init keycode-to-vt100 mapper state. */
|
||||
tty->last_key_len = 0;
|
||||
tty->last_key_offset = 0;
|
||||
tty->last_utf16_high_surrogate = 0;
|
||||
memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
|
||||
if (readable) {
|
||||
/* Initialize TTY input specific fields. */
|
||||
tty->original_console_mode = original_console_mode;
|
||||
tty->flags |= UV_HANDLE_TTY_READABLE;
|
||||
tty->read_line_handle = NULL;
|
||||
tty->read_line_buffer = uv_null_buf_;
|
||||
tty->read_raw_wait = NULL;
|
||||
|
||||
/* Init utf8-to-utf16 conversion state. */
|
||||
tty->utf8_bytes_left = 0;
|
||||
tty->utf8_codepoint = 0;
|
||||
/* Init keycode-to-vt100 mapper state. */
|
||||
tty->last_key_len = 0;
|
||||
tty->last_key_offset = 0;
|
||||
tty->last_utf16_high_surrogate = 0;
|
||||
memset(&tty->last_input_record, 0, sizeof tty->last_input_record);
|
||||
} else {
|
||||
/* TTY output specific fields. */
|
||||
/* Init utf8-to-utf16 conversion state. */
|
||||
tty->utf8_bytes_left = 0;
|
||||
tty->utf8_codepoint = 0;
|
||||
|
||||
/* Initialize eol conversion state */
|
||||
tty->previous_eol = 0;
|
||||
/* Initialize eol conversion state */
|
||||
tty->previous_eol = 0;
|
||||
|
||||
/* Init ANSI parser state. */
|
||||
tty->ansi_parser_state = ANSI_NORMAL;
|
||||
/* Init ANSI parser state. */
|
||||
tty->ansi_parser_state = ANSI_NORMAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -146,6 +164,11 @@ int uv_tty_set_mode(uv_tty_t* tty, int mode) {
|
||||
uv_alloc_cb alloc_cb;
|
||||
uv_read_cb read_cb;
|
||||
|
||||
if (!(tty->flags & UV_HANDLE_TTY_READABLE)) {
|
||||
uv__set_artificial_error(tty->loop, UV_EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!!mode == !!(tty->flags & UV_HANDLE_TTY_RAW)) {
|
||||
return 0;
|
||||
}
|
||||
@ -442,6 +465,7 @@ void uv_process_tty_read_raw_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
off_t buf_used;
|
||||
|
||||
assert(handle->type == UV_TTY);
|
||||
assert(handle->flags & UV_HANDLE_TTY_READABLE);
|
||||
handle->flags &= ~UV_HANDLE_READ_PENDING;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_READING) ||
|
||||
@ -681,6 +705,7 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
uv_buf_t buf;
|
||||
|
||||
assert(handle->type == UV_TTY);
|
||||
assert(handle->flags & UV_HANDLE_TTY_READABLE);
|
||||
|
||||
buf = handle->read_line_buffer;
|
||||
|
||||
@ -724,6 +749,8 @@ void uv_process_tty_read_line_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
|
||||
void uv_process_tty_read_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
uv_req_t* req) {
|
||||
assert(handle->type == UV_TTY);
|
||||
assert(handle->flags & UV_HANDLE_TTY_READABLE);
|
||||
|
||||
/* If the read_line_buffer member is zero, it must have been an raw read. */
|
||||
/* Otherwise it was a line-buffered read. */
|
||||
@ -740,6 +767,11 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
|
||||
uv_read_cb read_cb) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
|
||||
if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
|
||||
uv__set_artificial_error(handle->loop, UV_EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
handle->flags |= UV_HANDLE_READING;
|
||||
INCREASE_ACTIVE_COUNT(loop, handle);
|
||||
handle->read_cb = read_cb;
|
||||
@ -767,6 +799,10 @@ int uv_tty_read_start(uv_tty_t* handle, uv_alloc_cb alloc_cb,
|
||||
|
||||
int uv_tty_read_stop(uv_tty_t* handle) {
|
||||
uv_loop_t* loop = handle->loop;
|
||||
if (!(handle->flags & UV_HANDLE_TTY_READABLE)) {
|
||||
uv__set_artificial_error(handle->loop, UV_EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (handle->flags & UV_HANDLE_READING) {
|
||||
handle->flags &= ~UV_HANDLE_READING;
|
||||
@ -1676,6 +1712,11 @@ int uv_tty_write(uv_loop_t* loop, uv_write_t* req, uv_tty_t* handle,
|
||||
uv_buf_t bufs[], int bufcnt, uv_write_cb cb) {
|
||||
DWORD error;
|
||||
|
||||
if (handle->flags & UV_HANDLE_TTY_READABLE) {
|
||||
uv__set_artificial_error(handle->loop, UV_EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((handle->flags & UV_HANDLE_SHUTTING) ||
|
||||
(handle->flags & UV_HANDLE_CLOSING)) {
|
||||
uv__set_sys_error(loop, WSAESHUTDOWN);
|
||||
@ -1727,11 +1768,16 @@ void uv_process_tty_write_req(uv_loop_t* loop, uv_tty_t* handle,
|
||||
|
||||
|
||||
void uv_tty_close(uv_tty_t* handle) {
|
||||
handle->flags |= UV_HANDLE_SHUTTING;
|
||||
|
||||
uv_tty_read_stop(handle);
|
||||
CloseHandle(handle->handle);
|
||||
|
||||
if (handle->flags & UV_HANDLE_TTY_READABLE) {
|
||||
/* Readable TTY handle */
|
||||
uv_tty_read_stop(handle);
|
||||
} else {
|
||||
/* Writable TTY handle */
|
||||
handle->flags |= UV_HANDLE_SHUTTING;
|
||||
}
|
||||
|
||||
uv__handle_start(handle);
|
||||
|
||||
if (handle->reqs_pending == 0) {
|
||||
@ -1741,7 +1787,7 @@ void uv_tty_close(uv_tty_t* handle) {
|
||||
|
||||
|
||||
void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
if ((handle->flags && UV_HANDLE_CONNECTION) &&
|
||||
if (!(handle->flags && UV_HANDLE_TTY_READABLE) &&
|
||||
handle->shutdown_req != NULL &&
|
||||
handle->write_reqs_pending == 0) {
|
||||
UNREGISTER_HANDLE_REQ(loop, handle, handle->shutdown_req);
|
||||
@ -1766,11 +1812,13 @@ void uv_tty_endgame(uv_loop_t* loop, uv_tty_t* handle) {
|
||||
handle->reqs_pending == 0) {
|
||||
/* The console handle duplicate used for line reading should be destroyed */
|
||||
/* by uv_tty_read_stop. */
|
||||
assert(handle->read_line_handle == NULL);
|
||||
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
|
||||
handle->read_line_handle == NULL);
|
||||
|
||||
/* The wait handle used for raw reading should be unregistered when the */
|
||||
/* wait callback runs. */
|
||||
assert(handle->read_raw_wait == NULL);
|
||||
assert(!(handle->flags & UV_HANDLE_TTY_READABLE) ||
|
||||
handle->read_raw_wait == NULL);
|
||||
|
||||
assert(!(handle->flags & UV_HANDLE_CLOSED));
|
||||
uv__handle_stop(handle);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user