From: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> To: dev@dpdk.org Cc: Dmitry Malloy <dmitrym@microsoft.com>, Narcisa Ana Maria Vasile <Narcisa.Vasile@microsoft.com>, Fady Bader <fady@mellanox.com>, Tal Shnaiderman <talshn@mellanox.com>, "Kadam, Pallavi" <pallavi.kadam@intel.com>, Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>, Thomas Monjalon <thomas@monjalon.net>, Olivier Matz <olivier.matz@6wind.com> Subject: [dpdk-dev] [PATCH v2 6/7] cmdline: support Windows Date: Fri, 31 Jul 2020 00:06:50 +0300 Message-ID: <20200730210652.14568-7-dmitry.kozliuk@gmail.com> (raw) In-Reply-To: <20200730210652.14568-1-dmitry.kozliuk@gmail.com> Implement terminal handling, input polling, and vdprintf() for Windows. Because Windows I/O model differs fundamentally from Unix and there is no concept of character device, polling is simulated depending on the underlying inpue device. Supporting non-terminal input is useful for automated testing. Windows emulation of VT100 uses "ESC [ E" for newline instead of standard "ESC E", so a workaround is added. Signed-off-by: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com> --- config/meson.build | 2 + lib/librte_cmdline/cmdline.c | 5 + lib/librte_cmdline/cmdline_os_windows.c | 207 ++++++++++++++++++++++++ lib/librte_cmdline/cmdline_private.h | 15 ++ lib/librte_cmdline/cmdline_socket.c | 4 + lib/librte_cmdline/cmdline_vt100.h | 4 + lib/librte_cmdline/meson.build | 4 +- lib/meson.build | 1 + 8 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 lib/librte_cmdline/cmdline_os_windows.c diff --git a/config/meson.build b/config/meson.build index cff8b33dd..2d1b6fab2 100644 --- a/config/meson.build +++ b/config/meson.build @@ -270,6 +270,8 @@ if is_windows add_project_arguments('-D__USE_MINGW_ANSI_STDIO', language: 'c') endif + add_project_link_arguments('-lws2_32', language: 'c') + # Contrary to docs, VirtualAlloc2() is exported by mincore.lib # in Windows SDK, while MinGW exports it by advapi32.a. if is_ms_linker diff --git a/lib/librte_cmdline/cmdline.c b/lib/librte_cmdline/cmdline.c index 00b9e6b2e..c0ddb5f23 100644 --- a/lib/librte_cmdline/cmdline.c +++ b/lib/librte_cmdline/cmdline.c @@ -13,9 +13,14 @@ #include <fcntl.h> #include <errno.h> #include <netinet/in.h> +#include <unistd.h> #include <rte_string_fns.h> +#ifdef RTE_EXEC_ENV_WINDOWS +#define write _write +#endif + #include "cmdline.h" #include "cmdline_private.h" diff --git a/lib/librte_cmdline/cmdline_os_windows.c b/lib/librte_cmdline/cmdline_os_windows.c new file mode 100644 index 000000000..9736f6531 --- /dev/null +++ b/lib/librte_cmdline/cmdline_os_windows.c @@ -0,0 +1,207 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2020 Dmitry Kozlyuk + */ + +#include <io.h> + +#include <rte_os.h> + +#include "cmdline_private.h" + +/* Missing from some MinGW-w64 distributions. */ +#ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING +#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 +#endif + +#ifndef ENABLE_VIRTUAL_TERMINAL_INPUT +#define ENABLE_VIRTUAL_TERMINAL_INPUT 0x0200 +#endif + +void +terminal_adjust(struct terminal *oldterm) +{ + HANDLE handle; + DWORD mode; + + ZeroMemory(oldterm, sizeof(*oldterm)); + + /* Detect console input, set it up and make it emulate VT100. */ + handle = GetStdHandle(STD_INPUT_HANDLE); + if (GetConsoleMode(handle, &mode)) { + oldterm->is_console_input = 1; + oldterm->input_mode = mode; + + mode &= ~( + ENABLE_LINE_INPUT | /* no line buffering */ + ENABLE_ECHO_INPUT | /* no echo */ + ENABLE_PROCESSED_INPUT | /* pass Ctrl+C to program */ + ENABLE_MOUSE_INPUT | /* no mouse events */ + ENABLE_WINDOW_INPUT); /* no window resize events */ + mode |= ENABLE_VIRTUAL_TERMINAL_INPUT; + SetConsoleMode(handle, mode); + } + + /* Detect console output and make it emulate VT100. */ + handle = GetStdHandle(STD_OUTPUT_HANDLE); + if (GetConsoleMode(handle, &mode)) { + oldterm->is_console_output = 1; + oldterm->output_mode = mode; + + mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT; + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(handle, mode); + } +} + +void +terminal_restore(const struct terminal *oldterm) +{ + if (oldterm->is_console_input) { + HANDLE handle = GetStdHandle(STD_INPUT_HANDLE); + SetConsoleMode(handle, oldterm->input_mode); + } + + if (oldterm->is_console_output) { + HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); + SetConsoleMode(handle, oldterm->output_mode); + } +} + +static int +cmdline_is_key_down(const INPUT_RECORD *record) +{ + return (record->EventType == KEY_EVENT) && + record->Event.KeyEvent.bKeyDown; +} + +static int +cmdline_poll_char_console(HANDLE handle) +{ + INPUT_RECORD record; + DWORD events; + + if (!PeekConsoleInput(handle, &record, 1, &events)) { + /* Simulate poll(3) behavior on EOF. */ + return (GetLastError() == ERROR_HANDLE_EOF) ? 1 : -1; + } + + if ((events == 0) || !cmdline_is_key_down(&record)) + return 0; + + return 1; +} + +static int +cmdline_poll_char_file(struct cmdline *cl, HANDLE handle) +{ + DWORD type = GetFileType(handle); + + /* Since console is handled by cmdline_poll_char_console(), + * this is either a serial port or input handle had been replaced. + */ + if (type == FILE_TYPE_CHAR) + return cmdline_poll_char_console(handle); + + /* PeekNamedPipe() can handle all pipes and also sockets. */ + if (type == FILE_TYPE_PIPE) { + DWORD bytes_avail; + if (!PeekNamedPipe(handle, NULL, 0, NULL, &bytes_avail, NULL)) + return (GetLastError() == ERROR_BROKEN_PIPE) ? 1 : -1; + return bytes_avail ? 1 : 0; + } + + /* There is no straightforward way to peek a file in Windows + * I/O model. Read the byte, if it is not the end of file, + * buffer it for subsequent read. This will not work with + * a file being appended and probably some other edge cases. + */ + if (type == FILE_TYPE_DISK) { + char c; + int ret; + + ret = _read(cl->s_in, &c, sizeof(c)); + if (ret == 1) { + cl->repeat_count = 1; + cl->repeated_char = c; + } + return ret; + } + + /* GetFileType() failed or file of unknown type, + * which we do not know how to peek anyway. + */ + return -1; +} + +int +cmdline_poll_char(struct cmdline *cl) +{ + HANDLE handle = (HANDLE)_get_osfhandle(cl->s_in); + return cl->oldterm.is_console_input ? + cmdline_poll_char_console(handle) : + cmdline_poll_char_file(cl, handle); +} + +ssize_t +cmdline_read_char(struct cmdline *cl, char *c) +{ + HANDLE handle; + INPUT_RECORD record; + KEY_EVENT_RECORD *key; + DWORD events; + + if (!cl->oldterm.is_console_input) + return _read(cl->s_in, c, 1); + + /* Return repeated strokes from previous event. */ + if (cl->repeat_count > 0) { + *c = cl->repeated_char; + cl->repeat_count--; + return 1; + } + + handle = (HANDLE)_get_osfhandle(cl->s_in); + key = &record.Event.KeyEvent; + do { + if (!ReadConsoleInput(handle, &record, 1, &events)) { + if (GetLastError() == ERROR_HANDLE_EOF) { + *c = EOF; + return 0; + } + return -1; + } + } while (!cmdline_is_key_down(&record)); + + *c = key->uChar.AsciiChar; + + /* Save repeated strokes from a single event. */ + if (key->wRepeatCount > 1) { + cl->repeated_char = *c; + cl->repeat_count = key->wRepeatCount - 1; + } + + return 1; +} + +int +cmdline_vdprintf(int fd, const char *format, va_list op) +{ + int copy, ret; + FILE *file; + + copy = _dup(fd); + if (copy < 0) + return -1; + + file = _fdopen(copy, "a"); + if (file == NULL) { + _close(copy); + return -1; + } + + ret = vfprintf(file, format, op); + + fclose(file); /* also closes copy */ + + return ret; +} diff --git a/lib/librte_cmdline/cmdline_private.h b/lib/librte_cmdline/cmdline_private.h index 338d3d55c..1e05ec376 100644 --- a/lib/librte_cmdline/cmdline_private.h +++ b/lib/librte_cmdline/cmdline_private.h @@ -5,7 +5,11 @@ #ifndef _CMDLINE_PRIVATE_H_ #define _CMDLINE_PRIVATE_H_ +#ifdef RTE_EXEC_ENV_WINDOWS +#include <rte_windows.h> +#else #include <termios.h> +#endif #include <stdarg.h> @@ -15,7 +19,14 @@ #include <cmdline_parse.h> struct terminal { +#ifndef RTE_EXEC_ENV_WINDOWS struct termios termios; +#else + DWORD input_mode; + DWORD output_mode; + int is_console_input; + int is_console_output; +#endif }; /* Disable buffering and echoing, save previous settings to oldterm. */ @@ -31,6 +42,10 @@ struct cmdline { struct rdline rdl; char prompt[RDLINE_PROMPT_SIZE]; struct terminal oldterm; +#ifdef RTE_EXEC_ENV_WINDOWS + char repeated_char; + WORD repeat_count; +#endif }; /* Check if a single character can be read from input. */ diff --git a/lib/librte_cmdline/cmdline_socket.c b/lib/librte_cmdline/cmdline_socket.c index e73666f15..c5f483413 100644 --- a/lib/librte_cmdline/cmdline_socket.c +++ b/lib/librte_cmdline/cmdline_socket.c @@ -16,6 +16,10 @@ #include "cmdline_private.h" #include "cmdline_socket.h" +#ifdef RTE_EXEC_ENV_WINDOWS +#define open _open +#endif + struct cmdline * cmdline_file_new(cmdline_parse_ctx_t *ctx, const char *prompt, const char *path) { diff --git a/lib/librte_cmdline/cmdline_vt100.h b/lib/librte_cmdline/cmdline_vt100.h index e33e67ed8..be9ae8e1c 100644 --- a/lib/librte_cmdline/cmdline_vt100.h +++ b/lib/librte_cmdline/cmdline_vt100.h @@ -31,7 +31,11 @@ extern "C" { #define vt100_multi_right "\033\133%uC" #define vt100_multi_left "\033\133%uD" #define vt100_suppr "\033\133\063\176" +#ifndef RTE_EXEC_ENV_WINDOWS #define vt100_home "\033M\033E" +#else +#define vt100_home "\033M\033[E" +#endif #define vt100_word_left "\033\142" #define vt100_word_right "\033\146" diff --git a/lib/librte_cmdline/meson.build b/lib/librte_cmdline/meson.build index 5c9e8886d..5009b3354 100644 --- a/lib/librte_cmdline/meson.build +++ b/lib/librte_cmdline/meson.build @@ -25,7 +25,9 @@ headers = files('cmdline.h', 'cmdline_cirbuf.h', 'cmdline_parse_portlist.h') -if not is_windows +if is_windows + sources += files('cmdline_os_windows.c') +else sources += files('cmdline_os_unix.c') endif diff --git a/lib/meson.build b/lib/meson.build index 6bbaf242a..8430057c6 100644 --- a/lib/meson.build +++ b/lib/meson.build @@ -41,6 +41,7 @@ if is_windows 'eal', 'ring', 'mempool', 'mbuf', 'pci', 'net', + 'cmdline', ] # only supported libraries for windows endif -- 2.25.4
next prev parent reply other threads:[~2020-07-30 21:08 UTC|newest] Thread overview: 50+ messages / expand[flat|nested] mbox.gz Atom feed top 2020-06-20 21:05 [dpdk-dev] [PATCH 0/7] " Dmitry Kozlyuk 2020-06-20 21:05 ` [dpdk-dev] [PATCH 1/7] cmdline: make implementation opaque Dmitry Kozlyuk 2020-06-20 21:05 ` [dpdk-dev] [PATCH 2/7] cmdline: add internal wrappers for terminal handling Dmitry Kozlyuk 2020-06-20 21:05 ` [dpdk-dev] [PATCH 3/7] cmdline: add internal wrappers for character input Dmitry Kozlyuk 2020-06-20 21:05 ` [dpdk-dev] [PATCH 4/7] cmdline: add internal wrapper for vdprintf Dmitry Kozlyuk 2020-06-20 21:05 ` [dpdk-dev] [PATCH 5/7] eal/windows: improve compatibility networking headers Dmitry Kozlyuk 2020-06-20 21:05 ` [dpdk-dev] [PATCH 6/7] cmdline: support Windows Dmitry Kozlyuk 2020-06-28 14:20 ` Fady Bader 2020-06-29 6:23 ` Ranjit Menon 2020-06-29 7:42 ` Dmitry Kozlyuk 2020-06-29 8:12 ` Tal Shnaiderman 2020-06-29 23:56 ` Dmitry Kozlyuk 2020-07-08 1:09 ` Dmitry Kozlyuk 2020-06-20 21:05 ` [dpdk-dev] [PATCH 7/7] examples/cmdline: build on Windows Dmitry Kozlyuk 2020-07-17 22:16 ` [dpdk-dev] [PATCH 0/7] cmdline: support Windows Narcisa Ana Maria Vasile 2020-07-30 18:08 ` Kadam, Pallavi 2020-07-30 21:06 ` [dpdk-dev] [PATCH v2 " Dmitry Kozlyuk 2020-07-30 21:06 ` [dpdk-dev] [PATCH v2 1/7] cmdline: make implementation opaque Dmitry Kozlyuk 2020-08-05 9:31 ` Kinsella, Ray 2020-08-05 11:17 ` Dmitry Kozlyuk 2020-09-30 8:11 ` Kinsella, Ray 2020-09-30 15:26 ` Dmitry Kozlyuk 2020-09-17 13:34 ` Olivier Matz 2020-09-17 17:05 ` Stephen Hemminger 2020-09-18 8:33 ` Bruce Richardson 2020-09-18 12:13 ` Ferruh Yigit 2020-09-18 13:23 ` Kinsella, Ray 2020-09-17 23:13 ` Dmitry Kozlyuk 2020-09-18 13:31 ` Kinsella, Ray 2020-07-30 21:06 ` [dpdk-dev] [PATCH v2 2/7] cmdline: add internal wrappers for terminal handling Dmitry Kozlyuk 2020-07-30 21:06 ` [dpdk-dev] [PATCH v2 3/7] cmdline: add internal wrappers for character input Dmitry Kozlyuk 2020-07-30 21:06 ` [dpdk-dev] [PATCH v2 4/7] cmdline: add internal wrapper for vdprintf Dmitry Kozlyuk 2020-07-30 21:06 ` [dpdk-dev] [PATCH v2 5/7] eal/windows: improve compatibility networking headers Dmitry Kozlyuk 2020-07-30 21:06 ` Dmitry Kozlyuk [this message] 2020-07-30 21:06 ` [dpdk-dev] [PATCH v2 7/7] examples/cmdline: build on Windows Dmitry Kozlyuk 2020-09-26 1:33 ` [dpdk-dev] [EXTERNAL] " Narcisa Ana Maria Vasile 2020-09-26 6:03 ` Khoa To 2020-09-28 21:50 ` [dpdk-dev] [PATCH v3 0/7] cmdline: support Windows Dmitry Kozlyuk 2020-09-28 21:50 ` [dpdk-dev] [PATCH v3 1/7] cmdline: make implementation logically opaque Dmitry Kozlyuk 2020-09-30 8:12 ` Kinsella, Ray 2020-09-28 21:50 ` [dpdk-dev] [PATCH v3 2/7] cmdline: add internal wrappers for terminal handling Dmitry Kozlyuk 2020-09-28 21:50 ` [dpdk-dev] [PATCH v3 3/7] cmdline: add internal wrappers for character input Dmitry Kozlyuk 2020-09-28 21:50 ` [dpdk-dev] [PATCH v3 4/7] cmdline: add internal wrapper for vdprintf Dmitry Kozlyuk 2020-09-28 21:50 ` [dpdk-dev] [PATCH v3 5/7] eal/windows: improve compatibility networking headers Dmitry Kozlyuk 2020-09-28 21:50 ` [dpdk-dev] [PATCH v3 6/7] cmdline: support Windows Dmitry Kozlyuk 2020-10-14 22:31 ` Thomas Monjalon 2020-09-28 21:50 ` [dpdk-dev] [PATCH v3 7/7] examples/cmdline: build on Windows Dmitry Kozlyuk 2020-10-14 22:33 ` Thomas Monjalon 2020-10-05 15:33 ` [dpdk-dev] [PATCH v3 0/7] cmdline: support Windows Olivier Matz 2020-10-14 22:41 ` Thomas Monjalon
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=20200730210652.14568-7-dmitry.kozliuk@gmail.com \ --to=dmitry.kozliuk@gmail.com \ --cc=Narcisa.Vasile@microsoft.com \ --cc=dev@dpdk.org \ --cc=dmitrym@microsoft.com \ --cc=fady@mellanox.com \ --cc=olivier.matz@6wind.com \ --cc=pallavi.kadam@intel.com \ --cc=talshn@mellanox.com \ --cc=thomas@monjalon.net \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: link
DPDK patches and discussions This inbox may be cloned and mirrored by anyone: git clone --mirror http://inbox.dpdk.org/dev/0 dev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 dev dev/ http://inbox.dpdk.org/dev \ dev@dpdk.org public-inbox-index dev Example config snippet for mirrors. Newsgroup available over NNTP: nntp://inbox.dpdk.org/inbox.dpdk.dev AGPL code for this site: git clone https://public-inbox.org/public-inbox.git