windows: separate uv_tty_t read state from write state

This commit is contained in:
Bert Belder 2012-08-16 23:05:59 +02:00
parent 7cf1b67594
commit 88634c1405
3 changed files with 115 additions and 59 deletions

View File

@ -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; \

View File

@ -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

View File

@ -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);